// para Arduino nano

#include <avr/wdt.h>  
//#include <TimerOne.h>
#define TIMER1_COMPB_vect 	_VECTOR(12)  // con esto no mejora
// Pin definitions
#define         Relay_1_Pin1       6    
#define         Relay_1_Pin2       7     
#define         Relay_2_Pin1       8  
#define         Relay_2_Pin2       9
#define         Pilot_PWM_Pin      10
#define         GFCI_Test_Pin      11
#define         Indicator_LED      13

#define         GFCI_ADC_Pin            A0
#define         Pilot_ReadADC_Pin       A1

// State and fault definitions
#define         STATE_A                     1         // No EV connected
#define         STATE_B                     2         // EV Connected but not charging
#define         STATE_C                     3                                   // Charging
#define         CHARGE_PWM_DUTY             4000 //350       // Seems to result in 7.4 kW charging rate. (Lower numbers = higher duty cycle and charge rates)

#define         _12_VOLTS                  12
#define         _9_VOLTS                    9
#define         _6_VOLTS                    6
#define         _3_VOLTS                    3
#define         _DIODE_FAULT                1   // el diodo del circuito del vehiculo??
#define         _FAULT                      0

#define         FAIL                        0
#define         PASS                        1
#define         STARTUP_GFCI_TEST_FAIL      2
#define         GFCI_DETECT                 3
#define         DIODE_FAULT                 4
#define         VOLTAGE_CLASS_FAULT         5

#define         START_CHARGE_GFCI_TEST_FAIL    6
// ADC ranges for classifying voltage levels (923 = 12v and 285 = -12v)
#define         POS_12V_MAX                936         // 12.5V,   12v --> 4,51v
#define         POS_12V_MIN                910         // 11.5V
#define         POS_9V_MAX                 868         // 10V        
#define         POS_9V_MIN                 815         // 8V
#define         POS_6V_MAX                 789         // 7V
#define         POS_6V_MIN                 735         // 5V
#define         POS_3V_MAX                 708         // 4V  
#define         POS_3V_MIN                 656         // 2V
#define         NEG_12V_MAX                327         // -11.5v
#define         NEG_12V_MIN                245         // -12,5
  //  GFCI
