// Concepto: mide la tensión de bobinado constantemente y acciona el servo para aumentar o disminuír
// la tensión usando un control PID.
//
// Un botón (latch) determina si el control de tensión está activado. Si no, se mide la tensión, pero no se activa el servo para corregirla.
// Si la tensión está dentro del rango establecido como seguro, el LED tensión se mantiene encendido continuamente.
// Si la tensión está fuera de ese rango, el LED tensión titila cada vez con menos frecuencia a medida que se aleja del valor central.
// Lee la tensión de alimentación del Arduino.
// Avisa encendiendo un LED cuándo cae por debajo de un valor umbral.
// La ideal para 4 pilas recarganles es de 4,8 V (y se supone que se mantiene mucho tiempo así).
// Si cae por debajo de 4,4, el LED comienza a titilar, 1 vez cada tantos segundos como decimales haya:
// 4,4 V: 1 vez cada 4 segundos.
// 4,3 V: 1 vez cada 3 segundos.
// 4,2 V: 1 vez cada 2 segundos.
// 4,1 V: 1 vez cada 1 segundo.
// Por debajo de 4 V, se mantiene encendido.
// Si el switch del bluetooth está activado, envía los valores de tensión con una frecuenia determinada.
// Made by Juan 03/2025
#include <arduino-timer.h>
// https://deepbluembedded.com/arduino-timer-library/#google_vignette
// https://github.com/contrem/arduino-timer
#include "HX711.h"
// https://github.com/RobTillaart/HX711
HX711 scale;
Timer<1, millis> TimnerManageBatteryVoltage;
Timer<2, millis> TimerLowBatteryLED;           // 2 concurrent tasks, one to turn the LED on and the other to turn it off.
Timer<2, millis> TimerTensionLED;
Timer<1, millis> TimerBTSendData;              // 1 concurrent task, using millis as resolution.
// Global variables - Stert
float measured_tension = 0;
constexpr float target_tension = 1;               // Determined by a calibration.
constexpr float tension_safe_range_width = 0.1;   // Determined by a calibration.
long manage_battery_voltaje_delay = 600000L;        // Check every 10 minutes.
long low_battery_LED_delay = 1000L;        // Send data every ... ms.
long tension_LED_delay = 1000L;            // Send data every ... ms.
constexpr int BT_sendData_delay = 1000;            // Send data every ... ms.
constexpr int LED_blink_on_duration = 100;            // Amount of time the LED stays on (in ms).
constexpr byte low_battery_LED_pin = 2;
constexpr byte tension_LED_pin = 3;
constexpr byte active_tension_pin = 4;
constexpr byte active_BT_pin = 5;
constexpr byte LOADCELL_DOUT_PIN = A0;
constexpr byte LOADCELL_SCK_PIN = A1;
bool low_battery_LED_state = false;
bool isTimerLowBatteryLEDRunning = false;
bool tension_LED_state = false;
//bool active_tension_state = 0;
//bool active_BT_state = 0;
// Global variables - End
void setup() {
  pinMode(low_battery_LED_pin, OUTPUT);
  pinMode(tension_LED_pin, OUTPUT);
  pinMode(active_tension_pin, OUTPUT);
  pinMode(active_BT_pin, OUTPUT);
  TimnerManageBatteryVoltage.in(1, Manage_Battery_Voltage);  // Check the battery level when the program starts.
  TimerLowBatteryLED.every(low_battery_LED_delay, Blink_Low_Battery_LED);
  TimerTensionLED.every(tension_LED_delay, Set_tension_LED);
  TimerBTSendData.every(BT_sendData_delay, BT_send_data);
  
  scale.begin(dataPin, clockPin);
  scale.set_scale(0.420);           //  load cell factor (comes from calibration)
  scale.tare();                     //  reset the scale to zero = 0
}
void loop() {
  TimnerManageBatteryVoltage.tick();
  TimerLowBatteryLED.tick();
  TimerTensionLED.tick();
  TimerBTSendData.tick();
}
bool Set_tension_LED(void *)
// en proceso....
{
  if (low_battery_LED_state) {
    digitalWrite(tension_LED_pin, LOW);
  } else {
    digitalWrite(tension_LED_pin, HIGH);
  }
  return true;       // true: repeat the action, false: to stop the task.
}
bool BT_send_data(void *)
// en proceso....
{
  return true;       // true: repeat the action, false: to stop the task.
}
bool Manage_Battery_Voltage(void *)
// Measures the battery voltage and resets the TimerLowBatteryLED (so it will always show the latest data).
{
  TimerLowBatteryLED.cancel();              // Cancel all tasks in TimerLowBatteryLED.
  TimnerManageBatteryVoltage.cancel();      // Cancel all tasks in TimnerManageBatteryVoltage.
  int Vcc = getVcc();
  if (Vcc <= 4450) {                                // Low battery level:
    manage_battery_voltaje_delay = 60000L;          // Check every minute.
    if (Vcc > 4350) low_battery_LED_delay = 4000;
    else if (Vcc <= 4350 && Vcc > 4250) low_battery_LED_delay = 3000;
    else if (Vcc <= 4250 && Vcc > 4150) low_battery_LED_delay = 2000;
    else if (Vcc <= 4150 && Vcc > 4000) low_battery_LED_delay = 1000;
    else low_battery_LED_delay = 2.5 * LED_blink_on_duration;
    TimerLowBatteryLED.every(low_battery_LED_delay, Blink_Low_Battery_LED);         // Only sets low_battery_LED if Vcc <= 4450.
  } else manage_battery_voltaje_delay = 600000L;        // Check every 10 minutes.
  TimnerManageBatteryVoltage.every(manage_battery_voltaje_delay, Manage_Battery_Voltage);  // Read battery voltage every 10 minutes and set the blinking frecuency.
  return true;       // true: repeat the action, false: to stop the task.
}
bool Blink_Low_Battery_LED(void *)
{
  digitalWrite(low_battery_LED_pin, HIGH);
  TimerLowBatteryLED.in(LED_blink_on_duration, Turn_off_Low_Battery_LED);
  return true;       // true: repeat the action, false: to stop the task.
}
bool Turn_off_Low_Battery_LED(void *)
{
  digitalWrite(low_battery_LED_pin, LOW);
  return false;       // true: repeat the action, false: to stop the task.
}
int getVcc()
// Returns the Vcc voltage (in mV).
{
  constexpr long InternalReferenceVoltage = 1056L;  // Adjust this value to your boards specific internal BG voltage in mV.
  #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
    // For mega boards
      // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc reference
      // MUX4 MUX3 MUX2 MUX1 MUX0  --> 11110 1.1V (VBG)         -Selects channel 30, bandgap voltage, to measure
    ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR)| (0<<MUX5) | (1<<MUX4) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);
  #else
    // For 168/328 boards
      // REFS1 REFS0          --> 0 1, AVcc internal ref. -Selects AVcc external reference
      // MUX3 MUX2 MUX1 MUX0  --> 1110 1.1V (VBG)         -Selects channel 14, bandgap voltage, to measure
    ADMUX = (0<<REFS1) | (1<<REFS0) | (0<<ADLAR) | (1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (0<<MUX0);    
  #endif
  delay(50);  // Let mux settle a little to get a more stable A/D conversion
    // Start a conversion  
  ADCSRA |= _BV( ADSC );
    // Wait for it to complete
  while( ( (ADCSRA & (1<<ADSC)) != 0 ) );
  int result = ((InternalReferenceVoltage * 1024L) / ADC) + 5L; // calculates for straight line value.
  return result;
}