/*  frontind.c
 *
 *  Kevin Jones - 10/5/20
 *
 *  - For PIC12F675
 *
 *  Front indicator for MG magnette
 *  -------------------------------
 *
 *  Uses an RGB LED to show either white (for a sidelight) or amber (for a turn
 *  signal), depending on the voltage supplied to an analogue input.  Colours are
 *  produced by three PWM outputs, with mark:space ratios preconfigured.
 *
 *	Transitions on the analogue input sets the LED either off, amber or white.  White
 *	is nominally 50% (6v with a 12v input) and amber is nominally full voltage.
 *
 *  I/O
 *  ---
 *
 *	Pin 3        AN3/GP4		Analogue input
 *
 *	Pin 7        GP0        Output to green LED
 *	Pin 6		     GP1			  Output to red LED
 *	Pin 5		     GP2			  Output to blue LED
 *
 *	Revision history
 *	----------------
 *
 *	0.01		     9/5/20		First version.  Based on LED test program for
 *                          PIC18F2455, version 0.07
 *
 *  0.02         9/5/20     Waits 44ms on power-up before lighting.  Low
 *                          pass filter applied to input analogue signal.
 *
 *  0.03         10/5/20    RGB values for white sidelight are stored in
 *                          EEPROM.
 */

#define OFF			  0x01
#define WHITE		  0x02
#define AMBER		  0x04

#define LED_RED		GPIO.F1
#define LED_GREEN GPIO.F0
#define LED_BLUE  GPIO.F2

unsigned char red, green, blue;
unsigned char t_red, t_green, t_blue;
unsigned char s;								// State machine
unsigned char wait;
unsigned char white_r, white_g, white_b;
unsigned char amber_r, amber_g, amber_b;

void interrupt(void)
{
    INTCON.F2 = 0;             // Reset timer 0 interrupt flag
    
    if (wait) wait--;
    
		if (++t_red > 17) t_red = 0;
		if (++t_green > 17) t_green = 0;
		if (++t_blue > 17) t_blue = 0;

		if (red > t_red) LED_RED = 1; else LED_RED = 0;
		if (green > t_green) LED_GREEN = 1; else LED_GREEN = 0;
		if (blue > t_blue) LED_BLUE = 1; else LED_BLUE = 0;

}

void off(void)
{
	red = 0; green = 0; blue = 0;
	s = OFF;
}

void amber(void)
{
//	red = 17; green = 6; blue = 0;        // Input 12v
	red = amber_r; green = amber_g; blue = amber_b;
	s = AMBER;
}

void white(void)
{
//	red = 16; green = 17; blue = 6;				// Input 6v, red & green series resistors 33R, blue 82R
	red = white_r; green = white_g; blue = white_b;
	s = WHITE;
}

/* Main program */

void main()
{
	unsigned char v;							// Voltage measured from analogue input
	wait = 200;

/* Set PIC options */

  CMCON = 0x07;                // Comparators off
  TRISIO = 0x38;
  ANSEL = 0x58;				            // Analogue input on RA3/GP4
  ADCON0 = 0x0D;					       	// ADC module on, input on AN3

/* Configure timer 0 to generate PWM output */

	INTCON = 0xA0;                  // Interrupt on timer 0 overflow
	OPTION_REG = 0xD0;							// Timer 0 on, 8-bit, 1:2 prescale

	LED_RED = 0;
	LED_GREEN = 0;
	LED_BLUE = 0;

	t_red = 0; t_green = 6; t_blue = 12;
	off();
	v = 75;                         // 6v nominal value for white LED

	ADCON0.GO = 1;								// Start first conversion
	
	white_r = Eeprom_read(0);
	white_g = Eeprom_read(1);
	white_b = Eeprom_read(2);
	
	amber_r = Eeprom_read(3);
	amber_g = Eeprom_read(4);
	amber_b = Eeprom_read(5);

	/* Main loop */

	while(1) {

		/* Check analogue input */

		if (!ADCON0.GO && !wait) {				// Conversion has finished
     if (ADRESH > v) v++;
     else if (ADRESH < v) v--;

			switch (s) {
				case OFF:
					if (v > 125) amber();
					else if (v > 50) white();
					break;

				case WHITE:
					if (v > 125) amber();
					else if (v < 25) off();
					break;

				case AMBER:
					if (v < 25) off();
					else if (v < 100) white();
					break;
			}

			ADCON0.GO = 1;
			wait = 2;
		}
  }
}
