/*
AVR Application program for ATmega8515 to implement a Christmas Tree project.
RAW 2/4/11
*/
// Pattern execution modes
// default is to execute 8 differnt patterns in sequence
#define ALLSEQ 0   // all sequences in rotation
#define PRBSR 1    // prbs red (random)prbs 15 bits
#define PRBSG 2    // prbs green (random)prbs 15 bits
#define MARCHR 3   // march single walking red
#define MARCHG 4   // march single walking green
#define WALKR 5    // walk red through green to yellow top and return
#define WALKG 6    // walk green through red to yello top and return
#define FLASH 7    // Alternate red and green
#define RUNR 8     // Run a Red follwed by Green.
#define RUNG 9     // Run a Green followed by Red
#define JOGR 10    // 
#define JOGG 11    //
#define FADE 12    // Fade in green, turn on red (i.e. yellow), fade out to red. 
#define seqSize 13 // Number of sequences

//#define TOTLEDS 30

#define PRBSLEN 32768 // 2^15 = 32768
#define CLEAR 0
#define SET 1
#define ON 0x0
#define OFF 0x1

// Execution Rate i.e. millisecond delay (CPU Freq. = 1MHz)
#define FAST 48 // 5
#define MEDIUM 160 // 20
#define SLOW 640  // 80

// colors
#define RED 1
#define GREEN 2

// io assignments ( See IO Mapping Below )
// PortA[7:0], PortB[7:0], PortC[7:0], PortD[7:0] = 30 LED outputs
// PortD[3] = Interrupt INT1 rate slection input
// PortD[2] = Interrupt INT0, sequence selection input
#define PD(a, b, c, d, e, f) PORTD = ((a)<<7) + ((b)<<6) + ((c)<<5) + ((d)<<4) + ((e)<<1) + (f)
#define PB(a, b, c, d, e, f, g, h) PORTB = ((a)<<7) + ((b)<<6) + ((c)<<5) + ((d)<<4) + ((e)<<3) + ((f)<<2) + ((g)<<1) + (h)
#define PA(a, b, c, d, e, f, g, h) PORTA = (a) + ((b)<<1) + ((c)<<2) + ((d)<<3) + ((e)<<4) + ((f)<<5) + ((g)<<6) + ((h)<<7)
#define PC(a, b, c, d, e, f, g, h) PORTC = ((a)<<7) + ((b)<<6) + ((c)<<5) + ((d)<<4) + ((e)<<3) + ((f)<<2) + ((g)<<1) + (h)
#define dly _delay_ms(rate)
#define dataSize 64

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
#include <util/delay.h>

//                                     1>   7>   22<  23>  1>   7>   22<  23>  1>   7>   22<  23> 1>    7>   22<  23>  
// See io mapping below                d    b    a    c    d    b    a    c    d    b    a    c    d    b    a    c   
//eeprom data                          ------------------- ------------------- ------------------- -------------------
uint8_t EEMEM eepromMarchG[dataSize]= {0xf3,0xff,0xff,0xfd,0xf3,0xff,0xff,0xf7,0xf3,0xff,0xff,0xdf,0xf3,0xff,0xff,0x7f,
                                       0xf3,0xff,0xbf,0xff,0xf3,0xff,0xef,0xff,0xf3,0xff,0xfb,0xff,0xf3,0xff,0xfe,0xff,
				                       0xf3,0xfd,0xff,0xff,0xf3,0xf7,0xff,0xff,0xf3,0xdf,0xff,0xff,0xf3,0x7f,0xff,0xff,
						               0xf1,0xff,0xff,0xff,0xd3,0xff,0xff,0xff,0x73,0xff,0xff,0xff,0xf3,0xff,0xff,0xff};
