Modfied Init step and added NoConnection state
This commit is contained in:
parent
6989862dc4
commit
d7a1c92a47
2 changed files with 149 additions and 96 deletions
29
speedclock.h
29
speedclock.h
|
@ -1,6 +1,6 @@
|
|||
|
||||
#ifndef Remote_Control_transceiver_H
|
||||
#define Remote_Control_transceiver_H
|
||||
#ifndef speedclock_H
|
||||
#define speedclock_H
|
||||
|
||||
//-------------- defines for the radio devices NRF24 ---------------------------------------------------------
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
|||
typedef enum {BASESTATION = 0, TOPSTATION} radio_type_e;
|
||||
#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, ????
|
||||
|
||||
//--------------- defines for the I2C
|
||||
//#define SCL A5 // I2C clock pin
|
||||
|
@ -27,7 +28,7 @@ typedef struct transcv_struct{
|
|||
#define STOPBUTTON_PRESSED LOW // this the signal level the top button will be at as soon as pressed
|
||||
#define MIN_DELAY_BETWEEN_PRESSED_MS 1000 // this defines the time in milliseconds before the button is expected to be pressed again. We do this to avaoid keybouncing
|
||||
#define MIN_DELAY_BETWEEN_SEND_MS 1000 // this defines the time in milliseconds before the next set of data will be send to the base station - except the button was pressed.
|
||||
#define CONN_TIMEOUT 10000
|
||||
#define CONN_TIMEOUT 10000 // if there was no data received from the TOPSTATION for that amount of time - the connection is flagged as lost
|
||||
|
||||
#define STARTBUTTON_IN 4 // start button
|
||||
#define STARTBUTTON_PRESSED LOW
|
||||
|
@ -53,20 +54,22 @@ typedef struct transcv_struct{
|
|||
|
||||
#define DISPLAY_I2C_ADDRESS 0x3C //Adress of the Display
|
||||
|
||||
typedef enum {TIMER_INIT = 0, 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_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
|
||||
|
||||
// READY_LED, WARN_LED, RUN_LED, FAIL_LED
|
||||
const float LEDStates[][3] =
|
||||
{
|
||||
[TIMER_INIT] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_OFF},
|
||||
[TIMER_IDLE] = {READY_LED_ON, RUN_LED_OFF, FAIL_LED_OFF},
|
||||
[TIMER_READY] = {READY_LED_ON, RUN_LED_OFF, FAIL_LED_OFF},
|
||||
[TIMER_STARTED] = {READY_LED_ON, RUN_LED_ON, FAIL_LED_OFF},
|
||||
[TIMER_RUNNING] = {READY_LED_OFF, RUN_LED_ON, FAIL_LED_OFF},
|
||||
[TIMER_CANCELLED] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON},
|
||||
[TIMER_STOPPED] = {READY_LED_ON, RUN_LED_ON, FAIL_LED_OFF},
|
||||
[TIMER_TIMEDOUT] = {READY_LED_OFF, RUN_LED_ON, FAIL_LED_ON},
|
||||
[TIMER_FAIL] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON}
|
||||
[TIMER_INIT] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_OFF},
|
||||
[TIMER_NOCONNECTION] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON},
|
||||
[TIMER_IDLE] = {READY_LED_ON, RUN_LED_OFF, FAIL_LED_OFF},
|
||||
[TIMER_READY] = {READY_LED_ON, RUN_LED_OFF, FAIL_LED_OFF},
|
||||
[TIMER_STARTED] = {READY_LED_ON, RUN_LED_ON, FAIL_LED_OFF},
|
||||
[TIMER_RUNNING] = {READY_LED_OFF, RUN_LED_ON, FAIL_LED_OFF},
|
||||
[TIMER_CANCELLED] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON},
|
||||
[TIMER_STOPPED] = {READY_LED_ON, RUN_LED_ON, FAIL_LED_OFF},
|
||||
[TIMER_TIMEDOUT] = {READY_LED_OFF, RUN_LED_ON, FAIL_LED_ON},
|
||||
[TIMER_FAIL] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON}
|
||||
};
|
||||
|
||||
#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
|
||||
|
|
208
speedclock.ino
208
speedclock.ino
|
@ -1,5 +1,5 @@
|
|||
#include <Arduino.h>
|
||||
#include <U8g2lib.h>
|
||||
//#include <U8g2lib.h>
|
||||
//#include "fonts.h"
|
||||
#include <Wire.h>
|
||||
#include "SSD1306Ascii.h"
|
||||
|
@ -30,15 +30,16 @@ unsigned long runner_start_time = 0; // this is the time the runner lef
|
|||
signed long runner_run_time = 0; // this is the time the runner really needed or the time started to early - depending on sign ...
|
||||
unsigned long run_time = 0; // if the timer is running this is that start time ...
|
||||
boolean warn_during_run = false; // will be set to true if there is a warning during the run - usually an offset sync error
|
||||
unsigned long connection_established = 0; // time the last active connection was established
|
||||
unsigned long connection_last_established_at_ms = 0; // time the last active connection was established
|
||||
boolean connection_available = false; // if there were no data for longer then CONN_TIMEOUT the connection will be flaged as lost ...
|
||||
uint8_t failed_offsets = MAX_ALLOWED_FAILED_OFFSETS; // number of offset values that did not fullfill the MAX_DIFFERENCE_OFFSET_MS criterion
|
||||
|
||||
boolean topbuttonwaspressed = false;
|
||||
|
||||
timer_state_e timer_state = TIMER_IDLE; // current state needs to be initialized to somethin different then new_state due to the fact that some pieces of the code check for differnt values of state and _new_state to detect an update...
|
||||
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_state = TIMER_WAIT; // timer needs to be initialized ...
|
||||
timer_state_e timer_new_state = TIMER_INIT; // timer needs to be initialized ...
|
||||
|
||||
timer_mode_e timer_mode = MODE_COMPETE; // mode of the BASESTATION - this can be changed in IDLE state by pressing the CANCEL button
|
||||
|
||||
transcv_s radio_data;
|
||||
|
||||
|
@ -84,6 +85,8 @@ void setup(){
|
|||
radio.begin();
|
||||
radio.setRetries(15, 15); //the first is the time between reties in multiple of 250ms, the second is the numer of attempts
|
||||
if(stationNumber == TOPSTATION){
|
||||
// Set the PA Level of the sendin TOP_STATION
|
||||
radio.setPALevel(RF24_PA_LEVEL);
|
||||
radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, but opposite addresses
|
||||
radio.openReadingPipe(1,addresses[0]); // Open a reading pipe on address 0, pipe 1
|
||||
radio.stopListening(); // top station will never receive data.
|
||||
|
@ -92,14 +95,12 @@ void setup(){
|
|||
radio.openReadingPipe(1,addresses[1]);
|
||||
radio.startListening();
|
||||
}
|
||||
|
||||
radio_data.topstationtime = millis(); // set the current milli second count
|
||||
radio_data.topbuttonpressedtime = 0; // set the time the button was pressed last time to 0
|
||||
|
||||
//initialise Wire and OLED
|
||||
Wire.begin();
|
||||
Wire.setClock(400000L);
|
||||
|
||||
display.begin(&Adafruit128x64, DISPLAY_I2C_ADDRESS);
|
||||
display.clear();
|
||||
}
|
||||
|
@ -172,55 +173,79 @@ void loop(void) {
|
|||
// receive data from top_station, calculate offset and set 'last connection' time stamp
|
||||
receive_values();
|
||||
|
||||
// set state to new_state
|
||||
if(timer_state != timer_new_state){
|
||||
update_statemessage(timer_new_state);
|
||||
}
|
||||
// show state debug outputs at serial monitor
|
||||
update_statemessage(timer_new_state);
|
||||
|
||||
// update the OLED screen
|
||||
update_screen(timer_new_state);
|
||||
|
||||
// set state to new_state
|
||||
timer_state = timer_new_state;
|
||||
|
||||
// set LEDs
|
||||
set_state_LEDs(timer_state, warn_during_run );
|
||||
|
||||
switch(timer_state){
|
||||
case TIMER_INIT:
|
||||
// check if we are ready ...
|
||||
if(counter_time_offset > REQUIRED_NUMBER_MEANVALS){
|
||||
// check if offset is OK - if not .. set state back to INIT
|
||||
timer_new_state = TIMER_IDLE;
|
||||
}
|
||||
break;
|
||||
case TIMER_IDLE:
|
||||
warn_during_run = false;
|
||||
if(counter_time_offset < REQUIRED_NUMBER_MEANVALS){
|
||||
// check if offset is OK - if not .. set state back to INIT
|
||||
case TIMER_NOCONNECTION:
|
||||
// as long as there is no connection to TOP_STATION we will end up here
|
||||
if(connection_available == true){
|
||||
timer_new_state = TIMER_INIT;
|
||||
}
|
||||
case TIMER_INIT:
|
||||
// init the system offset ...
|
||||
if(connection_available == false){
|
||||
// if the connection was lost ... switch to noconnection state
|
||||
timer_new_state = TIMER_NOCONNECTION;
|
||||
}
|
||||
else{
|
||||
// check if the FALSESTATE button is pressed - somebody is ready to run ...
|
||||
if(digitalRead(FAILSTARTBUTTON_IN) == FAILSTARTBUTTON_PRESSED){
|
||||
//wait a few milliseconds to prevent keybouncing - this is a very simplistic method here
|
||||
delay(10);
|
||||
//read again and check if still active ...
|
||||
// if the offset is claculated switch to IDLE mode ...
|
||||
if(counter_time_offset > REQUIRED_NUMBER_MEANVALS){
|
||||
// check if offset is OK - if not .. set state back to INIT
|
||||
timer_new_state = TIMER_IDLE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TIMER_IDLE:
|
||||
warn_during_run = false;
|
||||
if(connection_available == false){
|
||||
// if the connection was lost ... switch to noconnection state
|
||||
timer_new_state = TIMER_NOCONNECTION;
|
||||
}
|
||||
else{
|
||||
if(counter_time_offset < REQUIRED_NUMBER_MEANVALS){
|
||||
// check if offset is OK - if not .. set state back to INIT
|
||||
timer_new_state = TIMER_INIT;
|
||||
}
|
||||
else{
|
||||
// check if the FALSESTATE button is pressed - somebody is ready to run ...
|
||||
if(digitalRead(FAILSTARTBUTTON_IN) == FAILSTARTBUTTON_PRESSED){
|
||||
timer_new_state = TIMER_READY;
|
||||
//wait a few milliseconds to prevent keybouncing - this is a very simplistic method here
|
||||
delay(10);
|
||||
//read again and check if still active ...
|
||||
if(digitalRead(FAILSTARTBUTTON_IN) == FAILSTARTBUTTON_PRESSED){
|
||||
timer_new_state = TIMER_READY;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TIMER_READY:
|
||||
if(digitalRead(FAILSTARTBUTTON_IN) == FAILSTARTBUTTON_PRESSED){
|
||||
// check if the start button was pressed ... there is at least still someone waiting for the run .
|
||||
if(digitalRead(STARTBUTTON_IN) == STARTBUTTON_PRESSED){
|
||||
// now enable the interrupt for the FALSESTART button
|
||||
attachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN), false_start_isr, CHANGE);
|
||||
timer_new_state = TIMER_STARTED;
|
||||
}
|
||||
if(connection_available == false){
|
||||
// if the connection was lost ... switch to noconnection state
|
||||
timer_new_state = TIMER_NOCONNECTION;
|
||||
}
|
||||
else{
|
||||
timer_new_state = TIMER_IDLE;
|
||||
if(digitalRead(FAILSTARTBUTTON_IN) == FAILSTARTBUTTON_PRESSED){
|
||||
// check if the start button was pressed ... there is at least still someone waiting for the run .
|
||||
if(digitalRead(STARTBUTTON_IN) == STARTBUTTON_PRESSED){
|
||||
// now enable the interrupt for the FALSESTART button
|
||||
attachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN), false_start_isr, CHANGE);
|
||||
timer_new_state = TIMER_STARTED;
|
||||
}
|
||||
}
|
||||
else{
|
||||
timer_new_state = TIMER_IDLE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TIMER_STARTED:
|
||||
|
@ -299,14 +324,14 @@ void loop(void) {
|
|||
|
||||
//####################### HELPER FUNCTIONS ###########################
|
||||
void receive_values(void){
|
||||
byte pipeNo;
|
||||
// check if radio data is available - if so read the data
|
||||
if( radio.available()){
|
||||
while( radio.available(&pipeNo)){ // Read all available payloads
|
||||
// read data from TOP_STATION ...
|
||||
connection_established = millis();
|
||||
// read data from TOP_STATION ...
|
||||
while( radio.available()){ // Read all available payloads
|
||||
radio.read( &radio_data, sizeof(radio_data) ); // Read the data the TOPSTATION sent
|
||||
}
|
||||
connection_last_established_at_ms = millis();
|
||||
connection_available = true;
|
||||
current_time_offset = radio_data.topstationtime - millis(); // the offset between TOP_STATION and BASESTATION
|
||||
Serial.print("Current time on host in millis:");
|
||||
Serial.print(millis());
|
||||
|
@ -326,6 +351,7 @@ void receive_values(void){
|
|||
if(abs(current_time_offset - mean_time_offset) < MAX_DIFFERENCE_OFFSET_MS){
|
||||
// if the current value is in range - decrease the fail counter by 1 if it was not zero already
|
||||
if(failed_offsets > 0){
|
||||
Serial.println("INFO: The last received TOPSTATION offset time stamp was again in range. Decrease internal fail counter");
|
||||
failed_offsets--;
|
||||
}
|
||||
// the offset is in range - check if we have already enough values of if we need to add more ...
|
||||
|
@ -345,11 +371,12 @@ void receive_values(void){
|
|||
// the current offset is out of range ...
|
||||
// if the values before also already failed the criterion but the max allowed number of such fails is not reached ... just increase the counter.
|
||||
if(failed_offsets < MAX_ALLOWED_FAILED_OFFSETS){
|
||||
Serial.println("WARNING: The last received TOPSTATION offset time stamp was out of range. Increase internal fail counter");
|
||||
failed_offsets++;
|
||||
}
|
||||
else{
|
||||
// if the values before also already failed the criterion AND the max allowed number of such fails is reached ... we need to restart the mean calculation and set the timer to unready state ...
|
||||
Serial.print(F("TopStation BaseStation are out off sync. Offset calculation will be restarted. Last "));
|
||||
Serial.print(F("ERROR: TopStation and BaseStation are out off sync. Offset calculation will be restarted. Last "));
|
||||
Serial.print(MAX_ALLOWED_FAILED_OFFSETS);
|
||||
//offset "));
|
||||
Serial.print(current_time_offset);
|
||||
|
@ -363,45 +390,63 @@ void receive_values(void){
|
|||
sum_time_offset = 0;
|
||||
mean_time_offset = 0;
|
||||
failed_offsets = 0;
|
||||
}
|
||||
}
|
||||
} // out of range counter exceeds maximum value
|
||||
} // time offset of TOPSTATION out of range
|
||||
}
|
||||
}
|
||||
else{
|
||||
// remove the RF24 connection flag if no data was received for longer time
|
||||
if(millis() - connection_last_established_at_ms >= CONN_TIMEOUT || connection_last_established_at_ms == 0){
|
||||
connection_available = false;
|
||||
Serial.println("ERROR: No connection established to TOPSTATION");
|
||||
}
|
||||
else{
|
||||
Serial.println("No data from TOP_STATION avaialble - OR the connection couldn't be established");
|
||||
}
|
||||
} // radio available
|
||||
|
||||
void update_statemessage(timer_state_e timer_state){
|
||||
switch(timer_state){
|
||||
case TIMER_INIT:
|
||||
Serial.println("*** TIMER_INIT ***");
|
||||
break;
|
||||
case TIMER_IDLE:
|
||||
Serial.println("*** TIMER_IDLE ***");
|
||||
break;
|
||||
case TIMER_READY:
|
||||
Serial.println("*** TIMER_READY ***");
|
||||
break;
|
||||
case TIMER_STARTED:
|
||||
Serial.println("*** TIMER_STARTED ***");
|
||||
break;
|
||||
case TIMER_RUNNING:
|
||||
Serial.println("*** TIMER_RUNNING ***");
|
||||
break;
|
||||
case TIMER_CANCELLED:
|
||||
Serial.println("*** TIMER_CANCELLED ***");
|
||||
break;
|
||||
case TIMER_STOPPED:
|
||||
Serial.println("*** TIMER_STOPPED ***");
|
||||
break;
|
||||
case TIMER_TIMEDOUT:
|
||||
Serial.println("*** TIMER_TIMEDOUT ***");
|
||||
break;
|
||||
case TIMER_FAIL:
|
||||
Serial.println("*** TIMER_FAIL ***");
|
||||
break;
|
||||
case TIMER_WAIT:
|
||||
Serial.println("*** TIMER_WAIT ***");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}// receive values
|
||||
|
||||
void update_statemessage(timer_state_e state){
|
||||
//check if the state has changed ... only show the message below (of the given state) in this case ...
|
||||
if(timer_state != timer_new_state){
|
||||
switch(state){
|
||||
case TIMER_NOCONNECTION:
|
||||
Serial.println("*** TIMER_NOCONNECTION ***");
|
||||
break;
|
||||
case TIMER_INIT:
|
||||
Serial.println("*** TIMER_INIT ***");
|
||||
break;
|
||||
case TIMER_IDLE:
|
||||
Serial.println("*** TIMER_IDLE ***");
|
||||
break;
|
||||
case TIMER_READY:
|
||||
Serial.println("*** TIMER_READY ***");
|
||||
break;
|
||||
case TIMER_STARTED:
|
||||
Serial.println("*** TIMER_STARTED ***");
|
||||
break;
|
||||
case TIMER_RUNNING:
|
||||
Serial.println("*** TIMER_RUNNING ***");
|
||||
break;
|
||||
case TIMER_CANCELLED:
|
||||
Serial.println("*** TIMER_CANCELLED ***");
|
||||
break;
|
||||
case TIMER_STOPPED:
|
||||
Serial.println("*** TIMER_STOPPED ***");
|
||||
break;
|
||||
case TIMER_TIMEDOUT:
|
||||
Serial.println("*** TIMER_TIMEDOUT ***");
|
||||
break;
|
||||
case TIMER_FAIL:
|
||||
Serial.println("*** TIMER_FAIL ***");
|
||||
break;
|
||||
case TIMER_WAIT:
|
||||
Serial.println("*** TIMER_WAIT ***");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -419,6 +464,11 @@ void update_screen(timer_state_e state){
|
|||
float curr_time_local = 0.0;
|
||||
|
||||
switch(state){
|
||||
case TIMER_NOCONNECTION:
|
||||
header = "No connection";
|
||||
content = "Waiting..";
|
||||
footer = "Waiting for TOPSTATION";
|
||||
break;
|
||||
case TIMER_INIT:
|
||||
header = "Init";
|
||||
content = "...";
|
||||
|
@ -499,7 +549,7 @@ void update_screen(timer_state_e state){
|
|||
display.print(header_to_char);
|
||||
display.setCursor(1,0);
|
||||
//check if there is a connection to the topstation
|
||||
if(millis() - connection_established >= CONN_TIMEOUT || connection_established == 0){
|
||||
if(connection_available != true){
|
||||
//if not remove the "Y"
|
||||
display.print(" ");
|
||||
}
|
||||
|
|
Reference in a new issue