
////////////////////////////////////////////////////////////////////////////////////////////////////
//ANDRUINO LIBRARY
//A.Scavuzzo
//www.andruino.it
////////////////////////////////////////////////////////////////////////////////////////////////////


/////////////////////////////////////////////////////
//INTERRUPT ROUTINES (software interrupt done using millis()
/////////////////////////////////////////////////////

#define MAX_ETH_ERROR_PERSIST 2                                     //after 2 ethernet init, the ping will be every 1 minute




byte blink_led = 0;
void int_Interrupt_Timer_1sec () {
  byte temp_send_http_req;
  //reset watchdog
  //wdt_reset();


  if (watchdog_cnt > 30) {
    Restart(true, true);         //true, increment in flash the fault counter, true SILENT power-up
  }
  else
    watchdog_cnt++;

  //Serial.print("watchdog_cnt: ");Serial.println(watchdog_cnt);


  seconds_total = millis() / 1000;
  //seconds_total++;

#ifdef BLINK_LED_RUNNING
  digitalWrite(LED_BUILTIN, blink_led % 4);     //each 4 sec
  blink_led++;
#endif


  //Used to avoid to connect to http client during user connections (as server)
  connection_isfar++;
  if (connection_isfar == 65535)
    connection_isfar = CONNECTION_FAR_IS;

  //  Serial.println(connection_isfar);


  //Calculate seconds/minutes/hours
  seconds_counter++;


  if (active_iphone_connection) {
    seconds_counter_sensors = seconds_counter_sensors + 5;      //increse read time
    if (seconds_counter_sensors > 59)
      seconds_counter_sensors = 0;
  }
  else {
    seconds_counter_sensors = seconds_counter;
  }


  //increment time
  if (seconds_counter % (CHECK_LIMITS_EVERY_SEC) == 0)                        //every 3 second
    check_limits_base = true;
  if ((seconds_counter + 1) % (CHECK_LIMITS_NODE_EVERY_SEC) == 0)             //every 5 second
    check_limits_NRF = true;


  if ((seconds_counter) % (CHECK_POWER_CONS_EVERY_SEC) == 0)        //every 5 second
    check_power_consumption = true;

  //active connection, Arduino send the data to server continuosly
  //when active connection, http request is done every 2 seconds
  if (eth_err_restart_persist < MAX_ETH_ERROR_PERSIST) {
    if (active_iphone_connection) {
      if (seconds_total % (client_sendjson_active_req_every_sec) == 0 )
        send_http_active_client_req = true;
    }
    //if the connection is not in place, Arduino will send the data only for data logger
    //PING is every 15 seconds
    else {
      if (seconds_total % (ping_req_every_sec) == 0 )
        send_ping_req = true;
      if (seconds_total % (client_sendjson_notactive_req_every_sec) == 0 && client_sendjson_notactive_req_every_sec > 0)
        send_http_notactive_client_req = true;
    }
  }





  //every minute
  if (seconds_counter > 59) {

    //if no connection, try again each 1 minute
    if (!station_connection_ok && access_point_connection_ok == false) {
      //restart_eth=true;
      restart_board = true;
    }

    seconds_counter = 0;
    minutes_counter++;

    //send a ping every minute when an ethernet card error persist
    if (eth_err_restart_persist >= MAX_ETH_ERROR_PERSIST)
      send_ping_req = true;



    if (minutes_counter % 5 == 0) {                                //every 5 minutes check the timers
      check_timers = true;
      system_json_data_scan = 1;                                  //send on json also static info (low frequency info)
    }

    if (minutes_counter % (CHECK_DALLAS_TEMP_MIN) == 0) //every 1 minutes
      check_DallasTemperature = true;
    if (minutes_counter > 59) {
      minutes_counter = 0;
      hours_counter++;
      if (hours_counter > 23) {
        hours_counter = 0;
        days_counter++;
      }
    }
  }

  //days of the week are 0(Sun)-1(Mon)-2-3-4-5-6(sat)
  if (days_counter > 6) {
    days_counter = 0;
  }

  //Each minute trigger READ OF SENSORS
  if (seconds_counter_sensors == 5)                                         //every minute read
    check_sensor_minutes[0] = true;
  else if (seconds_counter_sensors == 10)                                    //every minute read
    check_sensor_minutes[1] = true;
  else if (seconds_counter_sensors == 15)                                    //every minute read
    check_sensor_minutes[2] = true;
  else if (seconds_counter_sensors == 20)                                    //every minute read
    check_sensor_minutes[3] = true;
  else if (seconds_counter_sensors == 25)                                    //every minute read
    check_sensor_minutes[4] = true;
  else if (seconds_counter_sensors == 30)                                    //every minute read
    check_sensor_minutes[5] = true;
  else if (seconds_counter_sensors == 35)                                    //every minute read
    check_sensor_minutes[6] = true;
  else if (seconds_counter_sensors == 40)                                    //every minute read
    check_sensor_minutes[7] = true;
  else if (seconds_counter_sensors == 45)                                    //every minute read
    check_sensor_minutes[8] = true;
  else if (seconds_counter_sensors == 50)                                    //every minute read
    check_sensor_minutes[9] = true;


  if (((seconds_counter) % 2 == 0 && active_iphone_connection) || (seconds_counter == 32 && !active_iphone_connection)) {                                  //every 2 second when connected or every minute when not connected
    check_sensor_seconds[0] = true;
    check_sensor_seconds[1] = true;
  }



  //////////////////////////////////////////
  //TEMPORIZED OUTPUTS OR TIMERS
  //reset the OUTPUTS after a delay
  for (int i = 0; i < sizeof(base_digital_pins_used); i++) {    //MAXPIN
    if (ArduinoIO[i].used == 1 && ArduinoIO[i].mode == 1 && ArduinoIO[i].time_counter > 0) {  //Used and INPUT (mode=0 -- input, mode=1 --output, mode=3 --pwm)
      ArduinoIO[i].time_counter--;
      if (ArduinoIO[i].time_counter == 0) {
        writeDig(ArduinoIO[i], false);                            //reset the OUTPUT after the delay
      }
    }
  }


#if NRF24L_ENABLE == 1
  for (byte k = 0; k < NRF24LMaxModules; k++) {
    if (SystemNRF24LPins[k].RNF24LAddr != 0) {
      if (SystemNRF24LPins[k].alive_counter > 0)
        SystemNRF24LPins[k].alive_counter--;
      if (SystemNRF24LPins[k].alive_counter == 1)
        SystemNRF24LPins[k].alive_fail_counter++;
    }
  }
#endif



  /*
    //EXAMPLE LOGIC BETWEEN PINS
    //code used to create a logic on some PIN, enabled bu the VAR 8
    if (Arduino_User_var[8].value>0) {
      if(digitalRead(4) || digitalRead(5) || digitalRead(6) || digitalRead(7) || digitalRead(8) || digitalRead(10)) {
        digitalWrite(13, HIGH);      //on
      } else
        digitalWrite(13, LOW);       //off
    }
  */




#if CUBE_ANDREA == 1
  if (Arduino_User_var[26].value != ramp_step && (Arduino_User_var[26].value >= 0 && Arduino_User_var[26].value < 200)) {
    ramp_step = Arduino_User_var[26].value;

    if (Arduino_User_var[26].value == 0) {
      ramp_enable = false;
      writePWM(ArduinoIO[0], ArduinoIO[0].state);
    } else {
      ramp_enable = true;
    }
  }
#endif


//solo se non si connette e quindi dopo 10 secondi di tentativi va in sleep per non scaricare la batteria
#if SLEEP_MODE == 1
      if(pairing_id >0 && seconds_counter > 10 ) {
        Serial.println(F("Going in sleep mode")); 
        delay(500);
        ESP.deepSleep(SLEEP_WAKEUP_MIN*60e6); 
      }
#endif


#if DEBUG_SERIAL_INTERRUPT == 1
  Serial.print(F("iphone_connected:")); Serial.print(active_iphone_connection); Serial.print(F(" - seconds_counter:")); Serial.print(seconds_counter); Serial.print(F(", seconds_counter_sensors:")); Serial.print(seconds_counter_sensors); Serial.print(F(", push_fail_cnt:")); Serial.print(push_fail_cnt); Serial.print(F(", client_cumulated_fails_cnt:")); Serial.print(client_cumulated_fails_cnt); Serial.print(F(", server_fail_cnt:")); Serial.println(server_fail_cnt);
#endif



}