uint8_t EEMEM eepromMarchR[dataSize]= {0xf3,0xff,0xff,0xfe,0xf3,0xff,0xff,0xfb,0xf3,0xff,0xff,0xef,0xf3,0xff,0xff,0xbf,
                                       0xf3,0xff,0x7f,0xff,0xf3,0xff,0xdf,0xff,0xf3,0xff,0x7f,0xff,0xf3,0xff,0xfd,0xff,
				                       0xf3,0xfe,0xff,0xff,0xf3,0xfb,0xff,0xff,0xf3,0xef,0xff,0xff,0xf3,0xbf,0xff,0xff,
						               0xf1,0xff,0xff,0xff,0xd3,0xff,0xff,0xff,0x73,0xff,0xff,0xff,0xf3,0xff,0xff,0xff};
uint8_t EEMEM eepromWalkR[dataSize] = {0x62,0xaa,0x55,0xa9,0x92,0xaa,0x55,0xa6,0xa1,0xaa,0x55,0x9a,0x62,0x6a,0x55,0x6a,
                                       0xa2,0x9a,0x95,0xaa,0xa2,0xa6,0x55,0xaa,0xa2,0xa9,0x55,0xaa,0x62,0xaa,0x54,0xaa,
                                       0xa2,0xa9,0x59,0xaa,0xa2,0xa6,0x65,0xaa,0xa2,0x9a,0x95,0xaa,0xa8,0x9a,0x55,0x6a,
                                       0xa2,0xa1,0xaa,0x9a,0xa2,0xaa,0x55,0xa6,0xa2,0xaa,0x55,0xa9,0xf3,0xff,0xff,0xff};
uint8_t EEMEM eepromWalkG[dataSize] = {0x91,0x55,0xaa,0x56,0x61,0x55,0xaa,0x59,0x52,0x55,0xaa,0x65,0x51,0x95,0xaa,0x95,
                                       0x51,0x65,0xa8,0x55,0x51,0x59,0x9a,0x55,0x51,0x56,0xa6,0x55,0x51,0x55,0xa8,0x55,
                                       0x51,0x56,0xa6,0x55,0x51,0x59,0x9a,0x55,0x51,0x65,0x6a,0x55,0x51,0x95,0xaa,0x95,
                                       0x52,0x55,0xaa,0x65,0x61,0x55,0xaa,0x59,0x91,0x55,0xaa,0x56,0xf3,0xff,0xff,0xff};
uint8_t EEMEM eepromRunG[dataSize]  = {0xf3,0xff,0xff,0xfe,0xf3,0xff,0xff,0xf9,0xf3,0xff,0xff,0xe5,0xf3,0xff,0xff,0xe9,
                                       0xf3,0xff,0x7f,0x55,0xf3,0xff,0x9f,0x55,0xf3,0xff,0xa7,0x55,0xf3,0xff,0xa9,0x55,
				                       0xf3,0xfe,0xaa,0x55,0xf3,0xf9,0xaa,0x55,0xf3,0xf5,0xaa,0x55,0xf3,0x95,0xaa,0x55,
						               0xf2,0x55,0xaa,0x55,0xe1,0x55,0xaa,0x55,0xe1,0x55,0xaa,0x55,0xf3,0xff,0xff,0xff};
uint8_t EEMEM eepromRunR[dataSize]  = {0x83,0xff,0xff,0xff,0x93,0xff,0xff,0xff,0xa1,0xff,0xff,0xff,0xa2,0x7f,0xff,0xff,
                                       0xa2,0x9f,0xff,0xff,0xa2,0xa7,0xff,0xff,0xa2,0xa9,0xff,0xff,0xa2,0xaa,0xfe,0xff,
				                       0xa2,0xaa,0xf9,0xff,0xa2,0xaa,0xe5,0xff,0xa2,0xaa,0x95,0xff,0xa2,0xaa,0x55,0x7f,
						               0xa2,0xaa,0x55,0x9f,0xa2,0xff,0x55,0xaf,0xa2,0xff,0x55,0xa9,0xf3,0xff,0xff,0xff};

