Mode switching implemented

This commit is contained in:
Fenoglio 2018-07-24 18:35:58 +02:00
parent d95ea905f8
commit 55d750c866
2 changed files with 94 additions and 30 deletions

View file

@ -2,6 +2,7 @@
#ifndef speedclock_H #ifndef speedclock_H
#define 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 --------------------------------------------------------- //-------------- defines for the radio devices NRF24 ---------------------------------------------------------
#define STATION_SEL0 9 // this 9 for Nano #define STATION_SEL0 9 // this 9 for Nano
@ -28,6 +29,7 @@ typedef struct transcv_struct{
#define KEY_BOUNCE_MS 50 // the time we use to avoid keybouncing ... #define KEY_BOUNCE_MS 50 // the time we use to avoid keybouncing ...
#define KEY_LONGPRESSED_MS 1000 #define KEY_LONGPRESSED_MS 1000
#define KEY_TOGGLE_MS 500 // the time between to key actions ...
#define BUTTON_NOTPRESSED HIGH #define BUTTON_NOTPRESSED HIGH
#define BUTTON_PRESSED LOW #define BUTTON_PRESSED LOW
#define BUTTON_LONGPRESSED 3 #define BUTTON_LONGPRESSED 3
@ -44,9 +46,10 @@ const uint8_t BUTTONPins[NO_LAST_BUTTON] = {
#define DISPLAY_I2C_ADDRESS 0x3C //Adress of the Display #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_state_e; 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} 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 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 #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 // READY_LED, WARN_LED, RUN_LED, FAIL_LED
@ -60,17 +63,18 @@ const uint8_t LEDPins[NO_LAST_LED] = {
typedef enum {LED_OFF = 0, LED_ON, LED_BLINK } led_state_e; typedef enum {LED_OFF = 0, LED_ON, LED_BLINK } led_state_e;
const uint8_t LEDStates[][NO_LAST_LED] = 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_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_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_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_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_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_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_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_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_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_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_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_MS 100 // 0,001sec is the maximum offset we allow between the current offset and the mean offset. if it is more - restart offset calculation #define MAX_DIFFERENCE_OFFSET_MS 100 // 0,001sec is the maximum offset we allow between the current offset and the mean offset. if it is more - restart offset calculation

View file

@ -17,6 +17,8 @@ RF24 radio(RF24_CNS,RF24_CE);
/**********************************************************/ /**********************************************************/
byte addresses[][12] = {"top_station","basestation"}; // Radio pipe addresses for the 2 nodes to communicate. byte addresses[][12] = {"top_station","basestation"}; // Radio pipe addresses for the 2 nodes to communicate.
unsigned long stats_last_plotted = 0;
unsigned long startloop_ms = 0; unsigned long startloop_ms = 0;
boolean offset_sync_sequence = true; // set to true as the offset sync / calibration is not done - sending data to the basestation is more often as after the sync is done ... boolean offset_sync_sequence = true; // set to true as the offset sync / calibration is not done - sending data to the basestation is more often as after the sync is done ...
@ -28,6 +30,7 @@ uint8_t *leds_states = LEDStates[TIMER_INIT];
boolean time_offset_ok = false; // true as long as the offset is correctly calculated boolean time_offset_ok = false; // true as long as the offset is correctly calculated
uint16_t counter_time_offset = 0; // number of used values for the mean value calculation uint16_t counter_time_offset = 0; // number of used values for the mean value calculation
signed long sum_time_offset = 0; // sum of offset values signed long sum_time_offset = 0; // sum of offset values
signed long current_time_offset = 0; // current offset ...
signed long mean_time_offset = 0; // mean value for the offset signed long mean_time_offset = 0; // mean value for the offset
signed long running_time_offset = 0; // offset that will be used for this run ... signed long running_time_offset = 0; // offset that will be used for this run ...
volatile unsigned long start_time = 0; // if the timer is running this is that start time ... (use volatile for all shared variables that deals with hardware) volatile unsigned long start_time = 0; // if the timer is running this is that start time ... (use volatile for all shared variables that deals with hardware)
@ -54,7 +57,7 @@ timer_state_e timer_state = TIMER_INIT; // current state needs
timer_state_e timer_new_state = TIMER_NOCONNECTION; // next state - in the startup phase the first state - will be TIMER_NOCONNECTION ... checking if a connection to TOPSTATION is established timer_state_e timer_new_state = TIMER_NOCONNECTION; // next state - in the startup phase the first state - will be TIMER_NOCONNECTION ... checking if a connection to TOPSTATION is established
timer_mode_e timer_mode = MODE_COMPETE; // mode of the BASESTATION - this can be changed in IDLE state by pressing the CANCEL button timer_mode_e timer_mode = MODE_COMPETE; // mode of the BASESTATION - this can be changed in IDLE state by pressing the CANCEL button
unsigned long timer_mode_changed_at = 0;
transcv_s radio_data; transcv_s radio_data;
void setup(){ void setup(){
@ -124,6 +127,7 @@ void loop(void) {
} }
// set state to new_state // set state to new_state
/*
if(timer_state != timer_new_state){ if(timer_state != timer_new_state){
Serial.print(millis()); Serial.print(millis());
Serial.print("ms : current state:"); Serial.print("ms : current state:");
@ -131,6 +135,7 @@ void loop(void) {
Serial.print(" new state:"); Serial.print(" new state:");
Serial.println(timer_new_state); Serial.println(timer_new_state);
} }
*/
// update button states ... // update button states ...
update_buttons(); update_buttons();
@ -243,12 +248,18 @@ void loop(void) {
} }
else{ else{
// check if the FALSESTATE button is pressed OR we are in trainingsmode - somebody is ready to run, but STARTBUTTON is NOT pressed ... // check if the FALSESTATE button is pressed OR we are in trainingsmode - somebody is ready to run, but STARTBUTTON is NOT pressed ...
if(((button_state[BUTTON_FAIL] != BUTTON_NOTPRESSED) || (timer_mode == MODE_TRAINING)) && if(((button_state[BUTTON_FAIL] != BUTTON_NOTPRESSED) || (timer_mode != MODE_COMPETE)) &&
(button_state[BUTTON_START] == BUTTON_NOTPRESSED)) (button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED))
{ {
//read again and check if still active ...
if(button_state[BUTTON_FAIL] != BUTTON_NOTPRESSED){
timer_new_state = TIMER_READY; timer_new_state = TIMER_READY;
} else {
if((button_state[BUTTON_STOPCANCEL] == BUTTON_LONGPRESSED) &&
(button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED))
{
// switch to settings mode ...
timer_new_state = TIMER_SETTINGS;
} }
} }
} }
@ -256,7 +267,7 @@ void loop(void) {
break; break;
case TIMER_READY: case TIMER_READY:
if((button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED) && if((button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED) &&
(timer_mode != MODE_TRAINING)) (timer_mode == MODE_COMPETE))
{ {
// false start was released again - go back to IDLE ... so far this is not a false start - run was not started yet // false start was released again - go back to IDLE ... so far this is not a false start - run was not started yet
timer_new_state = TIMER_IDLE; timer_new_state = TIMER_IDLE;
@ -268,13 +279,23 @@ void loop(void) {
startsequence_done = false; startsequence_done = false;
running_time_offset = mean_time_offset; running_time_offset = mean_time_offset;
false_start = false; false_start = false;
attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_FAIL]), false_start_isr, RISING ); if(timer_mode == MODE_COMPETE){
attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_FAIL]), false_start_isr, RISING );
}
Timer1.initialize(); Timer1.initialize();
timer_new_state = TIMER_STARTED; timer_new_state = TIMER_STARTED;
// set the startime - this is the current time plus the length of this sequence // set the startime - this is the current time plus the length of this sequence
start_time = millis() + STARTSEQ_LENGTH_MS; start_time = millis() + STARTSEQ_LENGTH_MS;
// call the start sequence interrupt routine ... // call the start sequence interrupt routine ...
Timer1.attachInterrupt(start_isr,STARTSEQ_PAUSE[startsequence_count]); // startISR to run every given microseconds Timer1.attachInterrupt(start_isr,STARTSEQ_PAUSE[startsequence_count]); // startISR to run every given microseconds
} else {
if((button_state[BUTTON_STOPCANCEL] == BUTTON_LONGPRESSED) &&
(button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED))
{
// switch to settings mode ...
timer_new_state = TIMER_SETTINGS;
}
} }
} }
break; break;
@ -354,16 +375,48 @@ void loop(void) {
timer_new_state = TIMER_IDLE; timer_new_state = TIMER_IDLE;
} }
break; break;
case TIMER_SETTINGS:
// switch between the different modes for now - compete, training and calibration ...
if((button_state[BUTTON_STOPCANCEL] == BUTTON_PRESSED) &&
(button_state[BUTTON_START] == BUTTON_NOTPRESSED))
{
// go back to idle
timer_new_state = TIMER_IDLE;
} else {
if((button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED) &&
(button_state[BUTTON_START] == BUTTON_PRESSED))
{
if((millis() - timer_mode_changed_at) > KEY_TOGGLE_MS){
// switch system mode ...
switch(timer_mode){
case MODE_COMPETE:
timer_mode = MODE_TRAINING;
break;
case MODE_TRAINING:
timer_mode = MODE_CALIBRATION;
break;
case MODE_CALIBRATION:
timer_mode = MODE_COMPETE;
break;
}
timer_mode_changed_at = millis();
}
}
}
break;
} }
} }
//Serial.print("mean_time_offset "); if( (STATS_PLOTS_EVERY_MS > 0) &&
//Serial.println(mean_time_offset); ((millis() -stats_last_plotted) > STATS_PLOTS_EVERY_MS))
//Serial.print("current_time_offset "); {
//Serial.println(current_time_offset); Serial.println("mean_time_offset-current_time_offset & looptime");
//Serial.print("looptime "); Serial.print((signed long)(mean_time_offset - current_time_offset);
//Serial.println(millis()); Serial.print(" ");
Serial.println(millis()- startloop_ms);
stats_last_plotted = millis();
}
} }
//####################### HELPER FUNCTIONS ########################### //####################### HELPER FUNCTIONS ###########################
@ -409,7 +462,6 @@ void update_buttons(void){
} }
void receive_values(void){ void receive_values(void){
signed long current_time_offset = 0; // current offset ...
// wait the connection time out time before receiving data - this is to tell the TOP_STATION to resend offset values in fast mode ... // wait the connection time out time before receiving data - this is to tell the TOP_STATION to resend offset values in fast mode ...
if(keep_connection_off){ if(keep_connection_off){
if((millis() - connection_last_established_at_ms) > (2*CONN_TIMEOUT)){ if((millis() - connection_last_established_at_ms) > (2*CONN_TIMEOUT)){
@ -576,6 +628,11 @@ void update_screen(timer_state_e state){
content = curr_time_local; content = curr_time_local;
footer = "seconds too early"; footer = "seconds too early";
break; break;
case TIMER_SETTINGS:
header = "Settings";
content = timer_mode_string[timer_mode];
footer = "Press Start to toggle.";
break;
default: default:
scr_update = false; scr_update = false;
break; break;
@ -607,6 +664,9 @@ void update_screen(timer_state_e state){
//if print the "Y" //if print the "Y"
display.print("Y"); display.print("Y");
} }
//check which timer_mode we are in
display.setCursor(122,0);
display.print(timer_mode_short[timer_mode]);
display.setCursor(0,1); display.setCursor(0,1);
display.setLetterSpacing(0); display.setLetterSpacing(0);
display.print("----------------------------"); display.print("----------------------------");