diff --git a/pitch.h b/pitch.h new file mode 100644 index 0000000..55c7d54 --- /dev/null +++ b/pitch.h @@ -0,0 +1,95 @@ +/************************************************* + * Public Constants + *************************************************/ + +#define NOTE_B0 31 +#define NOTE_C1 33 +#define NOTE_CS1 35 +#define NOTE_D1 37 +#define NOTE_DS1 39 +#define NOTE_E1 41 +#define NOTE_F1 44 +#define NOTE_FS1 46 +#define NOTE_G1 49 +#define NOTE_GS1 52 +#define NOTE_A1 55 +#define NOTE_AS1 58 +#define NOTE_B1 62 +#define NOTE_C2 65 +#define NOTE_CS2 69 +#define NOTE_D2 73 +#define NOTE_DS2 78 +#define NOTE_E2 82 +#define NOTE_F2 87 +#define NOTE_FS2 93 +#define NOTE_G2 98 +#define NOTE_GS2 104 +#define NOTE_A2 110 +#define NOTE_AS2 117 +#define NOTE_B2 123 +#define NOTE_C3 131 +#define NOTE_CS3 139 +#define NOTE_D3 147 +#define NOTE_DS3 156 +#define NOTE_E3 165 +#define NOTE_F3 175 +#define NOTE_FS3 185 +#define NOTE_G3 196 +#define NOTE_GS3 208 +#define NOTE_A3 220 +#define NOTE_AS3 233 +#define NOTE_B3 247 +#define NOTE_C4 262 +#define NOTE_CS4 277 +#define NOTE_D4 294 +#define NOTE_DS4 311 +#define NOTE_E4 330 +#define NOTE_F4 349 +#define NOTE_FS4 370 +#define NOTE_G4 392 +#define NOTE_GS4 415 +#define NOTE_A4 440 +#define NOTE_AS4 466 +#define NOTE_B4 494 +#define NOTE_C5 523 +#define NOTE_CS5 554 +#define NOTE_D5 587 +#define NOTE_DS5 622 +#define NOTE_E5 659 +#define NOTE_F5 698 +#define NOTE_FS5 740 +#define NOTE_G5 784 +#define NOTE_GS5 831 +#define NOTE_A5 880 +#define NOTE_AS5 932 +#define NOTE_B5 988 +#define NOTE_C6 1047 +#define NOTE_CS6 1109 +#define NOTE_D6 1175 +#define NOTE_DS6 1245 +#define NOTE_E6 1319 +#define NOTE_F6 1397 +#define NOTE_FS6 1480 +#define NOTE_G6 1568 +#define NOTE_GS6 1661 +#define NOTE_A6 1760 +#define NOTE_AS6 1865 +#define NOTE_B6 1976 +#define NOTE_C7 2093 +#define NOTE_CS7 2217 +#define NOTE_D7 2349 +#define NOTE_DS7 2489 +#define NOTE_E7 2637 +#define NOTE_F7 2794 +#define NOTE_FS7 2960 +#define NOTE_G7 3136 +#define NOTE_GS7 3322 +#define NOTE_A7 3520 +#define NOTE_AS7 3729 +#define NOTE_B7 3951 +#define NOTE_C8 4186 +#define NOTE_CS8 4435 +#define NOTE_D8 4699 +#define NOTE_DS8 4978 + + diff --git a/speedclock.h b/speedclock.h index e1fa5bd..07d099a 100644 --- a/speedclock.h +++ b/speedclock.h @@ -2,13 +2,19 @@ #ifndef Remote_Control_transceiver_H #define Remote_Control_transceiver_H -//-------------- defines fpr the radio devices NRF24 --------------------------------------------------------- +//-------------- defines for the radio devices NRF24 --------------------------------------------------------- + +#define STATION_SEL0 9 // this 9 for Nano +#define STATION_SEL1 10 // this 10 for Nano -#define STATION_SEL 4 // this 4 for Nano 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 +//--------------- defines for the I2C +//#define SCL A5 // I2C clock pin +//#define SDA A4 // I2C data pin + //--------------- define the structure and type of data that sender and receiver will exchange ---------------- typedef struct transcv_struct{ @@ -17,18 +23,20 @@ typedef struct transcv_struct{ }transcv_s; -#define STOPBUTTON_IN D2 // this is the input for the button +#define STOPBUTTON_IN 2 // this is the input for the button #define STOPBUTTON_PRESSED HIGH // this the signal level the top button will be at as soon as pressed #define MIN_DELAY_BETWEEN_PRESSED_MS 1000 // this defines the time in milliseconds before the button is expected to be pressed again. We do this to avaoid keybouncing #define MIN_DELAY_BETWEEN_SEND_MS 1000 // this defines the time in milliseconds before the next set of data will be send to the base station - except the button was pressed. -#define STARTBUTTON_IN D4 // start button +#define STARTBUTTON_IN 4 // start button #define STARTBUTTON_PRESSED LOW -#define CHANCELBUTTON_IN D2 // chancle button -#define CHANCELBUTTON_PRESSED LOW -#define FAILSTARTBUTTON_IN D3 // fail start button +#define CANCELBUTTON_IN 2 // chancle button +#define CANCELBUTTON_PRESSED LOW +#define FAILSTARTBUTTON_IN 3 // fail start button #define FAILSTARTBUTTON_PRESSED LOW +#define PIEZO_PIN 6 // piezo speaker + #define WARN_LED A1 // yellow warn LED #define WARN_LED_ON HIGH #define WARN_LED_OFF LOW @@ -43,29 +51,46 @@ typedef struct transcv_struct{ #define RUN_LED_OFF LOW -typedef enum {TIMER_INIT = 0, TIMER_READY, TIMER_STARTED, TIMER_RUNNING , TIMER_CHANCELED, TIMER_STOPPED, TIMER_TIMEDOUT, TIMER_FAIL, TIMER_WAIT} timer_state_e; +typedef enum {TIMER_INIT = 0, TIMER_READY, TIMER_STARTED, TIMER_RUNNING , TIMER_CANCELLED, TIMER_STOPPED, TIMER_TIMEDOUT, TIMER_FAIL, TIMER_WAIT} timer_state_e; // READY_LED, WARN_LED, RUN_LED, FAIL_LED const float LEDStates[][3] = { - TIMER_INIT = {READY_LED_OFF, 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_CHANCELED = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON}, - TIMER_STOPPED = {READY_LED_ON, RUN_LED_ON, FAIL_LED_OFF}, - TIMER_TIMEDOUT = {READY_LED_OFF, RUN_LED_ON, FAIL_LED_ON}, - TIMER_FAIL = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON} -} + [TIMER_INIT] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_OFF}, + [TIMER_READY] = {READY_LED_ON, RUN_LED_OFF, FAIL_LED_OFF}, + [TIMER_STARTED] = {READY_LED_ON, RUN_LED_ON, FAIL_LED_OFF}, + [TIMER_RUNNING] = {READY_LED_OFF, RUN_LED_ON, FAIL_LED_OFF}, + [TIMER_CANCELLED] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON}, + [TIMER_STOPPED] = {READY_LED_ON, RUN_LED_ON, FAIL_LED_OFF}, + [TIMER_TIMEDOUT] = {READY_LED_OFF, RUN_LED_ON, FAIL_LED_ON}, + [TIMER_FAIL] = {READY_LED_OFF, RUN_LED_OFF, FAIL_LED_ON} +}; #define MAX_DIFFERENCE_OFFSET_MS 10 // 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 10 // we need at least this number of meanvalues to be ready to start a run -#define STARTSEQ_LENGTH_MS = 3100 // the length of the start sequence from the time the button was pressed ... includes the 3 tones -#define STARTSEQ_STARTPAUSE_MS = 1000 -#define STARTSEQ_TONEPAUSE_MS = 800 -#define STARTSEQ_TON_1_2_LENGTH_MS = 200 -#define STARTSEQ_TON_3_LENGTH_MS = 100 +#define STARTSEQ_LENGTH_MS 3100 // the length of the start sequence from the time the button was pressed ... includes the 3 tones +#define STARTSEQ_STARTPAUSE_MS 1000 +#define STARTSEQ_TONEPAUSE_MS 800 +#define STARTSEQ_TON_1_2_LENGTH_MS 200 +#define STARTSEQ_TON_1_2_FREQUENCY NOTE_G4 +#define STARTSEQ_TON_3_LENGTH_MS 100 +#define STARTSEQ_TON_3_FREQUENCY NOTE_C6 + +#define FAILSEQ_TONEPAUSE_MS 400 +#define FAILSEQ_TON_LENGTH_MS 300 +#define FAILSEQ_TON_FREQUENCY NOTE_G1 + +#define TIMER_MAX_TIME 99999 +#define TIMER_TIMEOUT 20000 + +//--------------------------------------- function declarations ---------------------------------------------- +void false_start_isr(void); +void update_screen(timer_state_e timer_state); +void set_state_LEDs(timer_state_e state, boolean warn); +void startSequence(void); +void update_statemassage(timer_state_e timer_state); +void failSequence(void); #endif diff --git a/speedclock.ino b/speedclock.ino index 7b440b0..24b3856 100644 --- a/speedclock.ino +++ b/speedclock.ino @@ -4,14 +4,17 @@ #include #include "RF24.h" #include "speedclock.h" +#include "pitch.h" // internal defines for the OLED display ... U8G2_SSD1306_128X64_NONAME_1_SW_I2C display(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display +//U8G2_SSD1306_128X64_NONAME_1_HW_I2C display(U8G2_R0,/* reset=*/ U8X8_PIN_NONE); // All Boards without Reset of the Display /****************** User Config for NRF24***************************/ /*** Set this radio as radio number RADIO0 or RADIO1 ***/ -radio_type_e radioNumber = BASESTATION; //---> TOPSTATION has the button connected +radio_type_e stationNumber = BASESTATION; //---> TOPSTATION has the button connected, BASESTATION is the default ... +uint8_t radio_sel0, radio_sel1; // code of type of station /* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */ RF24 radio(RF24_CNS,RF24_CE); @@ -24,15 +27,13 @@ unsigned long mean_time_offset = 0; // mean value for the offset unsigned long current_time_offset = 0; // current offset ... unsigned long running_time_offset = 0; // offset that will be used for this run ... unsigned long start_time = 0; // if the timer is running this is that start time ... +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 +signed long runner_run_time = 0; // this is the time the runner really needed or the time started to early - depending on sign ... unsigned long run_time = 0; // if the timer is running this is that start time ... boolean warn_during_run = false; // will be set to true if there is a warning during the run - usually an offset sync error -timer_state_e timer_state = TIMER_INIT; // timer needs to be initialized ... - // timer is ready to be started ... - // will be true if the timer was started - // will be true if the timer is running and the stopbutton was pressed at the TOPSTATION - // will be true if the timeout of the timer is reached - // will be true if the chancel button was pressed - e.g. in case of a early start +timer_state_e timer_state = TIMER_WAIT; // timer needs to be initialized ... +timer_state_e timer_new_state = TIMER_INIT; // timer needs to be initialized ... transcv_s radio_data; @@ -42,10 +43,10 @@ void setup(){ Serial.begin(115200); // this is the top button - will be pressed by the speed climber as soon she/he reaches the top ... - pinMode(STOPBUTTON_IN, INPUT); - pinMode(STARTBUTTON_IN, INPUT); - pinMode(CHANCELBUTTON_IN, INPUT); - pinMode(FAILSTARTBUTTON_IN, INPUT); + pinMode(STOPBUTTON_IN, INPUT_PULLUP); + pinMode(STARTBUTTON_IN, INPUT_PULLUP); + pinMode(CANCELBUTTON_IN, INPUT_PULLUP); + pinMode(FAILSTARTBUTTON_IN, INPUT_PULLUP); pinMode(WARN_LED, OUTPUT); pinMode(FAIL_LED, OUTPUT); @@ -53,12 +54,20 @@ void setup(){ // Get the station type (base or top) as set by the station select pin - BASESTATION is default - pinMode(STATION_SEL, INPUT); - Serial.print(F(" The station select pin (pin ")); - Serial.print(STATION_SEL); - Serial.print(F(") is set to level: ")); - Serial.println(RADIO_SEL); - if(digitalRead(RADIO_SEL) == HIGH){ + pinMode(STATION_SEL0, INPUT); + pinMode(STATION_SEL0, INPUT); + radio_sel0 = digitalRead(STATION_SEL0); + radio_sel1 = digitalRead(STATION_SEL1); + Serial.print(F(" The station select[1,0] pins (pin ")); + Serial.print(STATION_SEL0); + Serial.print(F(",")); + Serial.print(STATION_SEL1); + Serial.print(F(") are set to level: '")); + Serial.print(radio_sel0); + Serial.print(radio_sel1); + Serial.println("'"); + + if((radio_sel0 == 1) & (radio_sel1 == 0)){ stationNumber = TOPSTATION; Serial.print(F("The level of the station select pin makes the current node set to the TOPSTATION.")); } @@ -98,7 +107,7 @@ void loop(void) { // check for pressed button ... 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)){ + if(digitalRead(STOPBUTTON_IN) == STOPBUTTON_PRESSED){ // button was pressed - store the time radio_data.topbuttonpressedtime = millis(); topbuttonwaspressed = true; @@ -138,13 +147,13 @@ void loop(void) { // 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){ // 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 ... 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 already have ")) - Serial.print(counter_time_offset) + Serial.print(F("Offset calulation. We already have ")); + Serial.print(counter_time_offset); Serial.print(F(" of ")); Serial.print(REQUIRED_NUMBER_MEANVALS); Serial.print(F(" values used for offset calculation. Mean value of offset based on that is: ")); @@ -163,184 +172,273 @@ void loop(void) { mean_time_offset = 0; } + // set state to new_state + if(timer_state != timer_new_state){ + update_statemassage(timer_new_state); + } + timer_state = timer_new_state; // set LEDs set_state_LEDs(timer_state, warn_during_run ); switch(timer_state){ case TIMER_INIT: + update_screen(timer_state); // check if we are ready ... if(counter_time_offset > REQUIRED_NUMBER_MEANVALS){ // check if offset is OK - if not .. set state back to INIT - timer_state = TIMER_READY; + timer_new_state = TIMER_READY; } break; case TIMER_READY: + update_screen(timer_state); warn_during_run = false; if(counter_time_offset < REQUIRED_NUMBER_MEANVALS){ // check if offset is OK - if not .. set state back to INIT - timer_state = TIMER_INIT; + timer_new_state = TIMER_INIT; } else{ // check if the FALSESTATE button is pressed - somebody is ready to run ... - if(digitalRead(FAILSTARTBUTTON_IN, FAILSTARTBUTTON_PRESSED)){ + if(digitalRead(FAILSTARTBUTTON_IN) == FAILSTARTBUTTON_PRESSED){ //wait a few milliseconds to prevent keybouncing - this is a very simplistic method here delay(300); //read again and check if still active ... - if(digitalRead(FAILSTARTBUTTON_IN, FAILSTARTBUTTON_PRESSED)){ + if(digitalRead(FAILSTARTBUTTON_IN) == FAILSTARTBUTTON_PRESSED){ // check if the start button was pressed ... there is at least still someone waiting for the run . - if(digitalRead(STARTBUTTON_IN, STARTBUTTON_PRESSED)){ - timer_state = TIMER_STARTED; + if(digitalRead(STARTBUTTON_IN) == STARTBUTTON_PRESSED){ + // now enable the interrupt for the FALSESTART button + attachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN), false_start_isr, CHANGE); + timer_new_state = TIMER_STARTED; } } } } break; case TIMER_STARTED: - //enable the interrupt for the FALSESTART button and start the StartSequence - no interruption possible here anymore, except the FALSESTART button was released to early - - //initialize the start countdown here ... if done set to RUNNING ... maybe check fail start already here ... ?? or in running state ... or extra state ... + update_screen(timer_state); + //initialize the start countdown + timer_new_state = TIMER_RUNNING; startSequence(); - - case TIMER_FAILCHECK: - //check for fail start in this phase - interrupt is active, this state can only be reached from STARTED state ... - if(start_time - millis() >= STARTOK_TOLERANCETIME_MS) - { - timer_state = TIMER_RUNNING; - } break; - case TIMER_RUNNING: + case TIMER_RUNNING: + noTone(PIEZO_PIN); + update_screen(timer_state); if(counter_time_offset < REQUIRED_NUMBER_MEANVALS){ // check if offset is still OK - if not .. set state to TIMER_RUNNING warn_during_run = true; } - if(digitalRead(CHANCELBUTTON_IN, CHANCELBUTTON_PRESSED)){ - timer_state = TIMER_CHANCELED; + if(millis() - start_time > TIMER_TIMEOUT){ + timer_new_state = TIMER_TIMEDOUT; + } + if(digitalRead(CANCELBUTTON_IN) == CANCELBUTTON_PRESSED){ + timer_new_state = TIMER_CANCELLED; } if((radio_data.topbuttonpressedtime - running_time_offset) > millis()){ - timer_state = TIMER_STOPPED; - } + timer_new_state = TIMER_STOPPED; + } break; case TIMER_STOPPED: //calculate the run_time and switch to WAIT - - timer_state = TIMER_WAIT; + run_time = (radio_data.topbuttonpressedtime - running_time_offset) - start_time; + runner_run_time = runner_start_time - run_time; + update_screen(timer_state); + timer_new_state = TIMER_WAIT; break; case TIMER_FAIL: //fail start case .... - - timer_state = TIMER_WAIT; + failSequence(); + run_time = 99999; + runner_run_time = runner_start_time - start_time; + update_screen(timer_state); + timer_new_state = TIMER_WAIT; break; - case TIMER_CHANCELED: + case TIMER_CANCELLED: // what to do in chancel mode ? - - timer_state = TIMER_WAIT; + run_time = 99999; + runner_run_time = runner_start_time - start_time; + update_screen(timer_state); + timer_new_state = TIMER_WAIT; break; case TIMER_TIMEDOUT: - // - - timer_state = TIMER_WAIT; + // time out + run_time = millis() - start_time; + runner_run_time = runner_start_time - start_time; + update_screen(timer_state); + timer_new_state = TIMER_WAIT; break; case TIMER_WAIT: - // wait until the start button was pressed to go ahead - if(digitalRead(STARTBUTTON_IN, STARTBUTTON_PRESSED)){ - timer_state = TIMER_READY; + // disable interrupt if not already done + detachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN)); + // wait until the chancel button was pressed to go ahead + if(digitalRead(CANCELBUTTON_IN) == CANCELBUTTON_PRESSED){ + timer_new_state = TIMER_READY; } - break; } - int ypos = 64-42/2; - snprintf ( temp_string, sizeof(temp_string),"%d.%1d", int(client_data.temperature), int(abs(client_data.temperature - int(client_data.temperature))*10 + 0.5)); - Serial.println(temp_string); - - display.setFontPosCenter(); - display.setFont(u8g2_font_logisoso34_tn); - int xpos = (128-display.getStrWidth(temp_string))/2 - 10; - - display.firstPage(); - do { - display.setFont(u8g2_font_logisoso34_tn); - display.setCursor(xpos,ypos); - display.print(temp_string); - display.setCursor(xpos + display.getStrWidth(temp_string)+ 5,ypos-15); - display.setFont(u8g2_font_ncenB12_tr); - display.print(F("°C")); - } while ( display.nextPage() ); - } - - - -///////////////////// - - - - - if( radio.available(&pipeNo)){ - while( radio.available(&pipeNo)){ // Read all available payloads - radio.read( &control_data, sizeof(control_data) ); - } - - radio.stopListening(); // First, stop listening so we can talk - - Serial.print(F("Got remote data counter: ")); - Serial.print(control_data.counter); - Serial.print(F(" time: ")); - Serial.println(control_data.time); - radio_data.counter = control_data.counter + 1; // Ack payloads are much more efficient than switching to transmit mode to respond to a call - radio_data.time = control_data.time; - Serial.print(F("Loaded next response ")); - Serial.println(radio_data.counter); - - if( radio.write(&radio_data, sizeof(radio_data) )){ - Serial.println(F("Sending failed.")); // If no ack response, sending failed - //add error handling here if remote does not recieve the data anymore - } - - radio.startListening(); - - } - } + } } //####################### HELPER FUNCTIONS ########################### +void update_statemassage(timer_state_e timer_state){ + switch(timer_state){ + case TIMER_INIT: + Serial.println("*** TIMER_INIT ***"); + break; + case TIMER_READY: + Serial.println("*** TIMER_READY ***"); + break; + case TIMER_STARTED: + Serial.println("*** TIMER_STARTED ***"); + break; + case TIMER_RUNNING: + Serial.println("*** TIMER_RUNNING ***"); + break; + case TIMER_CANCELLED: + Serial.println("*** TIMER_CANCELLED ***"); + break; + case TIMER_STOPPED: + Serial.println("*** TIMER_STOPPED ***"); + break; + case TIMER_TIMEDOUT: + Serial.println("*** TIMER_TIMEDOUT ***"); + break; + case TIMER_FAIL: + Serial.println("*** TIMER_FAIL ***"); + break; + case TIMER_WAIT: + Serial.println("*** TIMER_WAIT ***"); + break; + default: + break; + } +} + +void update_screen(timer_state_e timer_state){ + bool scr_update = true; + int ypos = 64-42/2; + String top_line = "no state"; + char string_to_char[50]; + + switch(timer_state){ + case TIMER_INIT: + top_line = "Init"; + break; + case TIMER_READY: + top_line = "Ready!"; + break; + case TIMER_STARTED: + top_line = "Started ..."; + break; + case TIMER_RUNNING: + top_line = "Running ..."; + break; + case TIMER_CANCELLED: + top_line = "Cancelled!"; + break; + case TIMER_STOPPED: + top_line = "Stopped!"; + break; + case TIMER_TIMEDOUT: + top_line = "Time out!"; + break; + case TIMER_FAIL: + top_line = "False start!"; + break; + default: + scr_update = false; + break; + } + + if(scr_update == true){ + //snprintf( string_to_char, sizeof(string_to_char),"%s", top_line); + top_line.toCharArray(string_to_char, sizeof(string_to_char)); + //Serial.print("DISPLAY: "); + //Serial.println(string_to_char); + display.setFontPosCenter(); + display.setFont(u8g2_font_ncenB08_tr); + int xpos = (128 - (display.getStrWidth(string_to_char)))/2 - 10; + + display.firstPage(); + do { + display.setFont(u8g2_font_ncenB08_tr); + display.setCursor(xpos,ypos); + display.print(string_to_char); + } while ( display.nextPage() ); + } +} + void set_state_LEDs(timer_state_e state, boolean warn) { // 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]}; + 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}; + digitalWrite(WARN_LED, WARN_LED_ON); } else { - digitalWrite(WARN_LED, WARN_LED_OFF}; + digitalWrite(WARN_LED, WARN_LED_OFF); } } } void startSequence(void) { - // first - enable the interrupt - // set the startime - this is the current time plus the length of this sequence - start_time = millis() + STARTSEQ_LENGTH_MS; running_time_offset = mean_time_offset; - + start_time = millis() + STARTSEQ_LENGTH_MS; + Serial.print("Start time is: "); + Serial.println(start_time); // this is sequence of usually three tones after a wait time 1sec , in between the tones there is also a delay of 1 sec. Each tone is 200ms seconds long, except the last - delay(STARTSEQ_STARTPAUSE_MS); + if(timer_new_state == TIMER_RUNNING){ + delay(STARTSEQ_STARTPAUSE_MS); + } // first tone - - delay(STARTSEQ_TONEPAUSE_MS); + if(timer_new_state == TIMER_RUNNING){ + tone(PIEZO_PIN, STARTSEQ_TON_1_2_FREQUENCY,STARTSEQ_TON_1_2_LENGTH_MS ); + delay(STARTSEQ_TONEPAUSE_MS); + } //second tone - - delay(STARTSEQ_TONEPAUSE_MS); + if(timer_new_state == TIMER_RUNNING){ + tone(PIEZO_PIN, STARTSEQ_TON_1_2_FREQUENCY,STARTSEQ_TON_1_2_LENGTH_MS ); + delay(STARTSEQ_TONEPAUSE_MS); + } //third tone + if(timer_new_state == TIMER_RUNNING){ + tone(PIEZO_PIN, STARTSEQ_TON_3_FREQUENCY,STARTSEQ_TON_3_LENGTH_MS ); + } +} - // disable the interrupt and than +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); +} - +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(timer_state == TIMER_STARTED & timer_new_state == TIMER_STARTED){ + timer_new_state = TIMER_FAIL; + detachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN)); + noTone(PIEZO_PIN); + } else { + if(timer_state == TIMER_RUNNING | timer_new_state == TIMER_RUNNING ){ + // disable this interrupt; + detachInterrupt(digitalPinToInterrupt(FAILSTARTBUTTON_IN)); + } + } +}