uint8_t EEMEM eepromJogR[dataSize]  = {0xf3,0xaa,0x55,0xa9,0x92,0xaa,0x55,0xa6,0xa1,0xaa,0x55,0x9a,0x62,0x6a,0x55,0x6a,
                                       0xa2,0x9a,0x95,0xaa,0xa2,0xa6,0x55,0xaa,0xa2,0xa9,0x55,0xa2,0x62,0xaa,0x54,0xaa,
                                       0xa2,0xa9,0x59,0xaa,0xa2,0xa6,0x65,0xaa,0xa2,0x9a,0x95,0xa2,0xa8,0x9a,0x55,0x6a,
                                       0xa2,0xa1,0xaa,0x9a,0xa2,0xaa,0x55,0xa6,0xa2,0xaa,0x55,0xa9,0xf3,0xff,0xff,0xff};

uint8_t EEMEM eepromJogG[dataSize]  = {0x91,0x55,0xaa,0x56,0x61,0x55,0xaa,0x59,0x52,0x55,0xaa,0x65,0x51,0x95,0xaa,0x95,
                                       0x51,0x65,0xa8,0x51,0x51,0x59,0x9a,0x55,0x51,0x56,0xa6,0x55,0x51,0x55,0xa8,0x55,
                                       0x51,0x56,0xa6,0x55,0x51,0x59,0x9a,0x55,0x51,0x65,0x6a,0x55,0x51,0x95,0xaa,0x95,
                                       0x52,0x55,0xaa,0x65,0x61,0x55,0xaa,0x59,0x91,0x55,0xaa,0x56,0xf3,0xff,0xff,0xff};



// variable declarations, initialized to zero
unsigned char D[15], Q[15], feedback = 0;
static volatile unsigned char sequenceType = 0;     // use volatile when variable is accessed from interrupts
static volatile uint8_t sequenceFlag = 0;
static volatile uint8_t rateindex = 0;
static volatile uint16_t rate = MEDIUM;
uint8_t eepromdata[dataSize];

// function declarations
void prbs(unsigned char color);
void memSeq(unsigned char type);
void fade();
void flash();

ISR(INT0_vect) { /* signal handler for external interrupt int0 portd2 sequence selection */

if (sequenceType >= seqSize) {sequenceType = 0; } else { sequenceType++; }
sequenceFlag = SET; 
_delay_ms(400);

} //ISR

ISR(INT1_vect) { /* signal handler for external interrupt int1 portd3 rate*/

  rateindex++;
  switch (rateindex)
  {
  case 1:
  rate = FAST;
  break;

  case 2:
  rate = MEDIUM;
  break;

  default:
  rateindex = 0;
  rate = SLOW;
  break;
  }
_delay_ms(50);
} // ISR


int main() 
{

// Set-up io drections, 0 = in, 1 = out 
DDRA = 0xff;
DDRB = 0xff;
DDRC = 0xff;
DDRD = 0xf3;

// external interrupts
GICR = (1<<INT0)|(1<<INT1); // enable interrupt 0, 1
MCUCSR = (1<<ISC01) | (1<<ISC00); // falling edge
sei(); // enable interrupts

while (1) { // loop endlessly
switch (sequenceType)
	{
	case ALLSEQ:
	default:
	  prbs(RED);
	  flash();
	  memSeq(MARCHR);
	  memSeq(MARCHG);
	  memSeq(WALKR);
	  memSeq(WALKG);
	  prbs(GREEN);
	  memSeq(RUNR);
	  memSeq(RUNG);
	  memSeq(JOGR);
	  memSeq(JOGG);
	  fade();
	  break;

	case PRBSR:
	  prbs(RED);
	  break;

	case PRBSG:
      prbs(GREEN);
	  break;

    case MARCHR:
	  memSeq(MARCHR);
	  break;

    case MARCHG:
	  memSeq(MARCHG);
	  break;

    case WALKR:
	  memSeq(WALKR);
	  break;

    case WALKG:
	  memSeq(WALKG);
	  break;

    case FLASH:
	  flash();
	  break;	  	  

    case RUNG:
	  memSeq(RUNG);
	  break;

    case RUNR:
	  memSeq(RUNR);
	  break;

    case JOGG:
	  memSeq(JOGG);
	  break;

    case JOGR:
	  memSeq(JOGR);
	  break;	  	  
	  	  
    case FADE:
	  fade();
	  break;	  	  
	} // switch

  } // while

   return(0); 
} // main