byte previous1 = LOW;
byte reading1;
void int_Interrupt_Timer_100ms () {

  //switch on/off using button (GPIO0)
#if SONOFF_S20 == 1 || SONOFF_TH10 == 1 || SONOFF_BASIC == 1
  reading1 = digitalRead(0);
  if (reading1 == HIGH && previous1 == LOW && millis() - time1 > 300) {
    toggle(ArduinoIO[json_SearchDigitalPin(sizeof(base_digital_pins_used), ArduinoIO, SONOFF_GPIO_RELAY, OUTPUT)]);
    Serial.println(F("Toggle output"));
    time1 = millis();
  }
  previous1 = reading1;
#endif
}



//////////////////////////////////////
//1 SECOND INTERRUPT DURING EXECUTION
//////////////////////////////////////
void attach_interrupt_timer () {

  //TIMER SETUP
#if ARDUINO_2560MEGA == 1
  Timer1.initialize(1000000);                             //timer set for each second
  Timer1.attachInterrupt(int_Interrupt_Timer_1sec);       //attach the interrupt routine
  //  Timer3.attachInterrupt(int_Interrupt_Timer_1sec);
  //  Timer3.start(1000000); // Calls every 1s
#elif MCU_ESP8266 == 1

  Ticker_1sec.attach_ms(1000, int_Interrupt_Timer_1sec);

#elif MCU_STM32 == 1

  MyTim_runtime_10ms = new HardwareTimer(Instance);
  MyTim_runtime_10ms->setMode(2, TIMER_OUTPUT_COMPARE);  // In our case, channekFalling is configured but not really used. Nevertheless it would be possible to attach a callback to channel compare match.
  MyTim_startup_led_10ms->setOverflow(10000, MICROSEC_FORMAT); //10ms
  //MyTim_runtime_10ms->setOverflow(1, HERTZ_FORMAT); // 10 Hz
  MyTim_runtime_10ms->attachInterrupt(interrupt_timer_isr);
  MyTim_runtime_10ms->resume();
  timer1_count = 0;
  
#endif
}

