
#ifndef speedclock_H
#define speedclock_H

#define STATS_PLOTS_EVERY_MS 1000 // plots statistical values all number of milli seconds .... 0 menas no plot
//-------------- defines for the radio devices NRF24 ---------------------------------------------------------

#define STATION_SEL0 9   // this 9 for Nano
#define STATION_SEL1 10   // this 10 for Nano

typedef enum {BASESTATION = 0, TOPSTATION} radio_type_e;
#define RF24_IRQ 2    // this is 2 for the Nano, ?? for the ESP
#define RF24_CNS 7    // this is 7 for the Nano, D4 for the ESP
#define RF24_CE 8     // this is 8 for the Nano, D3 for the ESP
#define RF24_PA_LEVEL RF24_PA_LOW // sending power level RF24_PA_LOW, RF24_PA_HIGH????

//--------------- defines for the I2C
//#define SCL A5      // I2C clock pin
//#define SDA A4      // I2C data pin

//--------------- define the structure and type of data that sender and receiver will exchange ----------------

typedef struct transcv_struct{
  volatile unsigned long topstationtime_us;                  // the top station sends its time (micros()) continously to the base station
  volatile unsigned long topbuttonpressedtime_us;   // the top station sends the time in millis() when the button was pressed - this is already the calculated time
}transcv_s;

#define MAX_DELAY_BETWEEN_SEND_US 1000000           // this defines the time in micro seconds before the next set of data will be send to the base station - except the button was pressed.
#define MIN_DELAY_BETWEEN_SEND_US   50000           // this defines the time in micro seconds before the next set of data will be send to the base station when the button was pressed or in initsequnce
#define CONN_TIMEOUT_MS 5000                        // if there was no data received from the TOPSTATION for that amount of time - the connection is flagged as lost 

#define KEY_BOUNCE_MS 50                            // the time we use to avoid keybouncing ... 
#define KEY_LONGPRESSED_MS 1000
#define KEY_TOGGLE_MS 500                           // the time between to key actions ... 
#define BUTTON_NOTPRESSED HIGH
#define BUTTON_PRESSED LOW
#define BUTTON_LONGPRESSED 3
typedef enum {BUTTON_STOP = 0, BUTTON_CANCEL, BUTTON_START, BUTTON_FAIL,NO_LAST_BUTTON} button_number_e;
const uint8_t BUTTONPins[NO_LAST_BUTTON] = {
  [BUTTON_STOP]   = 2,                              // stop button input pin 
  [BUTTON_CANCEL]   = 5,                            // cancel button input pin 
  [BUTTON_START]  = 4,                              // start button input pin
  [BUTTON_FAIL]   = 3,                              // stop button input pin
};

#define MIN_DELAY_BETWEEN_PRESSED_US 500000         // this defines the time in microseconds before the button is expected to be pressed again. We do this to avaoid keybouncing

#define PIEZO_PIN 6                                 // piezo speaker

#define DISPLAY_I2C_ADDRESS 0x3C                    //Adress of the Display

typedef enum {TIMER_INIT = 0, TIMER_NOCONNECTION, TIMER_IDLE, TIMER_READY, TIMER_STARTED, TIMER_RUNNING , TIMER_CANCELLED, TIMER_STOPPED, TIMER_TIMEDOUT, TIMER_FAIL, TIMER_WAIT, TIMER_SETTINGS} timer_state_e;
typedef enum {MODE_COMPETE = 0, MODE_TRAINING, MODE_CALIBRATION, NO_LAST_MODE} timer_mode_e;  // compete - full mode with false start detector, training - no false start detection, calibration - parellel wired connection between top and base to kalibrate the offset calculation of the wireless connection
const char timer_mode_short[NO_LAST_MODE] = {[MODE_COMPETE]='F',[MODE_TRAINING]='T',[MODE_CALIBRATION]='C'};
const String timer_mode_string[NO_LAST_MODE] = {[MODE_COMPETE]="Competetion",[MODE_TRAINING]="  Training  ",[MODE_CALIBRATION]="Calibration"};
#define LED_BLINK_ALL_MS 500                        // LED set to BLINK will change there state every number of milli seconds specified here