void prbs(unsigned char color)
{
int i = PRBSLEN;

D[2] = 1; // LFSR seed value

while(i--) 
  {

Q[0] = D[0];
Q[1] = D[1];
Q[2] = D[2];
Q[3] = D[3];
Q[4] = D[4];
Q[5] = D[5];
Q[6] = D[6];
Q[7] = D[7];
Q[8] = D[8];
Q[9] = D[9];
Q[10] = D[10];
Q[11] = D[11];
Q[12] = D[12];
Q[13] = D[13];
Q[14] = D[14];


//14, 13, 12, 10   feedback coefficients for 2^15  (0-based)
if ((Q[14] ^ Q[13]) ^ (Q[12] ^ Q[10])) {feedback = 1;} else {feedback = 0;}

D[0] = feedback;
D[1] = Q[0];
D[2] = Q[1];
D[3] = Q[2];
D[4] = Q[3];
D[5] = Q[4];
D[6] = Q[5];
D[7] = Q[6];
D[8] = Q[7];
D[9] = Q[8];
D[10] = Q[9];
D[11] = Q[10];
D[12] = Q[11];
D[13] = Q[12];
D[14] = Q[13];

if ( color == RED) {

PD(1,Q[13],1,Q[12],1,Q[11]); // red (even)
PB(1,Q[10],1,Q[9],1,Q[8],1,Q[7]);
PA(1,Q[6],1,Q[5],1,Q[4],1,Q[3]);
PC(1,Q[2],1,Q[1],1,Q[0],1,feedback);  }

else {

PD(Q[13],1,Q[12],1,Q[11],1); // green (odd)
PB(Q[10],1,Q[9],1,Q[8],1,Q[7],1);
PA(Q[6],1,Q[5],1,Q[4],1,Q[3],1);
PC(Q[2],1,Q[1],1,Q[0],1,feedback,1);  }

dly;

if (sequenceFlag) { sequenceFlag = CLEAR; break; }
 
  } // while
   return; 
} // prbs



void memSeq(unsigned char type)  // 
{
uint16_t i = PRBSLEN/16;
uint8_t j;

switch (type)
	{
	case MARCHR:
	default:
      eeprom_read_block((void*)&eepromdata, (const void*)&eepromMarchR, dataSize);
	  break;

	case MARCHG:
      eeprom_read_block((void*)&eepromdata, (const void*)&eepromMarchG, dataSize); 
	  break;

	case WALKR:
	    eeprom_read_block((void*)&eepromdata, (const void*)&eepromWalkR, dataSize); 
	  break;

    case WALKG:
	    eeprom_read_block((void*)&eepromdata, (const void*)&eepromWalkG, dataSize); 
	  break;	  	  

	case RUNR:
      eeprom_read_block((void*)&eepromdata, (const void*)&eepromRunR, dataSize);
	  break;

	case RUNG:
      eeprom_read_block((void*)&eepromdata, (const void*)&eepromRunG, dataSize); 
	  break;

	case JOGR:
	    eeprom_read_block((void*)&eepromdata, (const void*)&eepromJogR, dataSize); 
	  break;

    case JOGG:
	    eeprom_read_block((void*)&eepromdata, (const void*)&eepromJogG, dataSize); 
	  break;	  	  
	} // switch


while (i--) {

j=0;

for (j=0;j<dataSize;j++) {

PORTD = eepromdata[j];
PORTB = eepromdata[++j];
PORTA = eepromdata[++j];
PORTC = eepromdata[++j];
dly;

  }

if (sequenceFlag) { sequenceFlag = CLEAR; break; }

	}  // while
   return;
}



