Agian a version that works for me .
Fixed a lot of bugs ...
This commit is contained in:
parent
b84b19b740
commit
46319a972a
2 changed files with 352 additions and 208 deletions
59
speedclock.h
59
speedclock.h
|
@ -10,7 +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, ????
|
||||
#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
|
||||
|
@ -24,7 +24,7 @@ typedef struct transcv_struct{
|
|||
}transcv_s;
|
||||
|
||||
#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 // if there was no data received from the TOPSTATION for that amount of time - the connection is flagged as lost
|
||||
#define CONN_TIMEOUT 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 10 // the time we use to avoid keybouncing ...
|
||||
|
||||
|
@ -41,42 +41,42 @@ typedef struct transcv_struct{
|
|||
|
||||
#define PIEZO_PIN 6 // piezo speaker
|
||||
|
||||
#define WARN_LED A1 // yellow warn LED
|
||||
#define WARN_LED_ON HIGH
|
||||
#define WARN_LED_OFF LOW
|
||||
#define FAIL_LED A3 // red fail LED
|
||||
#define FAIL_LED_ON HIGH
|
||||
#define FAIL_LED_OFF LOW
|
||||
#define READY_LED A2 // green ready LED
|
||||
#define READY_LED_ON HIGH
|
||||
#define READY_LED_OFF LOW
|
||||
#define RUN_LED A0 // blue run LED
|
||||
#define RUN_LED_ON HIGH
|
||||
#define RUN_LED_OFF LOW
|
||||
|
||||
|
||||
#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 {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
|
||||
|
||||
#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
|
||||
const float LEDStates[][3] =
|
||||
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_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}
|
||||
[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
|
||||
};
|
||||
|
||||
#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 REQUIRED_NUMBER_MEANVALS 100 // we need at least this number of meanvalues to be ready to start a run
|
||||
#define MAX_ALLOWED_FAILED_OFFSETS 3 // if more than this number of offsets are out of the specified MAX_DIFFERENCE_OFFSET_MS value, offset calcultion will be restarted
|
||||
#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
|
||||
|
@ -84,9 +84,10 @@ const uint16_t STARTSEQ_DURATION[] = {0,200,200,100}; // tone duration i
|
|||
const unsigned long STARTSEQ_PAUSE[] = {1000000,1000000,1000000,100000}; // pause between tones in microseconds
|
||||
#define STARTSEQ_LENGTH_MS 3100 // the length of the start sequence from the time the button was pressed ... includes the 3 tones
|
||||
|
||||
#define FAILSEQ_TONEPAUSE_MS 400
|
||||
#define FAILSEQ_TON_LENGTH_MS 300
|
||||
#define FAILSEQ_TON_FREQUENCY 49 //NOTE_G1
|
||||
#define FAILSEQ_STEPS 2
|
||||
const uint8_t FAILSEQ_NOTES[] = {49,49}; // tone frequence
|
||||
const uint16_t FAILSEQ_DURATION[] = {300,300}; // tone duration in milliseconds
|
||||
const unsigned long FAILSEQ_PAUSE[] = {400000,400000}; // pause between tones in microseconds
|
||||
|
||||
#define TIMER_MAX_TIME 99999
|
||||
#define TIMER_TIMEOUT 20000
|
||||
|
|
501
speedclock.ino
501
speedclock.ino
|
@ -18,8 +18,16 @@ RF24 radio(RF24_CNS,RF24_CE);
|
|||
/**********************************************************/
|
||||
byte addresses[][12] = {"top_station","basestation"}; // Radio pipe addresses for the 2 nodes to communicate.
|
||||
|
||||
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 blink_on = false; // set to TRUE if the system clock cycle signals to set LEDs in LED_BLINK mode to be active - means top be switched on
|
||||
unsigned long blink_on_swiched_at = 0; // the last system time (in milliseconds) the blink_on was switched
|
||||
uint8_t *leds_states = LEDStates[TIMER_INIT];
|
||||
|
||||
boolean time_offset_ok = false; // true as long as the offset is correctly calculated
|
||||
uint8_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 mean_time_offset = 0; // mean value for the offset
|
||||
signed long running_time_offset = 0; // offset that will be used for this run ...
|
||||
|
@ -29,10 +37,14 @@ unsigned long run_time = 0; // if the timer is running this is
|
|||
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_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 ...
|
||||
boolean keep_connection_off = true; // if sett to true the connection to the top station will be kept off for a timeout time to signal that we are in the init sequnce again ...
|
||||
uint8_t failed_offsets = MAX_ALLOWED_FAILED_OFFSETS; // number of offset values that did not fullfill the MAX_DIFFERENCE_OFFSET_MS criterion
|
||||
volatile boolean false_start = false; // set to true if a false start occurs (use volatile for all shared variables that deals with hardware)
|
||||
volatile uint8_t startsequence_count = 0; // shows thze actual step in the startsquence. Number of steps is defined in STARTSEQ_STEPS (use volatile for all shared variables that deals with hardware)
|
||||
volatile boolean startsequence_done = false;
|
||||
volatile boolean startsequence_done = false; // set to TRUE if the startsequnce was completed successfully (without a false start)
|
||||
volatile boolean failsequence_done = false;
|
||||
volatile uint8_t failsequence_count = 0;
|
||||
|
||||
boolean topbuttonwaspressed = false; // set to true if the stop button was pressed
|
||||
|
||||
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...
|
||||
|
@ -44,6 +56,8 @@ transcv_s radio_data;
|
|||
|
||||
void setup(){
|
||||
|
||||
PCICR = 0; // disable all pin change interrupts
|
||||
|
||||
Serial.begin(115200);
|
||||
|
||||
// this is the top button - will be pressed by the speed climber as soon she/he reaches the top ...
|
||||
|
@ -52,9 +66,10 @@ void setup(){
|
|||
pinMode(CANCELBUTTON_IN, INPUT_PULLUP);
|
||||
pinMode(FAILSTARTBUTTON_IN, INPUT_PULLUP);
|
||||
|
||||
pinMode(WARN_LED, OUTPUT);
|
||||
pinMode(FAIL_LED, OUTPUT);
|
||||
pinMode(READY_LED, OUTPUT);
|
||||
// set the LED pins as putput pins ...
|
||||
for(uint8_t led = 0; led<NO_LAST_LED-1;led++){
|
||||
pinMode(LEDPins[led], OUTPUT);
|
||||
}
|
||||
|
||||
// Get the station type (base or top) as set by the station select pin - BASESTATION is default
|
||||
|
||||
|
@ -98,52 +113,95 @@ void setup(){
|
|||
|
||||
void loop(void) {
|
||||
|
||||
|
||||
/****************** Shared code for all stations ********************************************************************************/
|
||||
if(millis() - blink_on_swiched_at > LED_BLINK_ALL_MS){
|
||||
blink_on_swiched_at = millis();
|
||||
blink_on = !blink_on;
|
||||
}
|
||||
/****************** Code for the TOPSTATION is here - the stop button is connected to the top station ***************************/
|
||||
|
||||
if (stationNumber == TOPSTATION){ // Radio is the top station and sends continously its time and the time the stop button was pressed.
|
||||
|
||||
// check for pressed button ...
|
||||
if(topbuttonwaspressed == false){
|
||||
if( (millis() - radio_data.topbuttonpressedtime) > MIN_DELAY_BETWEEN_PRESSED_MS){
|
||||
// ignore if the button was "pressed" a few millis before - this is keybouncing and would give a false result and if the button is pressed for a longer time that would effect the time as well
|
||||
if(digitalRead(STOPBUTTON_IN) == STOPBUTTON_PRESSED){
|
||||
// button was pressed - store the time
|
||||
radio_data.topbuttonpressedtime = millis();
|
||||
topbuttonwaspressed = true;
|
||||
digitalWrite(RUN_LED, RUN_LED_ON);
|
||||
|
||||
startloop_ms = millis();
|
||||
|
||||
if(false == offset_sync_sequence){
|
||||
// check for pressed button ...
|
||||
if(topbuttonwaspressed == false){
|
||||
if( (millis() - radio_data.topbuttonpressedtime) > MIN_DELAY_BETWEEN_PRESSED_MS){
|
||||
// ignore if the button was "pressed" a few millis before - this is keybouncing and would give a false result and if the button is pressed for a longer time that would effect the time as well
|
||||
if(digitalRead(STOPBUTTON_IN) == STOPBUTTON_PRESSED){
|
||||
// button was pressed - store the time
|
||||
radio_data.topbuttonpressedtime = millis();
|
||||
topbuttonwaspressed = true;
|
||||
digitalWrite(LEDPins[RUN_LED], LED_ON);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(digitalRead(STOPBUTTON_IN) != STOPBUTTON_PRESSED){
|
||||
topbuttonwaspressed = false;
|
||||
digitalWrite(LEDPins[RUN_LED], LED_OFF);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(digitalRead(STOPBUTTON_IN) != STOPBUTTON_PRESSED){
|
||||
topbuttonwaspressed = false;
|
||||
digitalWrite(RUN_LED, RUN_LED_OFF);
|
||||
}
|
||||
topbuttonwaspressed = false;
|
||||
digitalWrite(LEDPins[RUN_LED], LED_OFF);
|
||||
}
|
||||
|
||||
|
||||
// if the button was not pressed only each few second data will be send to BASESTATION ...
|
||||
if(topbuttonwaspressed || ((millis()-radio_data.topstationtime) >= MIN_DELAY_BETWEEN_SEND_MS)){
|
||||
if(offset_sync_sequence || topbuttonwaspressed || ((millis()-radio_data.topstationtime) >= MIN_DELAY_BETWEEN_SEND_MS)){
|
||||
// store current millis to be send as reference ...
|
||||
radio_data.topstationtime = millis(); // set the current milli second count
|
||||
Serial.print("ms - Send data to bottom station: topstationtime: ");
|
||||
Serial.print( radio_data.topstationtime );
|
||||
Serial.print(" stoppressedtime: ");
|
||||
Serial.print( radio_data.topbuttonpressedtime );
|
||||
Serial.print("senddate_to_base ");
|
||||
Serial.println(millis());
|
||||
//Serial.print("ms - topstationtime: ");
|
||||
//Serial.print( radio_data.topstationtime );
|
||||
//Serial.print(" stoppressedtime: ");
|
||||
//Serial.print( radio_data.topbuttonpressedtime );
|
||||
Serial.print(" offset counter value : ");
|
||||
Serial.println(counter_time_offset);
|
||||
|
||||
// send data ...
|
||||
if (!radio.write(&radio_data,sizeof(radio_data) )){ // Send the counter variable to the other radio
|
||||
Serial.println(F("Failed to send data to BASESSTATION ... will retry"));
|
||||
digitalWrite(FAIL_LED, FAIL_LED_ON);
|
||||
digitalWrite(READY_LED, READY_LED_OFF);
|
||||
if (!radio.write(&radio_data,sizeof(radio_data))){ // Send the counter variable to the other radio
|
||||
if(((millis() - connection_last_established_at_ms) >= (CONN_TIMEOUT-100)) || (connection_last_established_at_ms == 0)){
|
||||
connection_available = false;
|
||||
Serial.println(F("Failed to send data to BASESSTATION ... will retry"));
|
||||
digitalWrite(LEDPins[FAIL_LED], LED_ON);
|
||||
digitalWrite(LEDPins[READY_LED], LED_OFF);
|
||||
offset_sync_sequence = true;
|
||||
counter_time_offset = 0;
|
||||
} else {
|
||||
if(offset_sync_sequence){
|
||||
if(counter_time_offset > 0){
|
||||
counter_time_offset--;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Serial.println("Data sent to BASESSTATION");
|
||||
digitalWrite(FAIL_LED, FAIL_LED_OFF);
|
||||
digitalWrite(READY_LED, READY_LED_ON);
|
||||
//Serial.println("Data sent to BASESSTATION");
|
||||
digitalWrite(LEDPins[FAIL_LED], LED_OFF);
|
||||
if(offset_sync_sequence){
|
||||
digitalWrite(LEDPins[FAIL_LED], blink_on);
|
||||
} else {
|
||||
digitalWrite(LEDPins[READY_LED], LED_ON);
|
||||
}
|
||||
connection_last_established_at_ms = millis();
|
||||
connection_available = true;
|
||||
// check offset sync counter ...
|
||||
if(counter_time_offset < (4*REQUIRED_NUMBER_MEANVALS)){
|
||||
counter_time_offset++;
|
||||
} else {
|
||||
// offset sync done
|
||||
offset_sync_sequence = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Serial.print("looptime_top ");
|
||||
Serial.println(millis()-startloop_ms);
|
||||
|
||||
}
|
||||
|
||||
|
@ -151,6 +209,8 @@ void loop(void) {
|
|||
|
||||
if ( stationNumber == BASESTATION ) {
|
||||
|
||||
startloop_ms = millis();
|
||||
|
||||
// receive data from top_station, calculate offset and set 'last connection' time stamp
|
||||
receive_values();
|
||||
|
||||
|
@ -158,6 +218,13 @@ void loop(void) {
|
|||
update_screen(timer_new_state);
|
||||
|
||||
// set state to new_state
|
||||
if(timer_state != timer_new_state){
|
||||
Serial.print(millis());
|
||||
Serial.print("ms : current state: ");
|
||||
Serial.print(timer_state);
|
||||
Serial.print(" new state: ");
|
||||
Serial.println(timer_new_state);
|
||||
}
|
||||
timer_state = timer_new_state;
|
||||
|
||||
// set LEDs
|
||||
|
@ -174,15 +241,21 @@ void loop(void) {
|
|||
if(connection_available == false){
|
||||
// if the connection was lost ... switch to noconnection state
|
||||
timer_new_state = TIMER_NOCONNECTION;
|
||||
//Serial.println("No connection state will be next");
|
||||
}
|
||||
else{
|
||||
// if the offset is claculated, cancel not pressed and failstart not pressed switch to IDLE mode ...
|
||||
if((time_offset_ok == true) &&
|
||||
(digitalRead(CANCELBUTTON_IN != CANCELBUTTON_PRESSED)) &&
|
||||
(digitalRead(FAILSTARTBUTTON_IN != FAILSTARTBUTTON_PRESSED)) )
|
||||
(digitalRead(CANCELBUTTON_IN) != CANCELBUTTON_PRESSED) &&
|
||||
(digitalRead(FAILSTARTBUTTON_IN) != FAILSTARTBUTTON_PRESSED) )
|
||||
{
|
||||
// check if offset is OK - if not .. set state back to INIT
|
||||
//Serial.println("idle state will be next");
|
||||
timer_new_state = TIMER_IDLE;
|
||||
} else {
|
||||
//Serial.println("init state will be next");
|
||||
//Serial.print("offset_ok :");
|
||||
//Serial.println(time_offset_ok);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -193,9 +266,11 @@ void loop(void) {
|
|||
timer_new_state = TIMER_NOCONNECTION;
|
||||
}
|
||||
else{
|
||||
if(time_offset_ok == true){
|
||||
if(time_offset_ok == false){
|
||||
// check if offset is OK - if not .. set state back to INIT
|
||||
timer_new_state = TIMER_INIT;
|
||||
keep_connection_off = true;
|
||||
connection_last_established_at_ms = millis();
|
||||
}
|
||||
else{
|
||||
// check if the FALSESTATE button is pressed OR we are in trainingsmode - somebody is ready to run, but STARTBUTTON is NOT pressed ...
|
||||
|
@ -213,11 +288,12 @@ void loop(void) {
|
|||
}
|
||||
break;
|
||||
case TIMER_READY:
|
||||
delay(10);
|
||||
if((digitalRead(FAILSTARTBUTTON_IN) != FAILSTARTBUTTON_PRESSED) &&
|
||||
(timer_mode != MODE_TRAINING))
|
||||
{
|
||||
// false start was released again - go back to INIT ... so far this is not a false start - run was not started yet
|
||||
timer_new_state = TIMER_INIT;
|
||||
// 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;
|
||||
} else {
|
||||
// check if the start button was pressed ... there is at least still someone waiting for the run .
|
||||
if(digitalRead(STARTBUTTON_IN) == STARTBUTTON_PRESSED){
|
||||
|
@ -226,12 +302,16 @@ void loop(void) {
|
|||
startsequence_done = false;
|
||||
running_time_offset = mean_time_offset;
|
||||
false_start = false;
|
||||
attachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN), false_start_isr, CHANGE);
|
||||
attachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN), false_start_isr, RISING );
|
||||
Timer1.initialize();
|
||||
timer_new_state = TIMER_STARTED;
|
||||
// set the startime - this is the current time plus the length of this sequence
|
||||
start_time = millis() + STARTSEQ_LENGTH_MS;
|
||||
timer_new_state = TIMER_STARTED;
|
||||
//Serial.print(millis());
|
||||
//Serial.print(" <- current time ; starttime -> ");
|
||||
//Serial.println(start_time);
|
||||
// call the start sequence interrupt routine ...
|
||||
start_isr();
|
||||
Timer1.attachInterrupt(start_isr,STARTSEQ_PAUSE[startsequence_count]); // startISR to run every given microseconds
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -239,7 +319,10 @@ void loop(void) {
|
|||
//initialize the start ISR and the timer interrupt ...
|
||||
//----> to be removed : startSequence();
|
||||
if( false_start == true) {
|
||||
failsequence_done = false;
|
||||
failsequence_count = 0;
|
||||
timer_new_state = TIMER_FAIL;
|
||||
Timer1.attachInterrupt(failSequence,FAILSEQ_PAUSE[failsequence_count]);
|
||||
} else {
|
||||
if(startsequence_done == true){
|
||||
timer_new_state = TIMER_RUNNING;
|
||||
|
@ -247,21 +330,26 @@ void loop(void) {
|
|||
}
|
||||
break;
|
||||
case TIMER_RUNNING:
|
||||
noTone(PIEZO_PIN);
|
||||
//noTone(PIEZO_PIN);
|
||||
if(time_offset_ok != true){
|
||||
// check if offset is still OK - if not .. set warning
|
||||
warn_during_run = true;
|
||||
}
|
||||
if(millis() - start_time > TIMER_TIMEOUT){
|
||||
if((signed long)(millis() - start_time) > TIMER_TIMEOUT){
|
||||
//Serial.print(millis());
|
||||
//Serial.print("<- curren time ; runtime ->");
|
||||
//Serial.println(millis() - start_time);
|
||||
timer_new_state = TIMER_TIMEDOUT;
|
||||
}
|
||||
if(digitalRead(CANCELBUTTON_IN) == CANCELBUTTON_PRESSED){
|
||||
timer_new_state = TIMER_CANCELLED;
|
||||
}
|
||||
if(radio_data.topbuttonpressedtime > running_time_offset){
|
||||
if((radio_data.topbuttonpressedtime - running_time_offset) > start_time){
|
||||
run_time = (radio_data.topbuttonpressedtime - running_time_offset) - start_time;
|
||||
timer_new_state = TIMER_STOPPED;
|
||||
} else {
|
||||
if(digitalRead(CANCELBUTTON_IN) == CANCELBUTTON_PRESSED){
|
||||
timer_new_state = TIMER_CANCELLED;
|
||||
} else {
|
||||
if(radio_data.topbuttonpressedtime > running_time_offset){
|
||||
if((radio_data.topbuttonpressedtime - running_time_offset) > start_time){
|
||||
run_time = (radio_data.topbuttonpressedtime - running_time_offset) - start_time;
|
||||
timer_new_state = TIMER_STOPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -274,11 +362,12 @@ void loop(void) {
|
|||
break;
|
||||
case TIMER_FAIL:
|
||||
//fail start case ....
|
||||
failSequence();
|
||||
run_time = 99999;
|
||||
delay(KEY_BOUNCE_MS);
|
||||
if(digitalRead(CANCELBUTTON_IN) != CANCELBUTTON_PRESSED){
|
||||
timer_new_state = TIMER_WAIT;
|
||||
if(true == failsequence_done){
|
||||
delay(KEY_BOUNCE_MS);
|
||||
if(digitalRead(CANCELBUTTON_IN) != CANCELBUTTON_PRESSED){
|
||||
timer_new_state = TIMER_WAIT;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case TIMER_CANCELLED:
|
||||
|
@ -298,17 +387,23 @@ void loop(void) {
|
|||
}
|
||||
break;
|
||||
case TIMER_WAIT:
|
||||
delay(10);
|
||||
// disable interrupt if not already done
|
||||
detachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN));
|
||||
//detachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN));
|
||||
// wait until the chancel button was pressed to go ahead
|
||||
if((digitalRead(CANCELBUTTON_IN) == CANCELBUTTON_PRESSED) &&
|
||||
(digitalRead(STOPBUTTON_IN) == STOPBUTTON_PRESSED) &&
|
||||
(digitalRead(FAILSTARTBUTTON_IN) == FAILSTARTBUTTON_PRESSED))
|
||||
if((digitalRead(CANCELBUTTON_IN) == CANCELBUTTON_PRESSED) //&&
|
||||
//(digitalRead(STOPBUTTON_IN) != STOPBUTTON_PRESSED) &&
|
||||
//(digitalRead(FAILSTARTBUTTON_IN) != FAILSTARTBUTTON_PRESSED)
|
||||
)
|
||||
{
|
||||
timer_new_state = TIMER_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
//Serial.print("looptime_base ");
|
||||
//Serial.println(millis());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -316,91 +411,97 @@ void loop(void) {
|
|||
//####################### HELPER FUNCTIONS ###########################
|
||||
void receive_values(void){
|
||||
signed long current_time_offset = 0; // current offset ...
|
||||
// check if radio data is available - if so read the data
|
||||
if( radio.available()){
|
||||
// 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());
|
||||
Serial.print(F(" Current time on client in millis: "));
|
||||
Serial.println(radio_data.topstationtime);
|
||||
Serial.print("Offset is: ");
|
||||
Serial.println(current_time_offset);
|
||||
Serial.print(F(" Button was pressed last time on client in millis: "));
|
||||
Serial.println(radio_data.topbuttonpressedtime);
|
||||
|
||||
// offset calculation ... only needed if the variation is bigger than allowed or not enough values available already ...
|
||||
if(counter_time_offset == 0){
|
||||
// this is the initial setup to start with something - in this case the last offset value that was received
|
||||
mean_time_offset = current_time_offset;
|
||||
}
|
||||
// check current offset of the TOP_STATIOn and the BASESTATION if more than allowed ...
|
||||
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 ...
|
||||
if(counter_time_offset <= REQUIRED_NUMBER_MEANVALS){
|
||||
//add the next value to meanvalue calculation ...
|
||||
sum_time_offset = sum_time_offset + current_time_offset;
|
||||
counter_time_offset++;
|
||||
mean_time_offset = sum_time_offset/counter_time_offset;
|
||||
Serial.print(F("Offset calulation. We have "));
|
||||
Serial.print(counter_time_offset);
|
||||
Serial.print(F("/"));
|
||||
Serial.print(REQUIRED_NUMBER_MEANVALS);
|
||||
Serial.print(F(" values. Mean offset value based on that is: "));
|
||||
Serial.println(mean_time_offset);
|
||||
} else {
|
||||
time_offset_ok = true;
|
||||
}
|
||||
|
||||
// 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((millis() - connection_last_established_at_ms) > (2*CONN_TIMEOUT)){
|
||||
keep_connection_off = false;
|
||||
Serial.println("Connection ON allowed.");
|
||||
} else {
|
||||
// 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++;
|
||||
Serial.println("Connection OFF forced.");
|
||||
}
|
||||
} else
|
||||
{
|
||||
// check if radio data is available - if so read the data
|
||||
if( radio.available()){
|
||||
// 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());
|
||||
//Serial.print(F(" Current time on client in millis: "));
|
||||
//Serial.println(radio_data.topstationtime);
|
||||
//Serial.print("Offset is: ");
|
||||
//Serial.println(current_time_offset);
|
||||
//Serial.print(F(" Button was pressed last time on client in millis: "));
|
||||
//Serial.println(radio_data.topbuttonpressedtime);
|
||||
|
||||
// offset calculation ... only needed if the variation is bigger than allowed or not enough values available already ...
|
||||
if(counter_time_offset == 0){
|
||||
// this is the initial setup to start with something - in this case the last offset value that was received
|
||||
mean_time_offset = current_time_offset;
|
||||
}
|
||||
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("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);
|
||||
Serial.print("is to far from the mean offset ");
|
||||
Serial.println( abs(current_time_offset - mean_time_offset) );
|
||||
Serial.print(F(" is more than the allowed: "));
|
||||
Serial.print(MAX_DIFFERENCE_OFFSET_MS);
|
||||
Serial.print(F(" compared to the mean offset: "));
|
||||
Serial.println(mean_time_offset);
|
||||
time_offset_ok = false;
|
||||
counter_time_offset = 0;
|
||||
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");
|
||||
}
|
||||
// check current offset of the TOP_STATIOn and the BASESTATION if more than allowed ...
|
||||
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 ...
|
||||
if(counter_time_offset <= REQUIRED_NUMBER_MEANVALS){
|
||||
//add the next value to meanvalue calculation ...
|
||||
sum_time_offset = sum_time_offset + current_time_offset;
|
||||
counter_time_offset++;
|
||||
mean_time_offset = sum_time_offset/counter_time_offset;
|
||||
Serial.print(F("Offset calulation. We have "));
|
||||
Serial.print(counter_time_offset);
|
||||
Serial.print(F("/"));
|
||||
Serial.print(REQUIRED_NUMBER_MEANVALS);
|
||||
Serial.print(F(" values. Mean offset value based on that is: "));
|
||||
Serial.println(mean_time_offset);
|
||||
} else {
|
||||
time_offset_ok = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
// 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("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);
|
||||
Serial.print("is to far from the mean offset ");
|
||||
Serial.println( abs(current_time_offset - mean_time_offset) );
|
||||
Serial.print(F(" is more than the allowed: "));
|
||||
Serial.print(MAX_DIFFERENCE_OFFSET_MS);
|
||||
Serial.print(F(" compared to the mean offset: "));
|
||||
Serial.println(mean_time_offset);
|
||||
time_offset_ok = false;
|
||||
counter_time_offset = 0;
|
||||
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{
|
||||
Serial.println("No data from TOP_STATION avaialble - OR the connection couldn't be established");
|
||||
}
|
||||
} // radio available
|
||||
|
||||
|
||||
// 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");
|
||||
}
|
||||
} // radio available
|
||||
} // keep connection off
|
||||
}// receive values
|
||||
|
||||
void update_screen(timer_state_e state){
|
||||
|
@ -464,6 +565,7 @@ void update_screen(timer_state_e state){
|
|||
footer = "Reaction time: ";
|
||||
footer += curr_time_local;
|
||||
footer += " sec";
|
||||
Serial.println(footer);
|
||||
break;
|
||||
case TIMER_TIMEDOUT:
|
||||
header = "Timed out!";
|
||||
|
@ -530,65 +632,106 @@ void update_screen(timer_state_e state){
|
|||
}
|
||||
|
||||
void set_state_LEDs(timer_state_e state, boolean warn){
|
||||
//Serial.print("led state is: ");
|
||||
//Serial.println(state);
|
||||
// set the LEDS corresponding to the state of the timer ... as long as the system is not waiting for input ...
|
||||
if(TIMER_WAIT != state){
|
||||
digitalWrite(READY_LED, LEDStates[state][0]);
|
||||
digitalWrite(RUN_LED, LEDStates[state][1]);
|
||||
digitalWrite(FAIL_LED, LEDStates[state][2]);
|
||||
|
||||
if(warn == true){
|
||||
digitalWrite(WARN_LED, WARN_LED_ON);
|
||||
}
|
||||
else
|
||||
{
|
||||
digitalWrite(WARN_LED, WARN_LED_OFF);
|
||||
leds_states = LEDStates[state];
|
||||
}
|
||||
// loop over all the LEDs and set state ...
|
||||
for(uint8_t led = 0; led<NO_LAST_LED-1;led++){
|
||||
//Serial.print("led: ");
|
||||
//Serial.print(led);
|
||||
// warn is special so far - there is no special state for the warn led . Handle if warn flag is set - switch LED on in this case ...
|
||||
if((WARN_LED == led)&&(true==warn)){
|
||||
digitalWrite(LEDPins[led], HIGH);
|
||||
//Serial.println(" set to HIGH");
|
||||
} else {
|
||||
switch(leds_states[led]){
|
||||
case LED_BLINK:
|
||||
digitalWrite(LEDPins[led], blink_on);
|
||||
//Serial.println(" set to BLINK");
|
||||
break;
|
||||
case LED_OFF:
|
||||
digitalWrite(LEDPins[led], LOW);
|
||||
//Serial.println(" set to LOW");
|
||||
break;
|
||||
case LED_ON:
|
||||
digitalWrite(LEDPins[led], HIGH);
|
||||
//Serial.println(" set to HIGH");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void failSequence(void){
|
||||
// first tone
|
||||
tone(PIEZO_PIN, FAILSEQ_TON_FREQUENCY,FAILSEQ_TON_LENGTH_MS );
|
||||
delay(FAILSEQ_TONEPAUSE_MS);
|
||||
//second tone
|
||||
tone(PIEZO_PIN, FAILSEQ_TON_FREQUENCY,FAILSEQ_TON_LENGTH_MS );
|
||||
delay(FAILSEQ_TONEPAUSE_MS);
|
||||
noTone(PIEZO_PIN);
|
||||
Serial.print(millis());
|
||||
Serial.print(" <- current time ; failsquence count -> ");
|
||||
Serial.println(failsequence_count);
|
||||
if(failsequence_count <FAILSEQ_STEPS){
|
||||
Serial.println(FAILSEQ_DURATION[failsequence_count]);
|
||||
// play the tone ...
|
||||
tone( PIEZO_PIN, FAILSEQ_NOTES[failsequence_count],FAILSEQ_DURATION[failsequence_count] );
|
||||
if(failsequence_count > 0){
|
||||
Timer1.setPeriod(FAILSEQ_PAUSE[failsequence_count]);
|
||||
}
|
||||
// increase the counter
|
||||
failsequence_count++;
|
||||
} else {
|
||||
// set the done bit and stop and detache the timer1
|
||||
Timer1.detachInterrupt();
|
||||
failsequence_done = true;
|
||||
noTone(PIEZO_PIN);
|
||||
}
|
||||
}
|
||||
|
||||
void false_start_isr(void){
|
||||
// this is the interrupt routine for the FALSESTART button
|
||||
// this will save the time when the runner is really started
|
||||
//Serial.println("** Interrupt service routine started: false_start_ISR **");
|
||||
runner_start_time = millis();
|
||||
if(millis() - start_time <= 0){
|
||||
false_start = true;
|
||||
Serial.println("** Interrupt service routine detected false_start. Set new state to TIMER_FAIL **");
|
||||
detachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN));
|
||||
} else {
|
||||
// disable this interrupt;
|
||||
if(timer_new_state != TIMER_READY){
|
||||
//Serial.print(millis());
|
||||
//Serial.println("** Interrupt service routine started: false_start_ISR **");
|
||||
//Serial.print("false start button: ");
|
||||
//Serial.println(digitalRead(FAILSTARTBUTTON_IN));
|
||||
runner_start_time = millis();
|
||||
if(false == startsequence_done){
|
||||
false_start = true;
|
||||
Serial.print(millis());
|
||||
Serial.print(" <- current time ; starttime -> ");
|
||||
Serial.print(start_time);
|
||||
Serial.println(" ** Interrupt service routine detected false_start. **");
|
||||
}
|
||||
detachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN));
|
||||
}
|
||||
}
|
||||
|
||||
void start_isr(void){
|
||||
// this is the timer interrupt routine that is called during the startsequence
|
||||
if(startsequence_count < STARTSEQ_STEPS){
|
||||
// (re)init the interrupt timer ...
|
||||
Timer1.initialize(STARTSEQ_PAUSE[startsequence_count]);
|
||||
Timer1.attachInterrupt(start_isr); // startISR to run every given microseconds
|
||||
|
||||
// play the tone ...
|
||||
if(STARTSEQ_NOTES[startsequence_count] > 0 ){
|
||||
tone( PIEZO_PIN, STARTSEQ_NOTES[startsequence_count],STARTSEQ_DURATION[startsequence_count] );
|
||||
//Serial.print(millis());
|
||||
//Serial.print(" <- current time ; startsquence count -> ");
|
||||
//Serial.println(startsequence_count);
|
||||
if(false == false_start){
|
||||
if(startsequence_count < STARTSEQ_STEPS){
|
||||
// (re)init the interrupt timer ...
|
||||
if(startsequence_count > 0){
|
||||
// play the tone ...
|
||||
//Serial.println(STARTSEQ_DURATION[startsequence_count]);
|
||||
tone( PIEZO_PIN, STARTSEQ_NOTES[startsequence_count],STARTSEQ_DURATION[startsequence_count] );
|
||||
Timer1.setPeriod(STARTSEQ_PAUSE[startsequence_count]);
|
||||
}
|
||||
// increase the counter
|
||||
startsequence_count++;
|
||||
} else {
|
||||
// set the done bit and stop and detache the timer1
|
||||
Timer1.detachInterrupt();
|
||||
//Serial.print(millis());
|
||||
//Serial.println("ms: set startsequence done to true");
|
||||
startsequence_done = true;
|
||||
}
|
||||
|
||||
// increase the counter
|
||||
startsequence_count++;
|
||||
} else {
|
||||
// set the done bit and stop and detache the timer1
|
||||
Timer1.detachInterrupt();
|
||||
startsequence_done = true;
|
||||
Timer1.detachInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Reference in a new issue