/**
 * Flasher Relay
 *
 *
 * Version: 1.0
 * Date: 2011-04-22
 * (c) Geert Van Espen
 */

#ifdef __18F4550
//#define DWENGO
#endif

#ifdef DWENGO
#include <dwengoConfig.h>
#include <dwengoBoard.h>
#include <dwengoADC.h>

#define FACTOR 6

#else

#define FACTOR 1

#include "FlasherRelay.h"

#define TRUE    1
#define FALSE   0
#define HIGH    1
#define LOW     0
#define PRESSED 0
#define INPUT   1
#define OUTPUT  0
#define BYTE unsigned char

void delay_ms(int);
void initADC(void);
int readADC(BYTE address);
int readADCaverage(BYTE address);
void clearLCD(void) {}
void setCursorLCD(unsigned char a, unsigned char b) {}
void appendIntToLCD(int a) {}
void appendStringToLCD_(const far rom char* message) {}
#define appendStringToLCD(message)   appendStringToLCD_((const far rom char*)(message))
void initBoard(void) {}
void backlightOn(void) {}


#ifdef __18F2550
#include <p18f2550.h>
#endif

#ifdef __18F4550
#include <p18f4550.h>
#endif

#endif


#include <timers.h>
#include <adc.h>
#include <delays.h>



#define byte unsigned char
#define PRESSED 0
#define S_N PORTBbits.RB4
#define S_S PORTBbits.RB5
#define TRUE 1

#define MAXCOUNT_ON   13
#define MAXCOUNT_OFF  13
#define DELAY_TIME    20
#define TRESHOLD1     6

// Prototypes.
void showScreen(void);
void showTolerance(void);
void writeEepromByte(byte addr, byte data);
byte readEepromByte(unsigned char addr);

//void initADC(void);
void blip(void);
void blop(void);

// Global variables.
int diff, a1, a2, boosted = 0;
int counterScreen = 0;
int tolerance = 0;
char from_eeprom;

// Program.
void main(void)
{
  int counterBoosted = 0;
  int counterDimmed = 0;
  int calibMode = 0;
  int i, j, d, diffTotal;


  initBoard();

  // Set internal oscillator to 8 MHz.
  OSCCONbits.IRCF0 = 1;
  OSCCONbits.IRCF1 = 1;
  OSCCONbits.IRCF2 = 1;

  initADC();
  backlightOn();


  // Set inputs/outputs.
  TRISAbits.TRISA2 = 0;
  TRISAbits.TRISA3 = 0;
  TRISAbits.TRISA4 = 0;
  TRISAbits.TRISA5 = 0;
  TRISCbits.TRISC1 = 0;
  TRISCbits.TRISC6 = 0;
  TRISCbits.TRISC7 = 0;

  // Enable pull-ups on PORTB.
  INTCON2bits.NOT_RBPU = 0;

  PORTCbits.RC6 = 0;   // LED off.
  PORTCbits.RC7 = 0;   // Indicator light off.
  PORTAbits.RA4 = 0;
  delay_ms(100); // Wait for relay to release.
  PORTCbits.RC6 = 0;   // LED off.
  PORTCbits.RC7 = 0;   // Indicator light off.
  PORTAbits.RA4 = 0;

  if (PORTBbits.RB4 == 0) calibMode = 1;

  if (calibMode)
  {
    clearLCD();
    appendStringToLCD("Calibrating...");
    PORTAbits.RA4 = 1;   // Activate relay, light off.
    for (i = 0, diffTotal = 0; i < 10; i++)
    {
      a1 = readADCaverage(0);
      a2 = readADCaverage(1);
      if (i % 2) PORTCbits.RC6 = 0; else PORTCbits.RC6 = 1;
      delay_ms(120);
      diff = a2 - a1;
      if (diff < 0) diff *= -1;
      diffTotal += diff;
    }
    tolerance = diffTotal / 10;
    clearLCD();
    appendStringToLCD("Tolerance:");
    appendIntToLCD(tolerance);
    if (tolerance < 0) tolerance *= -1;
    writeEepromByte(0, tolerance);
    delay_ms(2000);
    from_eeprom = readEepromByte(0);
    tolerance = from_eeprom;
    if (tolerance < 0) tolerance *= -1;
    for (i = 0; i < tolerance; i++)
    {
      PORTCbits.RC6 = 1;
      delay_ms(50);
      PORTCbits.RC6 = 0;
      delay_ms(250);
    }
    while(TRUE) {}
  }

  from_eeprom = readEepromByte(0);
  tolerance = from_eeprom;
  if (tolerance < 0) tolerance *= -1;




  while(TRUE)
  {
    if (PORTBbits.RB4 == 0) showTolerance();
    a1 = readADCaverage(0);
    a2 = readADCaverage(1);
    delay_ms(DELAY_TIME);
    diff = a2 - a1;
    if (diff < 0) diff *= -1;
    diff -= tolerance;
    if (diff < 0) diff *= -1;
    showScreen();
    //boosted = 0;
    if (diff > TRESHOLD1) boosted = 1;
    if (boosted)
    {
      PORTCbits.RC6 = 1;   // LED on.
      PORTCbits.RC7 = 1;   // Indicator light on.
      if (counterBoosted == 0) blip();
      PORTAbits.RA5 = 1;   // Activate relay to bypass shunt.
      counterBoosted++;
      setCursorLCD(1, 1);
      appendStringToLCD("+");
      if (counterBoosted > MAXCOUNT_ON)
      {
        boosted = 0;
        PORTCbits.RC6 = 0;   // LED off.
        PORTCbits.RC7 = 0;   // Indicator light off.
        blop();
        PORTAbits.RA4 = 1;   // Activate relay, light off.
        delay_ms(100);       // Wait for relay to arrive.
        PORTAbits.RA5 = 0;   // Deactivate relay to un-bypass shunt.
        counterBoosted = 0;
        counterDimmed = 0;
        while (counterDimmed < MAXCOUNT_OFF)
        {
          if (PORTBbits.RB4 == 0) showTolerance();
          counterDimmed++;
          a1 = readADCaverage(0);
          a2 = readADCaverage(1);
          delay_ms(DELAY_TIME);
          diff = a2 - a1;
          if (diff < 0) diff *= -1;
          showScreen();
        }
        PORTAbits.RA4 = 0;   // Deactivate relay, light on.
        delay_ms(5);         // Wait for relay to release.
      }
    }
  }
}