#if MCU_STM32 == 1
static void interrupt_timer_isr(void) {

#if CUBE_ANDREA == 1
  //Arduino_User_var[26].value = enable ramp
  if (timer1_count % 2 == 0 && ramp_enable) {
    if (ramp_enable)
      int_Interrupt_Timer_pwm_50Hz(ramp_step);    //(%1)100Hz o 10Hz(%10) o 50Hz(%2) o 20Hz(%5)

  }
  int_check_button();
#endif

  if (timer1_count++ == 100) {
    timer1_count = 0;
    int_Interrupt_Timer_1sec();
  }
}

#if CUBE_ANDREA == 1
bool ramp_increase = true;
void int_Interrupt_Timer_pwm_50Hz(byte step_r) {

  if (ramp_increase)
    ramp_pwm = ramp_pwm + step_r;
  else
    ramp_pwm = ramp_pwm - step_r;

  if (ramp_pwm > ramp_max) {
    ramp_increase = false;
    ramp_pwm = ramp_max - 5;
    // Serial.print("ramp_pwm: ");Serial.print(ramp_pwm);Serial.print(", direction: ");Serial.println(ramp_increase);
  } else if (ramp_pwm < (ramp_min + 5)) {
    ramp_increase = true;
    ramp_pwm = ramp_min + 5;
    //  Serial.print("ramp_pwm: ");Serial.print(ramp_pwm);Serial.print(", direction: ");Serial.println(ramp_increase);
  }
  analogWrite(3, ramp_pwm);
}


byte previous1_stm = HIGH;
byte reading1_stm;
int state_button = 0;
void int_check_button () {

  //switch on/off using button (GPIO0)
  reading1_stm = digitalRead(PARAM_MANAGER_TRIGGER_PIN);
  if (reading1_stm == LOW && previous1_stm == HIGH && millis() - time1 > 300) {


    if (state_button == 0) {
      writeDig(ArduinoIO[json_SearchDigitalPin(sizeof(base_digital_pins_used), ArduinoIO, 10, OUTPUT)], HIGH);
      Arduino_User_var[26].value = 0;
      ramp_enable = false;
    }
    else if (state_button >= 1 && state_button < 5) {
      Arduino_User_var[26].value = state_button;
    }
    else if (state_button >= 5) {
      writeDig(ArduinoIO[json_SearchDigitalPin(sizeof(base_digital_pins_used), ArduinoIO, 10, OUTPUT)], LOW);
      state_button = -1;
      Arduino_User_var[26].value = 0;
    }

    state_button = state_button + 1;
    time1 = millis();
  } else if (reading1_stm == LOW && millis() - time1 > 500) {
    Serial.println(F("Preeesss...."));
  }

  previous1_stm = reading1_stm;

}
#endif