// READY_LED, WARN_LED, RUN_LED, FAIL_LED
typedef enum {READY_LED = 0, RUN_LED, FAIL_LED, WARN_LED ,NO_LAST_LED} led_number_e; // leave NO_LAST_LED as last element - its our marker ...
const uint8_t LEDPins[NO_LAST_LED] = {
  [READY_LED]           =A2,                        // green ready LED
  [RUN_LED]             =A0,                        // blue run LED
  [FAIL_LED]            =A3,                        // red fail LED
  [WARN_LED]            =A1                         // yellow warn LED
}; 
typedef enum {LED_OFF = 0, LED_ON, LED_BLINK } led_state_e;
const uint8_t LEDStates[][NO_LAST_LED] =
{
  [TIMER_INIT]          = {[READY_LED]=LED_OFF,   [RUN_LED]=LED_OFF,    [FAIL_LED]=LED_BLINK ,[WARN_LED]=LED_OFF},        // 0
  [TIMER_NOCONNECTION]  = {[READY_LED]=LED_OFF,   [RUN_LED]=LED_OFF,    [FAIL_LED]=LED_ON,    [WARN_LED]=LED_OFF},        // 1
  [TIMER_IDLE]          = {[READY_LED]=LED_ON,    [RUN_LED]=LED_OFF,    [FAIL_LED]=LED_OFF,   [WARN_LED]=LED_OFF},        // 2
  [TIMER_READY]         = {[READY_LED]=LED_BLINK, [RUN_LED]=LED_OFF,    [FAIL_LED]=LED_OFF,   [WARN_LED]=LED_OFF},        // 3
  [TIMER_STARTED]       = {[READY_LED]=LED_ON,    [RUN_LED]=LED_ON,     [FAIL_LED]=LED_OFF,   [WARN_LED]=LED_OFF},        // 4
  [TIMER_RUNNING]       = {[READY_LED]=LED_OFF,   [RUN_LED]=LED_ON,     [FAIL_LED]=LED_OFF,   [WARN_LED]=LED_OFF},        // 5
  [TIMER_CANCELLED]     = {[READY_LED]=LED_OFF,   [RUN_LED]=LED_OFF,    [FAIL_LED]=LED_ON,    [WARN_LED]=LED_OFF},        // 6
  [TIMER_STOPPED]       = {[READY_LED]=LED_ON,    [RUN_LED]=LED_ON,     [FAIL_LED]=LED_OFF,   [WARN_LED]=LED_OFF},        // 7
  [TIMER_TIMEDOUT]      = {[READY_LED]=LED_OFF,   [RUN_LED]=LED_ON,     [FAIL_LED]=LED_ON,    [WARN_LED]=LED_OFF},        // 8
  [TIMER_FAIL]          = {[READY_LED]=LED_OFF,   [RUN_LED]=LED_BLINK,  [FAIL_LED]=LED_ON,    [WARN_LED]=LED_OFF},        // 9
  [TIMER_WAIT]          = {[READY_LED]=LED_ON,    [RUN_LED]=LED_ON,     [FAIL_LED]=LED_ON,    [WARN_LED]=LED_ON},         // 10
  [TIMER_SETTINGS]      = {[READY_LED]=LED_OFF,   [RUN_LED]=LED_OFF,    [FAIL_LED]=LED_OFF,   [WARN_LED]=LED_ON}          // 11
};

#define MAX_DIFFERENCE_OFFSET_US 100000       // 0,001sec is the maximum offset we allow between the current offset and the mean offset. if it is more - restart offset calculation
#define REQUIRED_NUMBER_MEANVALS 1        // we need at least this number of meanvalues to be ready to start a run
#define MAX_ALLOWED_FAILED_OFFSETS 10       // if more than this number of offsets are out of the specified MAX_DIFFERENCE_OFFSET_MS value, offset calcultion will be restarted 

#define STARTSEQ_STEPS 4
const uint8_t   STARTSEQ_NOTES[]    = {0,392,392,1047};                             // tone frequence
const uint16_t  STARTSEQ_DURATION_MS[] = {0,200,200,100};                           // tone duration in milliseconds
const unsigned long  STARTSEQ_PAUSE_US[]    = {1000000,1000000,1000000,100000};     // pause between tones in microseconds
#define STARTSEQ_LENGTH_US 3100000                                                  // the length of the start sequence from the time the button was pressed ... includes the 3 tones

#define FAILSEQ_STEPS 2
const uint8_t FAILSEQ_NOTES[]    = {49,49};                                         // tone frequence
const uint16_t  FAILSEQ_DURATION_MS[] = {300,300};                                  // tone duration in milliseconds
const unsigned long  FAILSEQ_PAUSE_US[]    = {400000,400000};                       // pause between tones in microseconds

#define TIMER_MAX_TIME_US 99999999
#define TIMER_TIMEOUT_US 20000000

//--------------------------------------- function declarations ----------------------------------------------
void update_offset_values(void);
void false_start_isr(void);
void update_screen(timer_state_e state);
void set_state_LEDs(timer_state_e state, boolean warn);
void startSequence(void);
void update_statemessage(timer_state_e timer_state);
void failSequence(void);
void wait(unsigned long ms);
void start_isr(void);
void update_buttons(void);
void send_values(void);
void stop_isr(void);
String micros2string(signed long microsecs);
void nrf24_isr(void);
void handle_connection(void);
signed long calc_mean_offset(signed long current_toptime);
#endif