void showTolerance(void)
{
  int i = 0;

  PORTAbits.RA4 = 1;   // Activate relay, light off.
  PORTCbits.RC6 = 0;
  delay_ms(200);
  delay_ms(200);
  delay_ms(200);
  delay_ms(200);
  delay_ms(200);
  for (i = 0; i < tolerance; i++)
  {
    PORTCbits.RC6 = 1;
    delay_ms(50);
    PORTCbits.RC6 = 0;
    delay_ms(250);
  }
  delay_ms(200);
  delay_ms(200);
  delay_ms(200);
  delay_ms(200);
  delay_ms(200);
  PORTAbits.RA4 = 0;
}

void showScreen(void)
{
  char str[2];
  int val = 0;

  counterScreen++;
  str[0] = from_eeprom;
  str[1] = 0;
  val = str[0];

  if (counterScreen % 6 == 0)
  {
    counterScreen = 0;
    clearLCD();
    appendStringToLCD("Flash:");
    //appendIntToLCD(ADCON0);
    setCursorLCD(0, 6);
    appendIntToLCD(a1);
    setCursorLCD(1, 6);
    appendIntToLCD(a2);
    setCursorLCD(1, 11);
    appendIntToLCD(diff);
    setCursorLCD(0, 13);
    appendIntToLCD(tolerance);
  }
}

void writeEepromByte(byte addr, byte data)
{
  INTCONbits.GIE = 0;      // Disable interupts.

  EECON1bits.EEPGD = 0;    // Select the EEPROM memory.
  EECON1bits.CFGS = 0;     // Access the EEPROM memory.
  EECON1bits.WREN = 1;     // Enable writing.
  EEADR = addr;            // Set the address.
  EEDATA = data;           // Set the data.
  EECON2 = 0x55;           // Write initiate sequence.
  EECON2 = 0xaa;           // Write initiate sequence.
  EECON1bits.WR = 1;       // Start writing.
  while (!PIR2bits.EEIF);  // Wait for write to finish.
  PIR2bits.EEIF = 0;       // Clear EEIF bit.

  INTCONbits.GIE = 1; // Enable interupts
}


byte readEepromByte(unsigned char addr)
{
  EECON1bits.EEPGD = 0; // Select the EEPROM memory
  EECON1bits.CFGS = 0; // Access the EEPROM memory
  EEADR = addr; // Set the address
  EECON1bits.RD = 1; // Start reading

  return EEDATA; // Return the read value.
}

void blip(void)
{
  int i, d;
/*
  for (i = 0; i < 12; i++)
  {
    d = i / 4 + 1;
    PORTCbits.RC1 = 0;
    delay_ms(d);
    PORTCbits.RC1 = 1;
    delay_ms(d);
  }
*/
  for (i = 0; i < 21; i++)
  {
    d = i / 5 + 1;
    PORTCbits.RC1 = 0;
    Delay100TCYx(d * 3 * FACTOR);
    PORTCbits.RC1 = 1;
    Delay100TCYx(d * 3 * FACTOR);
  }
}

void blop(void)
{
  int i, d;
/*
  for (i = 0; i < 12; i++)
  {
    d = (11 - i) / 4 + 1;
    PORTCbits.RC1 = 0;
    delay_ms(d);
    PORTCbits.RC1 = 1;
    delay_ms(d);
  }
*/
  for (i = 0; i < 20; i++)
  {
    d = (19 - i) / 5 + 1;
    PORTCbits.RC1 = 0;
    Delay100TCYx(d * 3 * FACTOR);
    PORTCbits.RC1 = 1;
    Delay100TCYx(d * 3 * FACTOR);
  }
}

int readADCaverage(BYTE address)
{
  unsigned int i, t;

  for (i = 0, t = 0; i < 8; i++)
  {
    t += readADC(address);
  }

  return t / 8;
}

#ifndef DWENGO
void delay_ms(int d)
{
  int i;
  for (i = 0; i < 20; i++) Delay100TCYx(d);
}


void initADC(void)
{
  TRISA = 0b00000011;  // Set AN0 and AN1 as analog input.

  return;
}

int readADC(BYTE address)
{
  int voltage = 0;

  if (address == 0) ADCON0 = 0b00000001;   // ADC port channel 0 (AN0), Enable ADC.
  if (address == 1) ADCON0 = 0b00000101;   // ADC port channel 1 (AN1), Enable ADC.
  if (address == 2) ADCON0 = 0b00001001;   // ADC port channel 2 (AN2), Enable ADC.
  if (address == 3) ADCON0 = 0b00001101;   // ADC port channel 3 (AN3), Enable ADC.

  ADCON1 = 0b00001010;   // Use Internal Voltage Reference (Vdd and Vss) AN0..3=analog
  ADCON2 = 0b10011110;   // Right justify result, 6 TAD, Tosc/64.

  ConvertADC();      // Start A/D converter.
  while(BusyADC());  // This loop check is A/D converter currently performing a conversion.
  voltage = ReadADC();

  return voltage;
}

#endif

