#include <stdio.h>
#include <myuart.h>
#include <dmx.h>

void ShowState();
int csmallwait();
void UpdateState(int command);
char fadeup(int currentvalue,int totaltime);
char fadedown(int currentvalue,int totaltime);

// The DMX channel map
#define	BLUE_CHANNEL	1
#define	GREEN_CHANNEL	2
#define	WHITE_CHANNEL	3
#define	SOUNDA_CHANNEL	16
#define	SOUNDB_CHANNEL	18

#define SETSMOKEON		dmxout[6]=0xFF; dmxout[7]=0xFF; dmxout[8]=0xFF; dmxout[9]=0xFF; dmxout[10]=0xFF;
#define SETSMOKEOFF		dmxout[6]=0x0; dmxout[7]=0x0; dmxout[8]=0x0; dmxout[9]=0x0; dmxout[10]=0x0;

// The inputs
#define PIRONE			0x08
#define PIRTWO			0x04

main()
{
	unsigned int i,loopa;
	volatile char *mydmxdata=(volatile char*)&_dmxoutputdata;
	char channel=0;
	char newdata=0;

	printf("\n\rDMX haloween controller.\n\r");
   	fflush(stdout);

	// Clear output
	for (i=0;i<512;i++) mydmxdata[i]=0;

   	printf("Monitoring input and sending chase...\n\r");
   	fflush(stdout);

	while (1) {
		// Check for needing to do stuff
		if (_cwaiting()!=0) {
			newdata=_cget();
			switch (newdata) {
				case '1':
					// Pretend we had an input from pir 1
					UpdateState(1);
					break;
				case '2':
					// Pretend we had an input from pir 2
					UpdateState(2);
					break;
				case 'r':
					// Reset all states
					UpdateState(3);
					break;
			}
		}
		// Check for any real inputs
		// These should be >0 but will set to 0 to test
		if ((*gpiodatain&PIRONE)>0) {
			UpdateState(1);
		}
		if ((*gpiodatain&PIRTWO)>0) {
			UpdateState(2);
		}
		for (loopa=1;loopa<20;loopa++) {
			UpdateState(0);
			csmallwait();
		}
		// Display current status on the screen and wait
		ShowState();
	}
}

void UpdateState(int command)
{
	static int statea=0;
	static int stateb=0;
	volatile char *dmxout=(volatile char*)&_dmxoutputdata;

	int soundreq=0;

	// Which state should we go upon a command? (0=ignore command)
	int newstatea=0;
	int newstateb=0;

	// Depending upon their position increment the state machine
	if (statea!=0) statea++;
	if (statea>10500) statea=0;

	if (stateb!=0) stateb++;
	if (stateb>11025) stateb=0;


	// Set outputs and flags depending upon state machine positions

	// STATEA
	if (statea==0) { dmxout[BLUE_CHANNEL]=0; dmxout[GREEN_CHANNEL]=0; newstatea=1; }
	if ((statea>0)&&(statea<501)) { dmxout[BLUE_CHANNEL]=0; dmxout[GREEN_CHANNEL]=fadeup(statea,500); soundreq=1; }
	if ((statea>500)&&(statea<1001)) { dmxout[BLUE_CHANNEL]=fadeup(statea-500,500); dmxout[GREEN_CHANNEL]=fadedown(statea-500,500); soundreq=1; }
	if ((statea>1000)&&(statea<1501)) { dmxout[BLUE_CHANNEL]=0xFF; dmxout[GREEN_CHANNEL]=fadeup(statea-1000,500); soundreq=1; }
	if ((statea>1500)&&(statea<3001)) { dmxout[BLUE_CHANNEL]=0xFF; dmxout[GREEN_CHANNEL]=0xFF; soundreq=1; }
	if ((statea>3000)&&(statea<9001)) { dmxout[BLUE_CHANNEL]=0xFF; dmxout[GREEN_CHANNEL]=0xFF; soundreq=0; newstatea=3001; }
	if ((statea>9000)&&(statea<10501)) { dmxout[BLUE_CHANNEL]=fadedown(statea-9000,1500); dmxout[GREEN_CHANNEL]=fadedown(statea-9000,1500); }

	// STATEB
	if (stateb==0) { dmxout[WHITE_CHANNEL]=0; SETSMOKEOFF; newstateb=1; }
	if ((stateb>0)&&(stateb<251)) { dmxout[WHITE_CHANNEL]=0; SETSMOKEOFF; soundreq=3; }
	if ((stateb>250)&&(stateb<301)) { dmxout[WHITE_CHANNEL]=0xFF; SETSMOKEOFF; soundreq=3; }
	if ((stateb>300)&&(stateb<326)) { dmxout[WHITE_CHANNEL]=0; SETSMOKEOFF; soundreq=3; }
	if ((stateb>325)&&(stateb<401)) { dmxout[WHITE_CHANNEL]=0xFF; SETSMOKEON; soundreq=3; }
	if ((stateb>401)&&(stateb<1026)) { dmxout[WHITE_CHANNEL]=0; SETSMOKEON; soundreq=3; }
	if ((stateb>1025)&&(stateb<3526)) { dmxout[WHITE_CHANNEL]=0; SETSMOKEOFF; soundreq=3; }
	if ((stateb>3525)&&(stateb<11026)) { dmxout[WHITE_CHANNEL]=0; SETSMOKEOFF; newstateb=3526; }

	// Set the sound output
	switch (soundreq) {
		case 0: dmxout[SOUNDA_CHANNEL]=0;
				dmxout[SOUNDB_CHANNEL]=0;
				break;
		case 1: dmxout[SOUNDA_CHANNEL]=0xFF;
				dmxout[SOUNDB_CHANNEL]=0;
				break;
		case 3: dmxout[SOUNDA_CHANNEL]=0;
				dmxout[SOUNDB_CHANNEL]=0xFF;
				break;
	}

	// Deal with any new commands
	switch (command) {
		case 1: if (newstatea>0) statea=newstatea;
				break;
		case 2: if (newstatea>0) statea=newstatea;
				if (newstateb>0) stateb=newstateb;
				break;
		case 3:	statea=0;
				stateb=0;
				break;
	}

}

char fadeup(int currentvalue,int totaltime) {
	int rval;
	float a,b;
	a=(float)currentvalue;
	b=(float)totaltime;

	rval=(int)(255.0*currentvalue/totaltime);
	return (char)rval;

}

char fadedown(int currentvalue,int totaltime) {
	int rval;
	float a,b;
	a=(float)currentvalue;
	b=(float)totaltime;

	rval=(int)(255-(255.0*currentvalue/totaltime));
	return (char)rval;
}

void ShowState()
{
	int p;
	volatile char *mydmxdata=(volatile char*)&_dmxoutputdata;
	// First clear the screen
	printf("%c[2J",27);
	// print outputs
	printf("OUT: ");
	for(p=0;p<20;p++) printf("%i,",mydmxdata[p]);
	printf("\n\r");
	fflush(stdout);
}

int csmallwait()
{
	unsigned int i,p;
	p=0;

	for(i=0;i<0x700;i++) p++;
	return (p);
}