Mode switching implemented
This commit is contained in:
parent
d95ea905f8
commit
55d750c866
2 changed files with 94 additions and 30 deletions
32
speedclock.h
32
speedclock.h
|
@ -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
|
||||||
|
|
|
@ -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("----------------------------");
|
||||||
|
|
Reference in a new issue