#define         GFCI_FAULT_THRESHOLD        300
#define         GFCI_FAULT_ABORT_THRESHOLD  500   
#define         FAULT_COUNT_THRESHOLD       10
// Global variable definitions (no bueno !!!!!)
volatile int   Pilot_Low_ADC = 320;  // originalmente no estban con valor
volatile int   Pilot_High_ADC = 930;
volatile int   GFCI_ADC;
volatile byte  ADC_Channel = 0;
volatile int  cont_print_COMP = 0;   // para mis pruebas
volatile int  cont_print_OVF = 0;    // para mis pruebas
volatile byte PVC_prub = 0;          //   ""
// Declaración de funciones
void Close_Relays();
void Open_Relays();
byte Read_Pilot_Voltage();
byte GFCI_Test();
void Fault_Handler(byte Fault_type);
// ========================================================
void setup() {
  cont_print_COMP = 0; // pruebas
  cont_print_OVF = 0;
  PVC_prub = 0;    // ""
  delay(500);  
  noInterrupts(); 
  
  Serial.begin(115200);
  Serial.println("starting up...");
  pinMode(Indicator_LED, OUTPUT);

  // Abrir Reles
  Open_Relays();
  pinMode(Pilot_PWM_Pin, OUTPUT);  // Configue Pin 10 for PWM output 1kHz.
  
  // -------- Configure Timer 1   ---------
    ICR1 = 4000;   //1000 PWM-freq=16MHz/(2*8*1000)=1kHz, con prescaler = 8
    TCCR1A =  0;
    TCCR1B =  0;   
    TCCR1A = 0b00100010;   //  PWM
    TCCR1B = 0b00010010;   // Prescaler: WGM13 =1 prescaler = 8 (0b00010010;)  
    OCR1B = 100;          // Duty Cicle, PWM pin 10, originalmente a 0;  
    TIMSK1 |= 1 << TOIE1; // enable Timer Overflow Interrupt  (ahora convierte los 3 canales)
                          // al ponerla el ADC no convierte
    TIMSK1 |= 1 << OCIE1B;  // No funciona??enable Timer triggered when timer counter matches OCR1B (Output Compare Register B).                
  // --------- Configure ADC Module -------
    ADMUX = B01000000;        // AREF = 1, Referencua =5v (Vcc)
    ADCSRA = B10001111;       // Prescaler=128;  16MHz/ 128=125KHz, 125KHz/13clocks=9,615Khz
                              //  (ADC Sampling rate)=104uS (one conversion period) 
                              // ADEN=1, Enable ADC
      // Enable Watch Dog 4seg
  // wdt_enable(WDTO_4S);
  // wdt_reset(); // quitados de momento

  interrupts(); // habilita interrupciones
  if(GFCI_Test() != PASS) {     // al habilitar este código entra en las 2 interrupciones
    Fault_Handler(STARTUP_GFCI_TEST_FAIL);
  }
  
 OCR1B = 300;    // originalmente 0 (no funciona con 0)  Duty Cicle= (OCR1B+1)/2^16
/*while(1)  {  // solo para pruebas del ADC
    delay(100);
    // prueba para Leer Pilot_High_ADC
    ADMUX = B01000001;     // pruebas when the PWM signal is in the middle of its high period
    ADCSRA |= B01000000;   //   Start ADC, funciona lee el potenciómetro
    ADC_Channel = 2; 
    Serial.print(Pilot_Low_ADC); Serial.print(", ");
    Serial.print(Pilot_High_ADC); Serial.print(", ");
    Serial.println(GFCI_ADC);
 } */

   // Ready to start main loop
  Serial.println("Starting in State A");
}
// ===========================================================               
void loop() {
    /*  solo pruebas */
  // increm de contadores en las inerrupciones
  if (cont_print_COMP >= 100 and cont_print_OVF >= 100) {
    Serial.print(PVC_prub); Serial.print(", ");
    Serial.print(cont_print_COMP + cont_print_OVF); Serial.print(": ");
    Serial.print(Pilot_Low_ADC); Serial.print(", ");
    Serial.print(Pilot_High_ADC);Serial.print(", ");
    Serial.println(GFCI_ADC);
    cont_print_COMP = 0;
    cont_print_OVF = 0;
  }
  static byte Current_State = STATE_A;  
  static byte PVC; 
  // wdt_reset();      // quitado de momento
  delay(10); 

  PVC = Read_Pilot_Voltage();        // llamada a la Función
  PVC_prub=PVC; // para las pruebs
    // ---- Fault detection ------------------------
  if(GFCI_ADC > GFCI_FAULT_THRESHOLD)
    Fault_Handler(GFCI_DETECT);

  if(PVC == _DIODE_FAULT) // si == 1
    Fault_Handler(DIODE_FAULT); // llama a la función con 4
  
  if(PVC == _FAULT)   // si == 0
    Fault_Handler(VOLTAGE_CLASS_FAULT);   // 5
                // PVC = Pilot Voltage Classification
// ---- Main State machine logic ------------ 
  switch (Current_State)  {
    case STATE_A:
      if(PVC == _9_VOLTS or PVC == _6_VOLTS or PVC == _3_VOLTS)  {
        OCR1B = 500;  // pruebas     originalmente   OCR1B = 0;
        digitalWrite(Indicator_LED, HIGH);
        Serial.println("State B");        
        Current_State = STATE_B;  
      }  
      break;
      
    case STATE_B:       
      if(PVC == _12_VOLTS)  {
        OCR1B = 0;   // pruebas     originalmente   OCR1B = 0;
        digitalWrite(Indicator_LED, LOW);
        Serial.println("State A");
        Current_State = STATE_A;
      }     
      else if(PVC == _6_VOLTS or PVC == _3_VOLTS)  {
        if(GFCI_Test() != PASS) {
          Fault_Handler(START_CHARGE_GFCI_TEST_FAIL);
        } 
        else  {
          Serial.println("State C");
          Close_Relays();
          Current_State = STATE_C;
        }
      } 
      break;
      
    case STATE_C:
      if(PVC == _12_VOLTS or PVC == _9_VOLTS)  {
        Open_Relays();
        Serial.println("State B");        
        Current_State = STATE_B;
      }      
      break;    
  }

} // de void loop()
//  ############################################################
//  --------------        Funciones   -------------------------
//  ############################################################
byte Read_Pilot_Voltage()
{
  static int Fault_Count = 0;
  static int Previous_Value = _12_VOLTS;
  
  // Here we take the Pilot voltages and classfy them into states
  if((Pilot_Low_ADC > NEG_12V_MIN and Pilot_Low_ADC < NEG_12V_MAX) or OCR1B == 0) {
    if(Pilot_High_ADC > POS_12V_MIN and Pilot_High_ADC < POS_12V_MAX) {
      Previous_Value = _12_VOLTS; Fault_Count = 0;
      return(_12_VOLTS); 
    }
    else if(Pilot_High_ADC > POS_9V_MIN and Pilot_High_ADC < POS_9V_MAX) {
      Previous_Value = _9_VOLTS; Fault_Count = 0;
      return(_9_VOLTS);
    }
    else if(Pilot_High_ADC > POS_6V_MIN and Pilot_High_ADC < POS_6V_MAX) {
      Previous_Value = _6_VOLTS; Fault_Count = 0;
      return(_6_VOLTS);
    }
    else if(Pilot_High_ADC > POS_3V_MIN and Pilot_High_ADC < POS_3V_MAX) {
      Previous_Value = _3_VOLTS; Fault_Count = 0;
      return(_3_VOLTS);
    }
    else {
    // The measured voltage is out of any expected range. We call this a fault condition
      Fault_Count++;
      if(Fault_Count > FAULT_COUNT_THRESHOLD) // si > 10
        return(_FAULT); // return 0
      else  
        return(Previous_Value);
    }
  }
  else  {
    // Diode fault - the negative PWM should always be -12v, if it's not we have a diode missing fault!
    Fault_Count++;    
      if(Fault_Count > FAULT_COUNT_THRESHOLD)
        return(_DIODE_FAULT);   // return 1
      else  
        return(Previous_Value);
  }
  
}
//  ############################################################
void Fault_Handler(byte Fault_type)
{
  Open_Relays();
  OCR1B = 0;    // originalmente 0

  Serial.print("FAULT: "); Serial.print(Fault_type);
  
  while(1) {      // se queda parpadeando el diodo LED   13
    delay(100);
    digitalWrite(Indicator_LED, HIGH);
    delay(100); 
    digitalWrite(Indicator_LED, LOW);

    // wdt_reset();   // quitado de momento
  }
}
//  ############################################################
byte GFCI_Test()                // This routine energises the test coil on the current transformer using a 50Hz square wave
{                               // de momento siempre pasa el test
  return(PASS);
}