#endif


void deattach_interrupt_timer () {

#if ARDUINO_2560MEGA == 1
  Timer1.detachInterrupt();
  //Timer3.detachInterrupt();

#elif MCU_ESP8266 == 1
  Ticker_1sec.detach();

#elif MCU_STM32 == 1
  MyTim_runtime_10ms->detachInterrupt();
#endif
}

//////////////////////////////////////
//100ms SECOND INTERRUPT FOR PIN READ
//////////////////////////////////////
void attach_interrupt_pin_reading_timer () {

  //TIMER SETUP
#if ARDUINO_2560MEGA == 1

#elif MCU_ESP8266 == 1
  Ticker_100ms.attach_ms(100, int_Interrupt_Timer_100ms);
  time1 = millis();

#elif MCU_STM32 == 1

  // DA FARE
#endif
}
void deattach_interrupt_pin_reading_timer () {
#if ARDUINO_2560MEGA == 1
#elif MCU_ESP8266 == 1
  Ticker_100ms.detach();
#elif MCU_STM32 == 1

  // DA FARE
#endif
}





//////////////////////////////////////
//500ms BLINK LED DURING STARTUP
//duration in ms
//////////////////////////////////////
void attach_interrupt_startup_led_timer (int duration) {
#ifdef STARTUP_BLINK_LED_ENABLED
  pinMode(STARTUP_BLINK_LED, OUTPUT);
  //TIMER SETUP
#if ARDUINO_2560MEGA == 1
  Timer1.initialize(duration * 1000);                         //timer set for each second
  Timer1.attachInterrupt(int_Interrupt_Timer_led_1sec);       //attach the interrupt routine
  //  Timer3.attachInterrupt(int_Interrupt_Timer_1sec);
  //  Timer3.start(duration*1000000); // Calls every 1s

#elif MCU_ESP8266 == 1
  Ticker_1sec.attach_ms(duration, int_Interrupt_Timer_led_1sec);
#elif MCU_STM32 == 1


  MyTim_startup_led_10ms = new HardwareTimer(Instance);
  MyTim_startup_led_10ms->setMode(2, TIMER_OUTPUT_COMPARE);  // In our case, channekFalling is configured but not really used. Nevertheless it would be possible to attach a callback to channel compare match.
  MyTim_startup_led_10ms->setOverflow(10000, MICROSEC_FORMAT); // 10ms
  MyTim_startup_led_10ms->attachInterrupt(interrupt_timer_led_isr);
  MyTim_startup_led_10ms->resume();

  timer1_count = 0;

#endif
#endif
}

#if MCU_STM32 == 1
#ifdef STARTUP_BLINK_LED_ENABLED
static void interrupt_timer_led_isr(void) {

  if (timer1_count++ == divider_timer1) {
    timer1_count = 0;
    int_Interrupt_Timer_led_1sec();
  }
}
#endif
#endif

#ifdef STARTUP_BLINK_LED_ENABLED
void int_Interrupt_Timer_led_1sec () {
  digitalWrite(STARTUP_BLINK_LED, blink_led);
  blink_led = !blink_led;
}
#endif


void deattach_interrupt_startup_led_timer () {
#ifdef STARTUP_BLINK_LED_ENABLED
#if ARDUINO_2560MEGA == 1
  Timer1.detachInterrupt();
  //Timer3.detachInterrupt();

#elif MCU_ESP8266 == 1
  Ticker_1sec.detach();

#elif MCU_STM32 == 1
  MyTim_startup_led_10ms->detachInterrupt();
#endif

  if (station_connection_ok)
    writeDig(ArduinoIO[json_SearchDigitalPin(sizeof(base_digital_pins_used), ArduinoIO, STARTUP_BLINK_LED, OUTPUT)], LOW);
  else
    writeDig(ArduinoIO[json_SearchDigitalPin(sizeof(base_digital_pins_used), ArduinoIO, STARTUP_BLINK_LED, OUTPUT)], HIGH);
  store_digital_out_eeprom = false;
#endif
}