void flash() // flash red and green
{
int i = PRBSLEN/4;

while (i--)  {

PD(ON,OFF,ON,OFF,ON,OFF); // Green
PB(ON,OFF,ON,OFF,ON,OFF,ON,OFF);
PA(ON,OFF,ON,OFF,ON,OFF,ON,OFF);
PC(ON,OFF,ON,OFF,ON,OFF,ON,OFF);
dly;

PD(OFF,OFF,OFF,OFF,OFF,OFF); // OFF
PB(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
PA(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
PC(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
dly;

PD(OFF,ON,OFF,ON,OFF,ON); // RED
PB(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
PA(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
PC(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
dly;

if (sequenceFlag) { sequenceFlag = CLEAR; break; }

	}
return;
}

void fade()    // Fade: fade in green, turn on red (i.e. yellow), fade out to red. 
{
unsigned int i = PRBSLEN/32;
unsigned char factor = 4;


while (i--) {

for ( unsigned char dutyCycle = 255;dutyCycle > 0;dutyCycle-- ) { // fade in green

PD(ON,OFF,ON,OFF,ON,OFF); // Green
PB(ON,OFF,ON,OFF,ON,OFF,ON,OFF);
PA(ON,OFF,ON,OFF,ON,OFF,ON,OFF);
PC(ON,OFF,ON,OFF,ON,OFF,ON,OFF);
_delay_us((255-dutyCycle)*factor);

PD(OFF,OFF,OFF,OFF,OFF,OFF); // OFF
PB(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
PA(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
PC(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
_delay_us(dutyCycle*factor);

} // for

PD(ON,ON,ON,ON,ON,ON); // ON
PB(ON,ON,ON,ON,ON,ON,ON,ON);
PA(ON,ON,ON,ON,ON,ON,ON,ON);
PC(ON,ON,ON,ON,ON,ON,ON,ON);
dly;dly;

PD(OFF,ON,OFF,ON,OFF,ON); // RED
PB(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
PA(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
PC(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
dly;

for ( unsigned char dutyCycle = 255;dutyCycle > 0;dutyCycle-- )  { // fade in green

PD(OFF,ON,OFF,ON,OFF,ON); // RED
PB(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
PA(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
PC(OFF,ON,OFF,ON,OFF,ON,OFF,ON);
_delay_us(dutyCycle*factor);

PD(OFF,OFF,OFF,OFF,OFF,OFF); // OFF
PB(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
PA(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
PC(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
_delay_us((255-dutyCycle)*factor);

      } // for

PD(OFF,OFF,OFF,OFF,OFF,OFF); // OFF
PB(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
PA(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
PC(OFF,OFF,OFF,OFF,OFF,OFF,OFF,OFF);
dly;dly;

if (sequenceFlag) { sequenceFlag = CLEAR; break; }

   }  // while

return;
}

/*
LED logical to physical io mapping
Atmel AT90S8515, ATmega8515
orientation: topside, pin 1 upper left
 
LED #		pin #		pin Name	Color
1			17			PD7			RED
2			16			PD6			GREEN
3			15			PD5			RED
4			14			PD4			GREEN
5			11			PD1			RED
6			10			PD0			GREEN
7			8			PB7			RED
8			7			PB6			GREEN
9			6			PB5			RED
10			5			PB4			GREEN
11			4			PB3			RED
12			3			PB2			GREEN
13			2			PB1			RED
14			1			PB0			GREEN
15			39			PA0			RED
16			38			PA1			GREEN
17			37			PA2			RED
18			36			PA3			GREEN
19			35			PA4			RED			
20			34			PA5			GREEN
21			33			PA6			RED
22			32			PA7			GREEN
23			28			PC7			RED
24			27			PC6			GREEN
25			26			PC5			RED
26			25			PC4			GREEN
27			24			PC3			RED
28			23			PC2			GREEN
29			22			PC1			RED
30			21			PC0			GREEN
-
*/