void Close_Relays()
{
  pinMode(Relay_1_Pin1, OUTPUT); pinMode(Relay_2_Pin1, OUTPUT);
  pinMode(Relay_1_Pin2, OUTPUT); pinMode(Relay_2_Pin2, OUTPUT);        
  digitalWrite(Relay_1_Pin1, HIGH); digitalWrite(Relay_2_Pin1, HIGH);   
  digitalWrite(Relay_1_Pin2, HIGH); digitalWrite(Relay_2_Pin2, HIGH);

  pinMode(Relay_1_Pin1, OUTPUT); pinMode(Relay_2_Pin1, OUTPUT);
  pinMode(Relay_1_Pin2, OUTPUT); pinMode(Relay_2_Pin2, OUTPUT);   //añadirlo bién
  digitalWrite(Relay_1_Pin1, HIGH); digitalWrite(Relay_2_Pin1, HIGH);   
  digitalWrite(Relay_1_Pin2, HIGH); digitalWrite(Relay_2_Pin2, HIGH);    // añadirlo bién
}
void Open_Relays()
{
  pinMode(Relay_1_Pin1, OUTPUT); pinMode(Relay_2_Pin1, OUTPUT);
  pinMode(Relay_1_Pin2, OUTPUT); pinMode(Relay_2_Pin2, OUTPUT);
  digitalWrite(Relay_1_Pin1, LOW); digitalWrite(Relay_2_Pin1, LOW); 
  digitalWrite(Relay_1_Pin2, LOW); digitalWrite(Relay_2_Pin2, LOW);

  pinMode(Relay_1_Pin1, OUTPUT); pinMode(Relay_2_Pin1, OUTPUT);
  pinMode(Relay_1_Pin2, OUTPUT); pinMode(Relay_2_Pin2, OUTPUT);
  digitalWrite(Relay_1_Pin1, LOW); digitalWrite(Relay_2_Pin1, LOW); 
  digitalWrite(Relay_1_Pin2, LOW); digitalWrite(Relay_2_Pin2, LOW);    
}

