last changes
This commit is contained in:
parent
75be491f28
commit
8b9fcc31c2
4 changed files with 349 additions and 234 deletions
Binary file not shown.
BIN
server_client.pptx
Normal file
BIN
server_client.pptx
Normal file
Binary file not shown.
42
speedclock.h
42
speedclock.h
|
@ -9,6 +9,7 @@
|
||||||
#define STATION_SEL1 10 // this 10 for Nano
|
#define STATION_SEL1 10 // this 10 for Nano
|
||||||
|
|
||||||
typedef enum {BASESTATION = 0, TOPSTATION} radio_type_e;
|
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_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_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????
|
#define RF24_PA_LEVEL RF24_PA_LOW // sending power level RF24_PA_LOW, RF24_PA_HIGH????
|
||||||
|
@ -20,12 +21,13 @@ typedef enum {BASESTATION = 0, TOPSTATION} radio_type_e;
|
||||||
//--------------- define the structure and type of data that sender and receiver will exchange ----------------
|
//--------------- define the structure and type of data that sender and receiver will exchange ----------------
|
||||||
|
|
||||||
typedef struct transcv_struct{
|
typedef struct transcv_struct{
|
||||||
unsigned long topstationtime; // the top station sends its time (millis()) continously to the base station
|
volatile unsigned long topstationtime_us; // the top station sends its time (micros()) continously to the base station
|
||||||
volatile unsigned long topbuttonpressedtime; // the top station sends the time in millis() when the button was pressed - this is already the calculated time
|
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;
|
}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 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 CONN_TIMEOUT 5000 // if there was no data received from the TOPSTATION for that amount of time - the connection is flagged as lost
|
#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_BOUNCE_MS 50 // the time we use to avoid keybouncing ...
|
||||||
#define KEY_LONGPRESSED_MS 1000
|
#define KEY_LONGPRESSED_MS 1000
|
||||||
|
@ -33,14 +35,15 @@ typedef struct transcv_struct{
|
||||||
#define BUTTON_NOTPRESSED HIGH
|
#define BUTTON_NOTPRESSED HIGH
|
||||||
#define BUTTON_PRESSED LOW
|
#define BUTTON_PRESSED LOW
|
||||||
#define BUTTON_LONGPRESSED 3
|
#define BUTTON_LONGPRESSED 3
|
||||||
typedef enum {BUTTON_STOPCANCEL = 0, BUTTON_START, BUTTON_FAIL,NO_LAST_BUTTON} button_number_e;
|
typedef enum {BUTTON_STOP = 0, BUTTON_CANCEL, BUTTON_START, BUTTON_FAIL,NO_LAST_BUTTON} button_number_e;
|
||||||
const uint8_t BUTTONPins[NO_LAST_BUTTON] = {
|
const uint8_t BUTTONPins[NO_LAST_BUTTON] = {
|
||||||
[BUTTON_STOPCANCEL] = 2, // stop/cancel button input pin
|
[BUTTON_STOP] = 2, // stop button input pin
|
||||||
|
[BUTTON_CANCEL] = 5, // cancel button input pin
|
||||||
[BUTTON_START] = 4, // start button input pin
|
[BUTTON_START] = 4, // start button input pin
|
||||||
[BUTTON_FAIL] = 3, // stop button input pin
|
[BUTTON_FAIL] = 3, // stop button input pin
|
||||||
};
|
};
|
||||||
|
|
||||||
#define MIN_DELAY_BETWEEN_PRESSED_MS 500 // 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_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 PIEZO_PIN 6 // piezo speaker
|
||||||
|
|
||||||
|
@ -77,26 +80,26 @@ const uint8_t LEDStates[][NO_LAST_LED] =
|
||||||
[TIMER_SETTINGS] = {[READY_LED]=LED_OFF, [RUN_LED]=LED_OFF, [FAIL_LED]=LED_OFF, [WARN_LED]=LED_ON} // 11
|
[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_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 100 // we need at least this number of meanvalues to be ready to start a run
|
#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 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
|
#define STARTSEQ_STEPS 4
|
||||||
const uint8_t STARTSEQ_NOTES[] = {0,392,392,1047}; // tone frequence
|
const uint8_t STARTSEQ_NOTES[] = {0,392,392,1047}; // tone frequence
|
||||||
const uint16_t STARTSEQ_DURATION[] = {0,200,200,100}; // tone duration in milliseconds
|
const uint16_t STARTSEQ_DURATION_MS[] = {0,200,200,100}; // tone duration in milliseconds
|
||||||
const unsigned long STARTSEQ_PAUSE[] = {1000000,1000000,1000000,100000}; // pause between tones in microseconds
|
const unsigned long STARTSEQ_PAUSE_US[] = {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 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
|
#define FAILSEQ_STEPS 2
|
||||||
const uint8_t FAILSEQ_NOTES[] = {49,49}; // tone frequence
|
const uint8_t FAILSEQ_NOTES[] = {49,49}; // tone frequence
|
||||||
const uint16_t FAILSEQ_DURATION[] = {300,300}; // tone duration in milliseconds
|
const uint16_t FAILSEQ_DURATION_MS[] = {300,300}; // tone duration in milliseconds
|
||||||
const unsigned long FAILSEQ_PAUSE[] = {400000,400000}; // pause between tones in microseconds
|
const unsigned long FAILSEQ_PAUSE_US[] = {400000,400000}; // pause between tones in microseconds
|
||||||
|
|
||||||
#define TIMER_MAX_TIME 99999
|
#define TIMER_MAX_TIME_US 99999999
|
||||||
#define TIMER_TIMEOUT 20000
|
#define TIMER_TIMEOUT_US 20000000
|
||||||
|
|
||||||
//--------------------------------------- function declarations ----------------------------------------------
|
//--------------------------------------- function declarations ----------------------------------------------
|
||||||
void receive_values(void);
|
void update_offset_values(void);
|
||||||
void false_start_isr(void);
|
void false_start_isr(void);
|
||||||
void update_screen(timer_state_e state);
|
void update_screen(timer_state_e state);
|
||||||
void set_state_LEDs(timer_state_e state, boolean warn);
|
void set_state_LEDs(timer_state_e state, boolean warn);
|
||||||
|
@ -108,5 +111,8 @@ void start_isr(void);
|
||||||
void update_buttons(void);
|
void update_buttons(void);
|
||||||
void send_values(void);
|
void send_values(void);
|
||||||
void stop_isr(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
|
#endif
|
||||||
|
|
381
speedclock.ino
381
speedclock.ino
|
@ -17,28 +17,40 @@ 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 stats_last_plotted_at_ms = 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 ...
|
||||||
|
|
||||||
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
|
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
|
unsigned long blink_on_swiched_at_ms = 0; // the last system time (in milliseconds) the blink_on was switched
|
||||||
uint8_t *leds_states = LEDStates[TIMER_INIT];
|
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
|
||||||
|
volatile boolean new_current_offset_available = false;
|
||||||
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 current_time_offset = 0; // current offset ...
|
signed long long sum_time_offset_us = 0; // sum of offset values
|
||||||
signed long mean_time_offset = 0; // mean value for the offset
|
float sum_time_slope = 0; // sum of slopes
|
||||||
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 last_top_time_us = 0; // current top time ...
|
||||||
volatile unsigned long runner_start_time = 0; // this is the time the runner left the pad - so the status of the falsetstart pin goes to high again - but this is OK and a real start (use volatile for all shared variables that deals with hardware)
|
volatile unsigned long current_top_time_us = 0; // current top time ...
|
||||||
unsigned long run_time = 0; // if the timer is running this is that start time ...
|
volatile unsigned long last_bottom_time_us = 0; // current top time ...
|
||||||
|
volatile unsigned long current_bottom_time_us = 0; // current top time ...
|
||||||
|
|
||||||
|
volatile signed long current_time_offset_us = 0; // current offset ...
|
||||||
|
|
||||||
|
signed long mean_time_offset_us = 0; // mean value for the offset (we have an linear sync function to map the TOPSTATION time to BOTTOMSTATIONTIME : t
|
||||||
|
float mean_time_slope = 0; // mean slope
|
||||||
|
|
||||||
|
signed long running_time_offset_us = 0; // offset that will be used for this run ...
|
||||||
|
volatile unsigned long start_time_us = 0; // if the timer is running this is that start time ... (use volatile for all shared variables that deals with hardware)
|
||||||
|
volatile unsigned long runner_start_time_us = 0; // this is the time the runner left the pad - so the status of the falsetstart pin goes to high again - but this is OK and a real start (use volatile for all shared variables that deals with hardware)
|
||||||
|
unsigned long run_time_us = 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
|
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
|
volatile 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 ...
|
volatile 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 ...
|
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
|
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 boolean false_start = false; // set to true if a false start occurs (use volatile for all shared variables that deals with hardware)
|
||||||
|
@ -50,14 +62,14 @@ volatile uint8_t failsequence_count = 0;
|
||||||
boolean topbuttonwaspressed = false; // set to true if the stop button was pressed
|
boolean topbuttonwaspressed = false; // set to true if the stop button was pressed
|
||||||
|
|
||||||
uint8_t button_state[NO_LAST_BUTTON] = {BUTTON_NOTPRESSED};
|
uint8_t button_state[NO_LAST_BUTTON] = {BUTTON_NOTPRESSED};
|
||||||
unsigned long button_last_changed_at[NO_LAST_BUTTON] = {0};
|
unsigned long button_last_changed_at_ms[NO_LAST_BUTTON] = {0};
|
||||||
uint8_t button_last_changed_to[NO_LAST_BUTTON] = {BUTTON_NOTPRESSED};
|
uint8_t button_last_changed_to[NO_LAST_BUTTON] = {BUTTON_NOTPRESSED};
|
||||||
|
|
||||||
timer_state_e timer_state = TIMER_INIT; // 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_state = TIMER_INIT; // 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_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;
|
unsigned long timer_mode_changed_at_ms = 0;
|
||||||
transcv_s radio_data;
|
transcv_s radio_data;
|
||||||
|
|
||||||
void setup(){
|
void setup(){
|
||||||
|
@ -92,10 +104,10 @@ void setup(){
|
||||||
// Setup and configure the NRF radio
|
// Setup and configure the NRF radio
|
||||||
// radio setup ...
|
// radio setup ...
|
||||||
radio.begin();
|
radio.begin();
|
||||||
radio.setRetries(15, 15); //the first is the time between reties in multiple of 250ms, the second is the numer of attempts
|
radio.setRetries(1, 1); //the first is the time between reties in multiple of 250ms, the second is the numer of attempts
|
||||||
if(stationNumber == TOPSTATION){
|
if(stationNumber == TOPSTATION){
|
||||||
// Attach the STOP button interrupt
|
// Attach the STOP button interrupt
|
||||||
attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_STOPCANCEL]), stop_isr, FALLING );
|
attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_STOP]), stop_isr, FALLING );
|
||||||
// Set the PA Level of the sendin TOP_STATION
|
// Set the PA Level of the sendin TOP_STATION
|
||||||
radio.setPALevel(RF24_PA_LEVEL);
|
radio.setPALevel(RF24_PA_LEVEL);
|
||||||
radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, but opposite addresses
|
radio.openWritingPipe(addresses[1]); // Both radios listen on the same pipes by default, but opposite addresses
|
||||||
|
@ -106,8 +118,8 @@ void setup(){
|
||||||
radio.openReadingPipe(1,addresses[1]);
|
radio.openReadingPipe(1,addresses[1]);
|
||||||
radio.startListening();
|
radio.startListening();
|
||||||
}
|
}
|
||||||
radio_data.topstationtime = millis(); // set the current milli second count
|
radio_data.topstationtime_us = micros(); // set the current micro second count
|
||||||
radio_data.topbuttonpressedtime = 0; // set the time the button was pressed last time to 0
|
radio_data.topbuttonpressedtime_us = 0; // set the time the button was pressed last time to 0
|
||||||
|
|
||||||
//initialise Wire and OLED
|
//initialise Wire and OLED
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
|
@ -121,8 +133,8 @@ void loop(void) {
|
||||||
/****************** Shared code for all stations ********************************************************************************/
|
/****************** Shared code for all stations ********************************************************************************/
|
||||||
startloop_ms = millis();
|
startloop_ms = millis();
|
||||||
|
|
||||||
if(millis() - blink_on_swiched_at > LED_BLINK_ALL_MS){
|
if(millis() - blink_on_swiched_at_ms > LED_BLINK_ALL_MS){
|
||||||
blink_on_swiched_at = millis();
|
blink_on_swiched_at_ms = millis();
|
||||||
blink_on = !blink_on;
|
blink_on = !blink_on;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +177,7 @@ void loop(void) {
|
||||||
timer_new_state = TIMER_NOCONNECTION;
|
timer_new_state = TIMER_NOCONNECTION;
|
||||||
} else {
|
} else {
|
||||||
if(false == offset_sync_sequence){
|
if(false == offset_sync_sequence){
|
||||||
if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){
|
if(button_state[BUTTON_STOP] == BUTTON_NOTPRESSED){
|
||||||
topbuttonwaspressed = false;
|
topbuttonwaspressed = false;
|
||||||
timer_new_state = TIMER_IDLE;
|
timer_new_state = TIMER_IDLE;
|
||||||
}
|
}
|
||||||
|
@ -184,8 +196,8 @@ void loop(void) {
|
||||||
break;
|
break;
|
||||||
case TIMER_STOPPED:
|
case TIMER_STOPPED:
|
||||||
// wait a few millis and ... after that go back to idle ...
|
// wait a few millis and ... after that go back to idle ...
|
||||||
if((signed long)(millis() - radio_data.topbuttonpressedtime) > MIN_DELAY_BETWEEN_PRESSED_MS){
|
if((signed long)(micros() - radio_data.topbuttonpressedtime_us) > MIN_DELAY_BETWEEN_PRESSED_US){
|
||||||
if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){
|
if(button_state[BUTTON_STOP] == BUTTON_NOTPRESSED){
|
||||||
timer_new_state = TIMER_IDLE;
|
timer_new_state = TIMER_IDLE;
|
||||||
topbuttonwaspressed = false;
|
topbuttonwaspressed = false;
|
||||||
}
|
}
|
||||||
|
@ -198,8 +210,11 @@ void loop(void) {
|
||||||
/****************** Code for the BASESTATION is here - the display and the start button is connected here. All caclulation will be done here ***************************/
|
/****************** Code for the BASESTATION is here - the display and the start button is connected here. All caclulation will be done here ***************************/
|
||||||
if ( stationNumber == BASESTATION ) {
|
if ( stationNumber == BASESTATION ) {
|
||||||
|
|
||||||
// receive data from top_station, calculate offset and set 'last connection' time stamp
|
// update connection status
|
||||||
receive_values();
|
handle_connection();
|
||||||
|
|
||||||
|
// calculate offset and set 'last connection' time stamp
|
||||||
|
//update_offset_values();
|
||||||
|
|
||||||
// update the OLED screen
|
// update the OLED screen
|
||||||
update_screen(timer_new_state);
|
update_screen(timer_new_state);
|
||||||
|
@ -225,7 +240,7 @@ void loop(void) {
|
||||||
else{
|
else{
|
||||||
// if the offset is claculated, cancel not pressed and failstart not pressed switch to IDLE mode ...
|
// if the offset is claculated, cancel not pressed and failstart not pressed switch to IDLE mode ...
|
||||||
if((time_offset_ok == true) &&
|
if((time_offset_ok == true) &&
|
||||||
(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED) &&
|
(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED) &&
|
||||||
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED) )
|
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED) )
|
||||||
{
|
{
|
||||||
// check if offset is OK - if not .. set state back to INIT
|
// check if offset is OK - if not .. set state back to INIT
|
||||||
|
@ -250,11 +265,11 @@ void loop(void) {
|
||||||
// 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_COMPETE)) &&
|
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))
|
(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED))
|
||||||
{
|
{
|
||||||
timer_new_state = TIMER_READY;
|
timer_new_state = TIMER_READY;
|
||||||
} else {
|
} else {
|
||||||
if((button_state[BUTTON_STOPCANCEL] == BUTTON_LONGPRESSED) &&
|
if((button_state[BUTTON_CANCEL] == BUTTON_LONGPRESSED) &&
|
||||||
(button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
|
(button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
|
||||||
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED))
|
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED))
|
||||||
{
|
{
|
||||||
|
@ -277,7 +292,7 @@ void loop(void) {
|
||||||
// now enable the interrupt for the FALSESTART button
|
// now enable the interrupt for the FALSESTART button
|
||||||
startsequence_count = 0;
|
startsequence_count = 0;
|
||||||
startsequence_done = false;
|
startsequence_done = false;
|
||||||
running_time_offset = mean_time_offset;
|
running_time_offset_us = mean_time_offset_us;
|
||||||
false_start = false;
|
false_start = false;
|
||||||
if(timer_mode == MODE_COMPETE){
|
if(timer_mode == MODE_COMPETE){
|
||||||
attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_FAIL]), false_start_isr, RISING );
|
attachInterrupt(digitalPinToInterrupt(BUTTONPins[BUTTON_FAIL]), false_start_isr, RISING );
|
||||||
|
@ -285,11 +300,11 @@ void loop(void) {
|
||||||
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_us = micros() + STARTSEQ_LENGTH_US;
|
||||||
// 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_US[startsequence_count]); // startISR to run every given microseconds
|
||||||
} else {
|
} else {
|
||||||
if((button_state[BUTTON_STOPCANCEL] == BUTTON_LONGPRESSED) &&
|
if((button_state[BUTTON_CANCEL] == BUTTON_LONGPRESSED) &&
|
||||||
(button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
|
(button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
|
||||||
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED))
|
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED))
|
||||||
{
|
{
|
||||||
|
@ -306,7 +321,7 @@ void loop(void) {
|
||||||
failsequence_done = false;
|
failsequence_done = false;
|
||||||
failsequence_count = 0;
|
failsequence_count = 0;
|
||||||
timer_new_state = TIMER_FAIL;
|
timer_new_state = TIMER_FAIL;
|
||||||
Timer1.attachInterrupt(failSequence,FAILSEQ_PAUSE[failsequence_count]);
|
Timer1.attachInterrupt(failSequence,FAILSEQ_PAUSE_US[failsequence_count]);
|
||||||
} else {
|
} else {
|
||||||
if(startsequence_done == true){
|
if(startsequence_done == true){
|
||||||
timer_new_state = TIMER_RUNNING;
|
timer_new_state = TIMER_RUNNING;
|
||||||
|
@ -318,15 +333,15 @@ void loop(void) {
|
||||||
// check if offset is still OK - if not .. set warning
|
// check if offset is still OK - if not .. set warning
|
||||||
warn_during_run = true;
|
warn_during_run = true;
|
||||||
}
|
}
|
||||||
if((signed long)(millis() - start_time) > TIMER_TIMEOUT){
|
if((signed long)(micros() - start_time_us) > TIMER_TIMEOUT_US){
|
||||||
timer_new_state = TIMER_TIMEDOUT;
|
timer_new_state = TIMER_TIMEDOUT;
|
||||||
} else {
|
} else {
|
||||||
if(button_state[BUTTON_STOPCANCEL] != BUTTON_NOTPRESSED){
|
if(button_state[BUTTON_CANCEL] != BUTTON_NOTPRESSED){
|
||||||
timer_new_state = TIMER_CANCELLED;
|
timer_new_state = TIMER_CANCELLED;
|
||||||
} else {
|
} else {
|
||||||
if(radio_data.topbuttonpressedtime > running_time_offset){
|
if(radio_data.topbuttonpressedtime_us > running_time_offset_us){
|
||||||
if((radio_data.topbuttonpressedtime - running_time_offset) > start_time){
|
if((signed long)(radio_data.topbuttonpressedtime_us - running_time_offset_us) > start_time_us){
|
||||||
run_time = (radio_data.topbuttonpressedtime - running_time_offset) - start_time;
|
run_time_us = (radio_data.topbuttonpressedtime_us - running_time_offset_us) - start_time_us;
|
||||||
timer_new_state = TIMER_STOPPED;
|
timer_new_state = TIMER_STOPPED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,39 +350,36 @@ void loop(void) {
|
||||||
break;
|
break;
|
||||||
case TIMER_STOPPED:
|
case TIMER_STOPPED:
|
||||||
//calculate the run_time and switch to WAIT
|
//calculate the run_time and switch to WAIT
|
||||||
delay(KEY_BOUNCE_MS);
|
if(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED){
|
||||||
if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){
|
|
||||||
timer_new_state = TIMER_WAIT;
|
timer_new_state = TIMER_WAIT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TIMER_FAIL:
|
case TIMER_FAIL:
|
||||||
//fail start case ....
|
//fail start case ....
|
||||||
run_time = 99999;
|
run_time_us = TIMER_MAX_TIME_US;
|
||||||
if(true == failsequence_done){
|
if(true == failsequence_done){
|
||||||
delay(KEY_BOUNCE_MS);
|
if(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED){
|
||||||
if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){
|
|
||||||
timer_new_state = TIMER_WAIT;
|
timer_new_state = TIMER_WAIT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TIMER_CANCELLED:
|
case TIMER_CANCELLED:
|
||||||
// what to do in chancel mode ?
|
// what to do in chancel mode ?
|
||||||
run_time = 99999;
|
run_time_us = TIMER_MAX_TIME_US;
|
||||||
delay(KEY_BOUNCE_MS);
|
if(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED){
|
||||||
if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){
|
|
||||||
timer_new_state = TIMER_WAIT;
|
timer_new_state = TIMER_WAIT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TIMER_TIMEDOUT:
|
case TIMER_TIMEDOUT:
|
||||||
// time out
|
// time out
|
||||||
run_time = millis() - start_time;
|
run_time_us = micros() - start_time_us;
|
||||||
if(button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED){
|
if(button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED){
|
||||||
timer_new_state = TIMER_WAIT;
|
timer_new_state = TIMER_WAIT;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TIMER_WAIT:
|
case TIMER_WAIT:
|
||||||
// wait until the chancel button was pressed to go ahead
|
// wait until the chancel button was pressed to go ahead
|
||||||
if((button_state[BUTTON_STOPCANCEL] != BUTTON_NOTPRESSED) &&
|
if((button_state[BUTTON_CANCEL] != BUTTON_NOTPRESSED) &&
|
||||||
(button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
|
(button_state[BUTTON_START] == BUTTON_NOTPRESSED) &&
|
||||||
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED)
|
(button_state[BUTTON_FAIL] == BUTTON_NOTPRESSED)
|
||||||
)
|
)
|
||||||
|
@ -377,16 +389,16 @@ void loop(void) {
|
||||||
break;
|
break;
|
||||||
case TIMER_SETTINGS:
|
case TIMER_SETTINGS:
|
||||||
// switch between the different modes for now - compete, training and calibration ...
|
// switch between the different modes for now - compete, training and calibration ...
|
||||||
if((button_state[BUTTON_STOPCANCEL] == BUTTON_PRESSED) &&
|
if((button_state[BUTTON_CANCEL] == BUTTON_PRESSED) &&
|
||||||
(button_state[BUTTON_START] == BUTTON_NOTPRESSED))
|
(button_state[BUTTON_START] == BUTTON_NOTPRESSED))
|
||||||
{
|
{
|
||||||
// go back to idle
|
// go back to idle
|
||||||
timer_new_state = TIMER_IDLE;
|
timer_new_state = TIMER_IDLE;
|
||||||
} else {
|
} else {
|
||||||
if((button_state[BUTTON_STOPCANCEL] == BUTTON_NOTPRESSED) &&
|
if((button_state[BUTTON_CANCEL] == BUTTON_NOTPRESSED) &&
|
||||||
(button_state[BUTTON_START] == BUTTON_PRESSED))
|
(button_state[BUTTON_START] == BUTTON_PRESSED))
|
||||||
{
|
{
|
||||||
if((millis() - timer_mode_changed_at) > KEY_TOGGLE_MS){
|
if((millis() - timer_mode_changed_at_ms) > KEY_TOGGLE_MS){
|
||||||
// switch system mode ...
|
// switch system mode ...
|
||||||
switch(timer_mode){
|
switch(timer_mode){
|
||||||
case MODE_COMPETE:
|
case MODE_COMPETE:
|
||||||
|
@ -399,7 +411,7 @@ void loop(void) {
|
||||||
timer_mode = MODE_COMPETE;
|
timer_mode = MODE_COMPETE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
timer_mode_changed_at = millis();
|
timer_mode_changed_at_ms = millis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,21 +420,68 @@ void loop(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// ignore the first seconds ...
|
||||||
|
if(time_offset_ok == true){
|
||||||
if( (STATS_PLOTS_EVERY_MS > 0) &&
|
if( (STATS_PLOTS_EVERY_MS > 0) &&
|
||||||
((millis() -stats_last_plotted) > STATS_PLOTS_EVERY_MS))
|
((signed long)(millis() -stats_last_plotted_at_ms) > STATS_PLOTS_EVERY_MS))
|
||||||
{
|
{
|
||||||
Serial.println("mean_time_offset-current_time_offset");
|
//Serial.println("mean_time_offset-current_time_offset");
|
||||||
Serial.print((signed long)(mean_time_offset - current_time_offset));
|
//Serial.println(calc_mean_offset(current_top_time_us));
|
||||||
//Serial.print(" ");
|
//Serial.print(" ");
|
||||||
//Serial.println(millis()- startloop_ms);
|
//Serial.print(mean_time_offset_us);
|
||||||
stats_last_plotted = millis();
|
//Serial.print(" ");
|
||||||
|
//Serial.println(current_time_offset_us);
|
||||||
|
stats_last_plotted_at_ms = millis();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
//####################### HELPER FUNCTIONS ###########################
|
//####################### HELPER FUNCTIONS ###########################
|
||||||
|
signed long calc_top2bot_time(signed long current_toptime){
|
||||||
|
return((mean_time_slope*current_toptime) + mean_time_offset_us);
|
||||||
|
}
|
||||||
|
|
||||||
|
void nrf24_isr(void)
|
||||||
|
{
|
||||||
|
//Serial.println("Got data from TOPSTATION");
|
||||||
|
bool tx,fail,rx;
|
||||||
|
// 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 == false){
|
||||||
|
radio.whatHappened(tx,fail,rx); // What happened?
|
||||||
|
if ( rx ){
|
||||||
|
// check if radio data is available - if so read the data
|
||||||
|
// 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
|
||||||
|
//}
|
||||||
|
if(new_current_offset_available == false){
|
||||||
|
last_top_time_us = current_top_time_us;
|
||||||
|
current_top_time_us = radio_data.topstationtime_us;
|
||||||
|
last_bottom_time_us = current_bottom_time_us;
|
||||||
|
current_bottom_time_us = micros();
|
||||||
|
//new_current_offset_available = true;
|
||||||
|
Serial.print(" last_top_time_us:");
|
||||||
|
Serial.print(last_top_time_us);
|
||||||
|
Serial.print(" current_top_time_us:");
|
||||||
|
Serial.print(current_top_time_us);
|
||||||
|
Serial.print(" last_bottom_time_us.");
|
||||||
|
Serial.print(last_bottom_time_us);
|
||||||
|
Serial.print(" current_bottom_time_us:");
|
||||||
|
Serial.println(current_bottom_time_us);
|
||||||
|
Serial.print("current offset:");
|
||||||
|
Serial.println((signed long)(current_top_time_us - current_bottom_time_us));
|
||||||
|
}
|
||||||
|
connection_last_established_at_ms = millis();
|
||||||
|
connection_available = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void update_buttons(void){
|
void update_buttons(void){
|
||||||
uint8_t curr_button_state;
|
uint8_t curr_button_state;
|
||||||
unsigned long button_pressed_at = millis();
|
unsigned long button_pressed_at_ms = millis();
|
||||||
String state_string;
|
String state_string;
|
||||||
// we have some buttons to update that are used in the sketch ...
|
// we have some buttons to update that are used in the sketch ...
|
||||||
for(uint8_t button = 0; button < NO_LAST_BUTTON; button++){
|
for(uint8_t button = 0; button < NO_LAST_BUTTON; button++){
|
||||||
|
@ -435,7 +494,7 @@ void update_buttons(void){
|
||||||
curr_button_state = BUTTON_PRESSED;
|
curr_button_state = BUTTON_PRESSED;
|
||||||
}
|
}
|
||||||
if( curr_button_state != button_last_changed_to[button] ){
|
if( curr_button_state != button_last_changed_to[button] ){
|
||||||
button_last_changed_at[button] = button_pressed_at;
|
button_last_changed_at_ms[button] = button_pressed_at_ms;
|
||||||
button_last_changed_to[button] = curr_button_state;
|
button_last_changed_to[button] = curr_button_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,7 +502,7 @@ void update_buttons(void){
|
||||||
((curr_button_state == BUTTON_PRESSED) && (button_state[button] == BUTTON_NOTPRESSED))) // the button has changed its state
|
((curr_button_state == BUTTON_PRESSED) && (button_state[button] == BUTTON_NOTPRESSED))) // the button has changed its state
|
||||||
{
|
{
|
||||||
// is that bouncing or settled?
|
// is that bouncing or settled?
|
||||||
if((unsigned long)(button_pressed_at - button_last_changed_at[button]) > KEY_BOUNCE_MS){
|
if((unsigned long)(button_pressed_at_ms - button_last_changed_at_ms[button]) > KEY_BOUNCE_MS){
|
||||||
// settled! -> change the stored state.
|
// settled! -> change the stored state.
|
||||||
button_state[button] = curr_button_state;
|
button_state[button] = curr_button_state;
|
||||||
} else {
|
} else {
|
||||||
|
@ -453,7 +512,7 @@ void update_buttons(void){
|
||||||
(button_state[button] == BUTTON_PRESSED))
|
(button_state[button] == BUTTON_PRESSED))
|
||||||
{
|
{
|
||||||
//check for long pressed button ...
|
//check for long pressed button ...
|
||||||
if((unsigned long)(button_pressed_at - button_last_changed_at[button]) > KEY_LONGPRESSED_MS){
|
if((unsigned long)(button_pressed_at_ms - button_last_changed_at_ms[button]) > KEY_LONGPRESSED_MS){
|
||||||
button_state[button] = BUTTON_LONGPRESSED;
|
button_state[button] = BUTTON_LONGPRESSED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,61 +520,105 @@ void update_buttons(void){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void receive_values(void){
|
void handle_connection(void){
|
||||||
// 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 == true){
|
||||||
if(keep_connection_off){
|
// Attach the RF24 IRQ pin interrupt
|
||||||
if((millis() - connection_last_established_at_ms) > (2*CONN_TIMEOUT)){
|
detachInterrupt(digitalPinToInterrupt(RF24_IRQ));
|
||||||
|
connection_available = false;
|
||||||
|
if((millis() - connection_last_established_at_ms) > (2*CONN_TIMEOUT_MS)){
|
||||||
keep_connection_off = false;
|
keep_connection_off = false;
|
||||||
//Serial.print("Connection ON allowed.");
|
// Attach the RF24 IRQ pin interrupt
|
||||||
|
attachInterrupt(digitalPinToInterrupt(RF24_IRQ), nrf24_isr, LOW );
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
//Serial.print("Connection OFF forced.");
|
// remove the RF24 connection flag if no data was received for longer time
|
||||||
}
|
if((millis() - connection_last_established_at_ms >= CONN_TIMEOUT_MS) || (connection_last_established_at_ms == 0)){
|
||||||
} else
|
connection_available = false;
|
||||||
{
|
Serial.println("ERROR: No connection established to TOPSTATION");
|
||||||
// check if radio data is available - if so read the data
|
} // radio available
|
||||||
if( radio.available()){
|
} // keep connection off
|
||||||
// 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
|
void update_offset_values(void){
|
||||||
}
|
|
||||||
connection_last_established_at_ms = millis();
|
float int_time_slope = 1.0;
|
||||||
connection_available = true;
|
signed long int_time_delta_x = 0;
|
||||||
current_time_offset = radio_data.topstationtime - millis(); // the offset between TOP_STATION and BASESTATION
|
signed long int_time_delta_y = 0;
|
||||||
/*
|
signed long int_time_offset_us = 0;
|
||||||
Serial.print("Current time on host in millis:");
|
unsigned long int_current_bot_time_us = 0;
|
||||||
Serial.print(millis());
|
unsigned long int_calc_bot_time_us = 0;
|
||||||
Serial.print(" Current time on client in millis: ");
|
unsigned long int_current_top_time_us = 0;
|
||||||
Serial.println(radio_data.topstationtime);
|
signed long int_current_calc2real_offset = 0;
|
||||||
Serial.print("Offset is: ");
|
|
||||||
Serial.println(current_time_offset);
|
if((new_current_offset_available == true) && // there is a new value
|
||||||
Serial.print(" Button was pressed last time on client in millis: ");
|
(last_top_time_us != 0) && // the last top time is updated already
|
||||||
Serial.println(radio_data.topbuttonpressedtime);
|
(current_top_time_us != 0) && // the current top time is updated
|
||||||
*/
|
(last_bottom_time_us != 0) && // the last bottom time is updated
|
||||||
|
(current_bottom_time_us != 0)) // the current bottom time is updated
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
//calculate the last and the current offset based on what we got from Topstation
|
||||||
|
int_current_bot_time_us = current_bottom_time_us;
|
||||||
|
int_time_delta_y = current_bottom_time_us-last_bottom_time_us;
|
||||||
|
int_time_delta_x = current_top_time_us-last_top_time_us;
|
||||||
|
new_current_offset_available = false;
|
||||||
|
|
||||||
// offset calculation ... only needed if the variation is bigger than allowed or not enough values available already ...
|
|
||||||
if(counter_time_offset == 0){
|
if(counter_time_offset == 0){
|
||||||
// this is the initial setup to start with something - in this case the last offset value that was received
|
// 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;
|
int_current_calc2real_offset = 0;
|
||||||
|
} else {
|
||||||
|
int_calc_bot_time_us = calc_top2bot_time(current_top_time_us);
|
||||||
|
int_current_calc2real_offset = int_calc_bot_time_us - int_current_bot_time_us;
|
||||||
|
//Serial.print("Counter:");
|
||||||
|
//Serial.println(counter_time_offset);
|
||||||
|
//Serial.print("Calculated bot time:");
|
||||||
|
//Serial.println(int_calc_bot_time_us);
|
||||||
|
//Serial.print("Real bot time:");
|
||||||
|
//Serial.println(int_current_bot_time_us);
|
||||||
|
Serial.print("So offset between calc and Real bot time:");
|
||||||
|
Serial.println(abs(int_current_calc2real_offset));
|
||||||
|
// Serial.print("function offset:");
|
||||||
|
//Serial.println(mean_time_offset_us);
|
||||||
|
//Serial.print("function slope:");
|
||||||
|
//Serial.println((float)mean_time_slope);
|
||||||
}
|
}
|
||||||
// check current offset of the TOP_STATIOn and the BASESTATION if more than allowed ...
|
// 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(abs(int_current_calc2real_offset) < MAX_DIFFERENCE_OFFSET_US){
|
||||||
// if the current value is in range - decrease the fail counter by 1 if it was not zero already
|
// if the current value is in range - decrease the fail counter by 1 if it was not zero already
|
||||||
if(failed_offsets > 0){
|
if(failed_offsets > 0){
|
||||||
//Serial.println("INFO: The last received TOPSTATION offset time stamp was again in range. Decrease internal fail counter");
|
Serial.println("INFO: The last received TOPSTATION offset time stamp was again in range. Decrease internal fail counter");
|
||||||
failed_offsets--;
|
failed_offsets--;
|
||||||
}
|
}
|
||||||
// the offset is in range - check if we have already enough values of if we need to add more ...
|
// 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){
|
if(counter_time_offset <= REQUIRED_NUMBER_MEANVALS){
|
||||||
//add the next value to meanvalue calculation ...
|
//add the next value to meanvalue calculation ...
|
||||||
sum_time_offset = sum_time_offset + current_time_offset;
|
int_time_slope = (float)(int_time_delta_y / int_time_delta_x);
|
||||||
|
int_time_offset_us = current_bottom_time_us - (int_time_slope*current_top_time_us);
|
||||||
|
|
||||||
|
//Serial.print(" offset is: ");
|
||||||
|
//Serial.print(int_time_offset_us);
|
||||||
|
//Serial.print(" int_time_delta_y:");
|
||||||
|
//Serial.print(int_time_delta_y);
|
||||||
|
//Serial.print(" int_time_delta_x:");
|
||||||
|
//Serial.print(int_time_delta_x);
|
||||||
|
//Serial.print(" int_time_slope:");
|
||||||
|
//Serial.println(int_time_slope);
|
||||||
|
|
||||||
|
sum_time_offset_us = sum_time_offset_us + int_time_offset_us;
|
||||||
|
sum_time_slope = sum_time_slope + int_time_slope;
|
||||||
counter_time_offset++;
|
counter_time_offset++;
|
||||||
mean_time_offset = sum_time_offset/counter_time_offset;
|
mean_time_offset_us = sum_time_offset_us/counter_time_offset;
|
||||||
|
mean_time_slope = sum_time_slope/counter_time_offset;
|
||||||
Serial.print("Offset calulation. We have ");
|
Serial.print("Offset calulation. We have ");
|
||||||
Serial.print(counter_time_offset);
|
Serial.print(counter_time_offset);
|
||||||
Serial.print("/");
|
Serial.print("/");
|
||||||
Serial.print(REQUIRED_NUMBER_MEANVALS);
|
Serial.print(REQUIRED_NUMBER_MEANVALS);
|
||||||
Serial.print(" values. Mean offset value based on that is: ");
|
Serial.print(" values. y=slope*x+offset. Mean offset value based on that is: ");
|
||||||
Serial.println(mean_time_offset);
|
Serial.print(mean_time_offset_us);
|
||||||
|
Serial.print(" mean slope: ");
|
||||||
|
Serial.println(mean_time_slope);
|
||||||
} else {
|
} else {
|
||||||
time_offset_ok = true;
|
time_offset_ok = true;
|
||||||
}
|
}
|
||||||
|
@ -524,7 +627,7 @@ void receive_values(void){
|
||||||
// the current offset is out of range ...
|
// 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 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){
|
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");
|
Serial.println("WARNING: The last received TOPSTATION offset time stamp was out of range. Increase internal fail counter");
|
||||||
failed_offsets++;
|
failed_offsets++;
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
|
@ -542,20 +645,18 @@ void receive_values(void){
|
||||||
//Serial.println(mean_time_offset);
|
//Serial.println(mean_time_offset);
|
||||||
time_offset_ok = false;
|
time_offset_ok = false;
|
||||||
counter_time_offset = 0;
|
counter_time_offset = 0;
|
||||||
sum_time_offset = 0;
|
sum_time_offset_us = 0;
|
||||||
mean_time_offset = 0;
|
sum_time_slope = 0;
|
||||||
|
mean_time_offset_us = 0;
|
||||||
|
mean_time_slope = 0;
|
||||||
failed_offsets = 0;
|
failed_offsets = 0;
|
||||||
} // out of range counter exceeds maximum value
|
} // out of range counter exceeds maximum value
|
||||||
} // time offset of TOPSTATION out of range
|
} // time offset of TOPSTATION out of range
|
||||||
|
} else {
|
||||||
|
new_current_offset_available = false;
|
||||||
}
|
}
|
||||||
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");
|
|
||||||
}
|
|
||||||
} // radio available
|
|
||||||
} // keep connection off
|
|
||||||
}// receive values
|
}// receive values
|
||||||
|
|
||||||
void update_screen(timer_state_e state){
|
void update_screen(timer_state_e state){
|
||||||
|
@ -567,7 +668,7 @@ void update_screen(timer_state_e state){
|
||||||
|
|
||||||
char string_to_char[50];
|
char string_to_char[50];
|
||||||
|
|
||||||
float curr_time_local = 0.0;
|
signed long curr_time_local_s = 0;
|
||||||
|
|
||||||
switch(state){
|
switch(state){
|
||||||
case TIMER_NOCONNECTION:
|
case TIMER_NOCONNECTION:
|
||||||
|
@ -582,27 +683,27 @@ void update_screen(timer_state_e state){
|
||||||
break;
|
break;
|
||||||
case TIMER_IDLE:
|
case TIMER_IDLE:
|
||||||
header = "Idle!";
|
header = "Idle!";
|
||||||
content = "00.00 sec";
|
content = "00.000 sec";
|
||||||
footer = "Waiting for climber";
|
footer = "Waiting for climber";
|
||||||
break;
|
break;
|
||||||
case TIMER_READY:
|
case TIMER_READY:
|
||||||
header = "Ready!";
|
header = "Ready!";
|
||||||
content = "00.00 sec";
|
content = "00.000 sec";
|
||||||
footer = "Waiting for start";
|
footer = "Waiting for start";
|
||||||
break;
|
break;
|
||||||
case TIMER_STARTED:
|
case TIMER_STARTED:
|
||||||
header = "Starting ...";
|
header = "Starting ...";
|
||||||
content = "00.00 sec";
|
content = "00.000 sec";
|
||||||
footer = "...";
|
footer = "...";
|
||||||
break;
|
break;
|
||||||
case TIMER_RUNNING:
|
case TIMER_RUNNING:
|
||||||
header = "Running ...";
|
header = "Running ...";
|
||||||
curr_time_local = (millis() - start_time)/1000.000;
|
curr_time_local_s = (micros() - start_time_us);
|
||||||
content = curr_time_local;
|
content = micros2string(curr_time_local_s);
|
||||||
content += " sec";
|
content += " sec";
|
||||||
curr_time_local = (runner_start_time - start_time)/1000.000;
|
curr_time_local_s = (runner_start_time_us - start_time_us);
|
||||||
footer = "Reaction time: ";
|
footer = "Reaction time: ";
|
||||||
footer += curr_time_local;
|
footer += micros2string(curr_time_local_s);
|
||||||
footer += " sec";
|
footer += " sec";
|
||||||
break;
|
break;
|
||||||
case TIMER_CANCELLED:
|
case TIMER_CANCELLED:
|
||||||
|
@ -610,12 +711,12 @@ void update_screen(timer_state_e state){
|
||||||
break;
|
break;
|
||||||
case TIMER_STOPPED:
|
case TIMER_STOPPED:
|
||||||
header = "Stopped!";
|
header = "Stopped!";
|
||||||
curr_time_local = run_time/1000.000;
|
curr_time_local_s = run_time_us;
|
||||||
content = curr_time_local;
|
content = micros2string(curr_time_local_s);
|
||||||
content += " sec";
|
content += " sec";
|
||||||
curr_time_local = (runner_start_time - start_time)/1000.000;
|
curr_time_local_s = (runner_start_time_us - start_time_us);
|
||||||
footer = "Reaction time: ";
|
footer = "Reaction time: ";
|
||||||
footer += curr_time_local;
|
footer += micros2string(curr_time_local_s);
|
||||||
footer += " sec";
|
footer += " sec";
|
||||||
break;
|
break;
|
||||||
case TIMER_TIMEDOUT:
|
case TIMER_TIMEDOUT:
|
||||||
|
@ -624,8 +725,8 @@ void update_screen(timer_state_e state){
|
||||||
break;
|
break;
|
||||||
case TIMER_FAIL:
|
case TIMER_FAIL:
|
||||||
header = "False start!";
|
header = "False start!";
|
||||||
curr_time_local = (start_time - runner_start_time)/1000.000;
|
curr_time_local_s = (start_time_us - runner_start_time_us);
|
||||||
content = curr_time_local;
|
content = micros2string(curr_time_local_s);
|
||||||
footer = "seconds too early";
|
footer = "seconds too early";
|
||||||
break;
|
break;
|
||||||
case TIMER_SETTINGS:
|
case TIMER_SETTINGS:
|
||||||
|
@ -721,9 +822,9 @@ void failSequence(void){
|
||||||
// first tone
|
// first tone
|
||||||
if(failsequence_count <FAILSEQ_STEPS){
|
if(failsequence_count <FAILSEQ_STEPS){
|
||||||
// play the tone ...
|
// play the tone ...
|
||||||
tone( PIEZO_PIN, FAILSEQ_NOTES[failsequence_count],FAILSEQ_DURATION[failsequence_count] );
|
tone( PIEZO_PIN, FAILSEQ_NOTES[failsequence_count],FAILSEQ_DURATION_MS[failsequence_count] );
|
||||||
if(failsequence_count > 0){
|
if(failsequence_count > 0){
|
||||||
Timer1.setPeriod(FAILSEQ_PAUSE[failsequence_count]);
|
Timer1.setPeriod(FAILSEQ_PAUSE_US[failsequence_count]);
|
||||||
}
|
}
|
||||||
// increase the counter
|
// increase the counter
|
||||||
failsequence_count++;
|
failsequence_count++;
|
||||||
|
@ -739,7 +840,7 @@ void stop_isr(void){
|
||||||
// this is the interrupt routine for the topstation STOP button
|
// this is the interrupt routine for the topstation STOP button
|
||||||
// this will save the time when the runner has pushed the button
|
// this will save the time when the runner has pushed the button
|
||||||
if(timer_state == TIMER_IDLE){
|
if(timer_state == TIMER_IDLE){
|
||||||
radio_data.topbuttonpressedtime = millis();
|
radio_data.topbuttonpressedtime_us = micros();
|
||||||
//Serial.print(radio_data.topbuttonpressedtime);
|
//Serial.print(radio_data.topbuttonpressedtime);
|
||||||
//Serial.println(" ms <- current time ** stop_ISR ** stop button pushed: ");
|
//Serial.println(" ms <- current time ** stop_ISR ** stop button pushed: ");
|
||||||
topbuttonwaspressed = true;
|
topbuttonwaspressed = true;
|
||||||
|
@ -750,7 +851,7 @@ void false_start_isr(void) {
|
||||||
// this is the interrupt routine for the FALSESTART button
|
// this is the interrupt routine for the FALSESTART button
|
||||||
// this will save the time when the runner is really started
|
// this will save the time when the runner is really started
|
||||||
if(timer_new_state != TIMER_READY){
|
if(timer_new_state != TIMER_READY){
|
||||||
runner_start_time = millis();
|
runner_start_time_us = micros();
|
||||||
//Serial.print(runner_start_time);
|
//Serial.print(runner_start_time);
|
||||||
//Serial.println(" ms <- current time ** false_start_ISR ** false start button released: ");
|
//Serial.println(" ms <- current time ** false_start_ISR ** false start button released: ");
|
||||||
if(false == startsequence_done){
|
if(false == startsequence_done){
|
||||||
|
@ -773,8 +874,8 @@ void start_isr(void){
|
||||||
if(startsequence_count > 0){
|
if(startsequence_count > 0){
|
||||||
// play the tone ...
|
// play the tone ...
|
||||||
//Serial.println(STARTSEQ_DURATION[startsequence_count]);
|
//Serial.println(STARTSEQ_DURATION[startsequence_count]);
|
||||||
tone( PIEZO_PIN, STARTSEQ_NOTES[startsequence_count],STARTSEQ_DURATION[startsequence_count] );
|
tone( PIEZO_PIN, STARTSEQ_NOTES[startsequence_count],STARTSEQ_DURATION_MS[startsequence_count] );
|
||||||
Timer1.setPeriod(STARTSEQ_PAUSE[startsequence_count]);
|
Timer1.setPeriod(STARTSEQ_PAUSE_US[startsequence_count]);
|
||||||
}
|
}
|
||||||
// increase the counter
|
// increase the counter
|
||||||
startsequence_count++;
|
startsequence_count++;
|
||||||
|
@ -791,21 +892,21 @@ void start_isr(void){
|
||||||
}
|
}
|
||||||
|
|
||||||
void send_values(void){
|
void send_values(void){
|
||||||
if(offset_sync_sequence || topbuttonwaspressed || ((millis()-radio_data.topstationtime) >= MIN_DELAY_BETWEEN_SEND_MS)){
|
if((((micros()-radio_data.topstationtime_us) > MIN_DELAY_BETWEEN_SEND_US) && (offset_sync_sequence || topbuttonwaspressed)) || ((micros()-radio_data.topstationtime_us) >= MAX_DELAY_BETWEEN_SEND_US)){
|
||||||
// store current millis to be send as reference ...
|
// store current millis to be send as reference ...
|
||||||
radio_data.topstationtime = millis(); // set the current milli second count
|
radio_data.topstationtime_us = micros(); // set the current micro second count
|
||||||
//Serial.print("senddate_to_base at:");
|
//Serial.print("senddate_to_base at:");
|
||||||
//Serial.println(millis());
|
//Serial.println(millis());
|
||||||
//Serial.print(" -> topstationtime:");
|
//Serial.print(" -> topstationtime:");
|
||||||
//Serial.print(radio_data.topstationtime);
|
//Serial.print(radio_data.topstationtime_us);
|
||||||
//Serial.print("ms stoppressedtime:");
|
//Serial.print("us stoppressedtime:");
|
||||||
//Serial.print(radio_data.topbuttonpressedtime);
|
//Serial.print(radio_data.topbuttonpressedtime_us);
|
||||||
//Serial.print("ms offset counter value :");
|
//Serial.print("us offset counter value :");
|
||||||
//Serial.println(counter_time_offset);
|
//Serial.println(counter_time_offset);
|
||||||
|
|
||||||
// send data ...
|
// send data ...
|
||||||
if (!radio.write(&radio_data,sizeof(radio_data))){ // Send the counter variable to the other radio
|
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))){
|
if(((millis() - connection_last_established_at_ms) >= (CONN_TIMEOUT_MS-100))){
|
||||||
connection_available = false;
|
connection_available = false;
|
||||||
//Serial.println("Failed to send data to BASESSTATION ... will retry");
|
//Serial.println("Failed to send data to BASESSTATION ... will retry");
|
||||||
} else {
|
} else {
|
||||||
|
@ -822,7 +923,7 @@ void send_values(void){
|
||||||
connection_last_established_at_ms = millis();
|
connection_last_established_at_ms = millis();
|
||||||
connection_available = true;
|
connection_available = true;
|
||||||
// check offset sync counter ...
|
// check offset sync counter ...
|
||||||
if(counter_time_offset < (4*REQUIRED_NUMBER_MEANVALS)){
|
if(counter_time_offset < (2*REQUIRED_NUMBER_MEANVALS)){
|
||||||
counter_time_offset++;
|
counter_time_offset++;
|
||||||
} else {
|
} else {
|
||||||
// offset sync done
|
// offset sync done
|
||||||
|
@ -833,4 +934,12 @@ void send_values(void){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String micros2string(signed long microsecs){
|
||||||
|
char buf[32] = "";
|
||||||
|
String bufstring;
|
||||||
|
sprintf(buf, "%032d", microsecs);
|
||||||
|
sprintf(buf, "%c%c:%c%c%c", buf[24],buf[25],buf[26],buf[27],buf[28]);
|
||||||
|
bufstring = (String)buf;
|
||||||
|
return bufstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Reference in a new issue