//  ##################################################################
//  --------------------    Interrupciones  ------------------
//  ###################################################################
// This code runs when the PWM signal is in the middle of its low period
ISR(TIMER1_OVF_vect)
{
  static byte selector = 0;
  if(ADCSRA & 0b01000000)       // If the ADC is still performing a conversion (it shouldn't be) then return
    return;
      
  if(selector)  {
    ADMUX = B01000000;     // A0,     
    ADCSRA |= B01000000;  // Start the next ADC conversión
    ADC_Channel = 0;    // GFCI
    selector = 0;
  } 
  else  {     
    ADMUX = B01000001;  // A1,
    ADCSRA |= B01000000;  // Start the next ADC conversión
    ADC_Channel = 1;  // Pilot_Low_AD
    selector = 1;   
  }
  /*  solo pruebas */
  cont_print_OVF ++;  // cont_print+1 no vale
  pinMode(Relay_1_Pin1, OUTPUT); 
  digitalWrite(Relay_1_Pin1, LOW);
 // --------Funciona pero y lee Pilot High ---------
}

// This code runs when the PWM signal is in the middle of its high period
ISR(TIMER1_COMPB_vect) //originalmente CAPT_vect
{
  static byte selector = 0; // originalmente a 0
  if(ADCSRA & 0b01000000)
    return;
  
  if(selector)  {
    ADMUX = B01000000;     
    ADCSRA |= B01000000;  // Start the next ADC conversión
    ADC_Channel = 0;  // GFCI
    selector = 0;   
  } 
  else  {     
    ADMUX = B01000001;
    ADCSRA |= B01000000;
    ADC_Channel = 2;  // Pilot_High_AD
    selector = 1;     
  }
  cont_print_COMP ++;  // cont_print+1 no vale
  pinMode(Relay_1_Pin1, OUTPUT); 
  digitalWrite(Relay_1_Pin1, HIGH);
 // -------- entra ---------
}

// Interrupt service routine for ADC conversion complete
ISR(ADC_vect)   //  si entra en esta interrup pero no convierte
{    
  unsigned char adcl = ADCL;
  unsigned char adch = ADCH;

  switch(ADC_Channel)  {
    case 0:
      GFCI_ADC = (adch << 8) | adcl;
      //GFCI_ADC = 9; 
    break;
    
    case 1:
      //Pilot_Low_ADC = (adch << 8) | adcl;
      Pilot_Low_ADC  = 320;  // -12v  prueba
    break;
    
    case 2:
      Pilot_High_ADC = (adch << 8) | adcl;
      //Pilot_High_ADC = 860;   //9v         923--> +12v   prueba
    break;
  }
 
}