2018-07-06 23:56:33 +02:00
# include <Arduino.h>
# include <U8g2lib.h>
//#include "fonts.h"
2018-07-07 19:27:47 +02:00
# include <Wire.h>
# include "SSD1306Ascii.h"
# include "SSD1306AsciiWire.h"
2018-07-06 23:56:33 +02:00
# include "RF24.h"
# include "speedclock.h"
2018-07-07 18:47:18 +02:00
# include "pitch.h"
2018-07-06 23:56:33 +02:00
// internal defines for the OLED display ...
2018-07-07 19:27:47 +02:00
SSD1306AsciiWire display ;
2018-07-06 23:56:33 +02:00
/****************** User Config for NRF24***************************/
/*** Set this radio as radio number RADIO0 or RADIO1 ***/
2018-07-07 18:47:18 +02:00
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
2018-07-06 23:56:33 +02:00
/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio ( RF24_CNS , RF24_CE ) ;
/**********************************************************/
byte addresses [ ] [ 12 ] = { " top_station " , " basestation " } ; // Radio pipe addresses for the 2 nodes to communicate.
unsigned long counter_time_offset = 0 ; // number of used values for the mean value calculation
2018-07-08 01:34:57 +02:00
signed long sum_time_offset = 0 ; // sum of offset values
signed long mean_time_offset = 0 ; // mean value for the offset
signed long current_time_offset = 0 ; // current offset ...
signed long running_time_offset = 0 ; // offset that will be used for this run ...
2018-07-06 23:56:33 +02:00
unsigned long start_time = 0 ; // if the timer is running this is that start time ...
2018-07-07 18:47:18 +02:00
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 ...
2018-07-06 23:56:33 +02:00
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
2018-07-08 10:20:54 +02:00
unsigned long connection_established = 0 ;
2018-07-06 23:56:33 +02:00
2018-07-08 01:34:57 +02:00
boolean topbuttonwaspressed = false ;
2018-07-07 23:50:28 +02:00
2018-07-08 10:20:54 +02:00
2018-07-07 18:47:18 +02:00
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 ...
2018-07-06 23:56:33 +02:00
transcv_s radio_data ;
void setup ( ) {
Serial . begin ( 115200 ) ;
// this is the top button - will be pressed by the speed climber as soon she/he reaches the top ...
2018-07-07 18:47:18 +02:00
pinMode ( STOPBUTTON_IN , INPUT_PULLUP ) ;
pinMode ( STARTBUTTON_IN , INPUT_PULLUP ) ;
pinMode ( CANCELBUTTON_IN , INPUT_PULLUP ) ;
pinMode ( FAILSTARTBUTTON_IN , INPUT_PULLUP ) ;
2018-07-06 23:56:33 +02:00
pinMode ( WARN_LED , OUTPUT ) ;
pinMode ( FAIL_LED , OUTPUT ) ;
pinMode ( READY_LED , OUTPUT ) ;
// Get the station type (base or top) as set by the station select pin - BASESTATION is default
2018-07-07 18:47:18 +02:00
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 ) ) {
2018-07-06 23:56:33 +02:00
stationNumber = TOPSTATION ;
2018-07-08 01:34:57 +02:00
Serial . println ( F ( " The level of the station select pin makes the current node set to the TOPSTATION. " ) ) ;
2018-07-06 23:56:33 +02:00
}
else {
2018-07-08 01:34:57 +02:00
Serial . println ( F ( " The level of the station select pin makes the current node set to the BASESTATION " ) ) ;
2018-07-06 23:56:33 +02:00
}
// Setup and configure the NRF radio
// radio setup ...
radio . begin ( ) ;
radio . setRetries ( 15 , 15 ) ; //the first is the time between reties in multiple of 250ms, the second is the numer of attempts
if ( stationNumber = = TOPSTATION ) {
radio . openWritingPipe ( addresses [ 1 ] ) ; // Both radios listen on the same pipes by default, but opposite addresses
radio . openReadingPipe ( 1 , addresses [ 0 ] ) ; // Open a reading pipe on address 0, pipe 1
radio . stopListening ( ) ; // top station will never receive data.
} else {
radio . openWritingPipe ( addresses [ 0 ] ) ;
radio . openReadingPipe ( 1 , addresses [ 1 ] ) ;
2018-07-08 01:34:57 +02:00
radio . startListening ( ) ;
2018-07-06 23:56:33 +02:00
}
2018-07-08 01:34:57 +02:00
2018-07-06 23:56:33 +02:00
radio_data . topstationtime = millis ( ) ; // set the current milli second count
radio_data . topbuttonpressedtime = 0 ; // set the time the button was pressed last time to 0
2018-07-07 19:27:47 +02:00
//initialise Wire and OLED
Wire . begin ( ) ;
Wire . setClock ( 400000L ) ;
2018-07-06 23:56:33 +02:00
2018-07-07 19:27:47 +02:00
display . begin ( & Adafruit128x64 , DISPLAY_I2C_ADDRESS ) ;
display . clear ( ) ;
2018-07-06 23:56:33 +02:00
}
void loop ( void ) {
/****************** 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.
2018-07-08 01:34:57 +02:00
2018-07-06 23:56:33 +02:00
// check for pressed button ...
2018-07-08 01:34:57 +02:00
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 ;
Serial . print ( " Stopp button was pressed at: " ) ;
Serial . println ( radio_data . topbuttonpressedtime ) ;
digitalWrite ( RUN_LED , RUN_LED_ON ) ;
}
}
} else {
if ( digitalRead ( STOPBUTTON_IN ) ! = STOPBUTTON_PRESSED ) {
topbuttonwaspressed = false ;
digitalWrite ( RUN_LED , RUN_LED_OFF ) ;
2018-07-06 23:56:33 +02:00
}
}
2018-07-08 01:34:57 +02:00
2018-07-06 23:56:33 +02:00
// 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 ) ) {
// store current millis to be send as reference ...
radio_data . topstationtime = millis ( ) ; // set the current milli second count
2018-07-08 01:34:57 +02:00
Serial . print ( millis ( ) ) ;
Serial . print ( " ms - Send data to bottom station: topstationtime: " ) ;
Serial . print ( radio_data . topstationtime ) ;
Serial . print ( " stoppressedtime: " ) ;
Serial . print ( radio_data . topbuttonpressedtime ) ;
if ( topbuttonwaspressed )
{
Serial . println ( " .Stopp button was pressed. " ) ;
}
else {
Serial . println ( " .Stopp button was NOT pressed. " ) ;
}
2018-07-06 23:56:33 +02:00
// 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 " ) ) ;
2018-07-08 01:34:57 +02:00
digitalWrite ( FAIL_LED , FAIL_LED_ON ) ;
digitalWrite ( READY_LED , READY_LED_OFF ) ;
}
else
{
Serial . println ( " Data sent to BASESSTATION " ) ;
digitalWrite ( FAIL_LED , FAIL_LED_OFF ) ;
digitalWrite ( READY_LED , READY_LED_ON ) ;
}
2018-07-06 23:56:33 +02:00
}
}
/****************** Code for the BASESTATION is here - the display and the start button is connected here. All caclulation will be done here ***************************/
if ( stationNumber = = BASESTATION ) {
2018-07-08 01:34:57 +02:00
byte pipeNo ;
2018-07-06 23:56:33 +02:00
// read data from TOP_STATION ...
if ( radio . available ( ) ) {
// check if radio data is available - if so read the data
2018-07-08 10:20:54 +02:00
connection_established = millis ( ) ;
2018-07-08 01:34:57 +02:00
while ( radio . available ( & pipeNo ) ) { // Read all available payloads
radio . read ( & radio_data , sizeof ( radio_data ) ) ; // Read the data the TOPSTATION sent
}
2018-07-06 23:56:33 +02:00
current_time_offset = radio_data . topstationtime - millis ( ) ; // the offset between TOP_STATION and BASESTATION
2018-07-08 01:34:57 +02:00
Serial . print ( " Current time on host in millis: " ) ;
Serial . print ( millis ( ) ) ;
2018-07-06 23:56:33 +02:00
Serial . print ( F ( " Current time on client in millis: " ) ) ;
Serial . println ( radio_data . topstationtime ) ;
2018-07-08 01:34:57 +02:00
Serial . print ( " Offset is: " ) ;
Serial . println ( current_time_offset ) ;
2018-07-06 23:56:33 +02:00
Serial . print ( F ( " Button was pressed last time on client in millis: " ) ) ;
2018-07-08 01:34:57 +02:00
Serial . println ( radio_data . topbuttonpressedtime ) ;
2018-07-06 23:56:33 +02:00
}
// offset calculation ... only needed if the variation is bigger than allowed or not enough values available already ...
// check current offset of the TOP_STATIOn and the BASESTATION if more than allowed ...
2018-07-08 01:34:57 +02:00
if ( counter_time_offset = = 0 ) {
mean_time_offset = current_time_offset ;
}
2018-07-06 23:56:33 +02:00
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 ...
2018-07-07 18:47:18 +02:00
if ( counter_time_offset < = REQUIRED_NUMBER_MEANVALS ) {
2018-07-06 23:56:33 +02:00
//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 ;
2018-07-07 18:47:18 +02:00
Serial . print ( F ( " Offset calulation. We already have " ) ) ;
Serial . print ( counter_time_offset ) ;
2018-07-06 23:56:33 +02:00
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: " ) ) ;
Serial . println ( mean_time_offset ) ;
}
} else {
// the current offset is out of range so we need to restart the mean calculation and set the timer to unready state ...
2018-07-08 01:34:57 +02:00
Serial . print ( " Difference current offset is " ) ;
Serial . println ( abs ( current_time_offset - mean_time_offset ) ) ;
2018-07-06 23:56:33 +02:00
Serial . print ( F ( " Will restart offset calculation because the variation of the current offset: " ) ) ;
Serial . print ( current_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 ) ;
counter_time_offset = 0 ;
sum_time_offset = 0 ;
mean_time_offset = 0 ;
}
2018-07-07 18:47:18 +02:00
// set state to new_state
if ( timer_state ! = timer_new_state ) {
2018-07-07 22:50:05 +02:00
update_statemessage ( timer_new_state ) ;
2018-07-07 18:47:18 +02:00
}
2018-07-07 22:50:05 +02:00
update_screen ( timer_new_state ) ;
2018-07-07 18:47:18 +02:00
timer_state = timer_new_state ;
2018-07-06 23:56:33 +02:00
// set LEDs
set_state_LEDs ( timer_state , warn_during_run ) ;
switch ( timer_state ) {
case TIMER_INIT :
// check if we are ready ...
if ( counter_time_offset > REQUIRED_NUMBER_MEANVALS ) {
// check if offset is OK - if not .. set state back to INIT
2018-07-07 22:50:05 +02:00
timer_new_state = TIMER_IDLE ;
2018-07-06 23:56:33 +02:00
}
break ;
2018-07-07 22:50:05 +02:00
case TIMER_IDLE :
2018-07-06 23:56:33 +02:00
warn_during_run = false ;
if ( counter_time_offset < REQUIRED_NUMBER_MEANVALS ) {
// check if offset is OK - if not .. set state back to INIT
2018-07-07 18:47:18 +02:00
timer_new_state = TIMER_INIT ;
2018-07-06 23:56:33 +02:00
}
else {
// check if the FALSESTATE button is pressed - somebody is ready to run ...
2018-07-07 18:47:18 +02:00
if ( digitalRead ( FAILSTARTBUTTON_IN ) = = FAILSTARTBUTTON_PRESSED ) {
2018-07-06 23:56:33 +02:00
//wait a few milliseconds to prevent keybouncing - this is a very simplistic method here
2018-07-07 22:50:05 +02:00
delay ( 10 ) ;
2018-07-06 23:56:33 +02:00
//read again and check if still active ...
2018-07-07 18:47:18 +02:00
if ( digitalRead ( FAILSTARTBUTTON_IN ) = = FAILSTARTBUTTON_PRESSED ) {
2018-07-07 22:50:05 +02:00
timer_new_state = TIMER_READY ;
2018-07-06 23:56:33 +02:00
}
}
}
break ;
2018-07-07 22:50:05 +02:00
case TIMER_READY :
if ( digitalRead ( FAILSTARTBUTTON_IN ) = = FAILSTARTBUTTON_PRESSED ) {
// check if the start button was pressed ... there is at least still someone waiting for the run .
if ( digitalRead ( STARTBUTTON_IN ) = = STARTBUTTON_PRESSED ) {
// now enable the interrupt for the FALSESTART button
attachInterrupt ( digitalPinToInterrupt ( FAILSTARTBUTTON_IN ) , false_start_isr , CHANGE ) ;
timer_new_state = TIMER_STARTED ;
}
}
else {
timer_new_state = TIMER_IDLE ;
}
break ;
2018-07-06 23:56:33 +02:00
case TIMER_STARTED :
2018-07-07 18:47:18 +02:00
//initialize the start countdown
timer_new_state = TIMER_RUNNING ;
2018-07-06 23:56:33 +02:00
startSequence ( ) ;
break ;
2018-07-07 18:47:18 +02:00
case TIMER_RUNNING :
noTone ( PIEZO_PIN ) ;
2018-07-06 23:56:33 +02:00
if ( counter_time_offset < REQUIRED_NUMBER_MEANVALS ) {
// check if offset is still OK - if not .. set state to TIMER_RUNNING
warn_during_run = true ;
}
2018-07-07 18:47:18 +02:00
if ( millis ( ) - start_time > TIMER_TIMEOUT ) {
timer_new_state = TIMER_TIMEDOUT ;
}
if ( digitalRead ( CANCELBUTTON_IN ) = = CANCELBUTTON_PRESSED ) {
timer_new_state = TIMER_CANCELLED ;
2018-07-06 23:56:33 +02:00
}
2018-07-08 01:57:34 +02:00
Serial . println ( radio_data . topbuttonpressedtime ) ;
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 ;
runner_run_time = runner_start_time - run_time ;
timer_new_state = TIMER_STOPPED ;
}
2018-07-07 18:47:18 +02:00
}
2018-07-06 23:56:33 +02:00
break ;
case TIMER_STOPPED :
//calculate the run_time and switch to WAIT
2018-07-07 23:13:48 +02:00
delay ( 10 ) ;
if ( digitalRead ( CANCELBUTTON_IN ) ! = CANCELBUTTON_PRESSED ) {
timer_new_state = TIMER_WAIT ;
}
2018-07-06 23:56:33 +02:00
break ;
case TIMER_FAIL :
//fail start case ....
2018-07-07 18:47:18 +02:00
failSequence ( ) ;
run_time = 99999 ;
runner_run_time = runner_start_time - start_time ;
2018-07-07 23:13:48 +02:00
delay ( 10 ) ;
if ( digitalRead ( CANCELBUTTON_IN ) ! = CANCELBUTTON_PRESSED ) {
timer_new_state = TIMER_WAIT ;
}
2018-07-06 23:56:33 +02:00
break ;
2018-07-07 18:47:18 +02:00
case TIMER_CANCELLED :
2018-07-06 23:56:33 +02:00
// what to do in chancel mode ?
2018-07-07 18:47:18 +02:00
run_time = 99999 ;
runner_run_time = runner_start_time - start_time ;
2018-07-07 23:13:48 +02:00
delay ( 10 ) ;
if ( digitalRead ( CANCELBUTTON_IN ) ! = CANCELBUTTON_PRESSED ) {
timer_new_state = TIMER_WAIT ;
}
2018-07-06 23:56:33 +02:00
break ;
case TIMER_TIMEDOUT :
2018-07-07 18:47:18 +02:00
// time out
run_time = millis ( ) - start_time ;
runner_run_time = runner_start_time - start_time ;
2018-07-07 23:13:48 +02:00
delay ( 10 ) ;
if ( digitalRead ( CANCELBUTTON_IN ) ! = CANCELBUTTON_PRESSED ) {
timer_new_state = TIMER_WAIT ;
}
2018-07-06 23:56:33 +02:00
break ;
case TIMER_WAIT :
2018-07-07 18:47:18 +02:00
// 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 ) {
2018-07-07 22:50:05 +02:00
timer_new_state = TIMER_IDLE ;
2018-07-06 23:56:33 +02:00
}
break ;
}
2018-07-07 18:47:18 +02:00
}
}
2018-07-06 23:56:33 +02:00
2018-07-07 18:47:18 +02:00
//####################### HELPER FUNCTIONS ###########################
2018-07-06 23:56:33 +02:00
2018-07-07 22:50:05 +02:00
void update_statemessage ( timer_state_e timer_state ) {
2018-07-07 18:47:18 +02:00
switch ( timer_state ) {
case TIMER_INIT :
Serial . println ( " *** TIMER_INIT *** " ) ;
break ;
2018-07-07 22:50:05 +02:00
case TIMER_IDLE :
Serial . println ( " *** TIMER_IDLE *** " ) ;
break ;
2018-07-07 18:47:18 +02:00
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 ;
}
2018-07-06 23:56:33 +02:00
}
2018-07-07 22:50:05 +02:00
void update_screen ( timer_state_e state ) {
2018-07-07 18:47:18 +02:00
bool scr_update = true ;
int ypos = 64 - 42 / 2 ;
2018-07-07 21:41:53 +02:00
String header = " no state " ;
String content = " " ;
String footer = " " ;
char header_to_char [ 50 ] ;
char content_to_char [ 50 ] ;
char footer_to_char [ 50 ] ;
2018-07-07 22:00:53 +02:00
2018-07-07 23:25:46 +02:00
float curr_time_local = 0.0 ;
2018-07-07 18:47:18 +02:00
2018-07-07 22:50:05 +02:00
switch ( state ) {
2018-07-07 18:47:18 +02:00
case TIMER_INIT :
2018-07-07 21:41:53 +02:00
header = " Init " ;
2018-07-07 22:00:53 +02:00
content = " ... " ;
footer = " please wait " ;
2018-07-07 18:47:18 +02:00
break ;
2018-07-07 22:50:05 +02:00
case TIMER_IDLE :
header = " Idle! " ;
2018-07-08 00:04:43 +02:00
content = " 00.00 sec " ;
2018-07-07 22:50:05 +02:00
footer = " Waiting for climber " ;
break ;
2018-07-07 18:47:18 +02:00
case TIMER_READY :
2018-07-07 21:41:53 +02:00
header = " Ready! " ;
2018-07-08 00:04:43 +02:00
content = " 00.00 sec " ;
2018-07-07 23:25:46 +02:00
footer = " Waiting for start " ;
2018-07-07 18:47:18 +02:00
break ;
case TIMER_STARTED :
2018-07-07 22:00:53 +02:00
header = " Starting ... " ;
2018-07-08 00:04:43 +02:00
content = " 00.00 sec " ;
2018-07-07 22:00:53 +02:00
footer = " ... " ;
2018-07-07 18:47:18 +02:00
break ;
case TIMER_RUNNING :
2018-07-07 21:41:53 +02:00
header = " Running ... " ;
2018-07-07 23:25:46 +02:00
curr_time_local = ( millis ( ) - start_time ) / 1000.000 ;
content = curr_time_local ;
2018-07-08 00:04:43 +02:00
content + = " sec " ;
2018-07-07 23:50:28 +02:00
curr_time_local = ( runner_start_time - start_time ) / 1000.000 ;
2018-07-08 00:04:43 +02:00
footer = " Reaction time: " ;
2018-07-07 23:50:28 +02:00
footer + = curr_time_local ;
2018-07-08 00:04:43 +02:00
footer + = " sec " ;
2018-07-07 18:47:18 +02:00
break ;
case TIMER_CANCELLED :
2018-07-07 21:41:53 +02:00
header = " Cancelled! " ;
2018-07-07 18:47:18 +02:00
break ;
case TIMER_STOPPED :
2018-07-07 21:41:53 +02:00
header = " Stopped! " ;
2018-07-08 01:57:34 +02:00
curr_time_local = run_time / 1000.000 ;
content = curr_time_local ;
content + = " sec " ;
curr_time_local = ( runner_start_time - start_time ) / 1000.000 ;
footer = " Reaction time: " ;
footer + = curr_time_local ;
footer + = " sec " ;
2018-07-07 18:47:18 +02:00
break ;
case TIMER_TIMEDOUT :
2018-07-08 01:57:34 +02:00
header = " Timed out! " ;
2018-07-08 00:04:43 +02:00
content = " Invalid! " ;
2018-07-07 18:47:18 +02:00
break ;
case TIMER_FAIL :
2018-07-07 21:41:53 +02:00
header = " False start! " ;
2018-07-07 23:25:46 +02:00
curr_time_local = ( start_time - runner_start_time ) / 1000.000 ;
content = curr_time_local ;
footer = " seconds too early " ;
2018-07-07 18:47:18 +02:00
break ;
default :
scr_update = false ;
break ;
}
2018-07-07 22:50:05 +02:00
2018-07-07 18:47:18 +02:00
if ( scr_update = = true ) {
2018-07-07 22:50:05 +02:00
if ( timer_new_state ! = timer_state ) {
2018-07-07 23:14:10 +02:00
display . clear ( 0 , 200 , 0 , 0 ) ;
display . clear ( 0 , 200 , 3 , 5 ) ;
display . clear ( 0 , 200 , 7 , 7 ) ;
2018-07-07 22:50:05 +02:00
}
2018-07-07 21:41:53 +02:00
//snprintf( string_to_char, sizeof(string_to_char),"%s", header);
header . toCharArray ( header_to_char , sizeof ( header_to_char ) ) ;
content . toCharArray ( content_to_char , sizeof ( content_to_char ) ) ;
footer . toCharArray ( footer_to_char , sizeof ( footer_to_char ) ) ;
2018-07-07 18:47:18 +02:00
//Serial.print("DISPLAY: ");
//Serial.println(string_to_char);
2018-07-07 21:41:53 +02:00
2018-07-07 19:27:47 +02:00
display . setFont ( System5x7 ) ;
2018-07-07 21:41:53 +02:00
display . set1X ( ) ;
int xpos = ( 128 - ( display . strWidth ( header_to_char ) ) ) / 2 - 10 ;
2018-07-07 19:27:47 +02:00
display . home ( ) ;
2018-07-07 21:41:53 +02:00
display . setLetterSpacing ( 1 ) ;
display . setCursor ( 64 - ( display . strWidth ( header_to_char ) / 2 ) , 0 ) ;
display . print ( header_to_char ) ;
2018-07-08 10:20:54 +02:00
display . setCursor ( 1 , 0 ) ;
2018-07-08 11:29:03 +02:00
//check if there is a connection to the topstation
2018-07-08 10:20:54 +02:00
if ( millis ( ) - connection_established > = CONN_TIMEOUT | | connection_established = = 0 ) {
2018-07-08 11:29:03 +02:00
//if not remove the "Y"
2018-07-08 10:20:54 +02:00
display . print ( " " ) ;
}
else {
2018-07-08 11:29:03 +02:00
//if print the "Y"
2018-07-08 10:20:54 +02:00
display . print ( " Y " ) ;
}
2018-07-07 21:41:53 +02:00
display . setCursor ( 0 , 1 ) ;
display . setLetterSpacing ( 0 ) ;
display . print ( " ---------------------------- " ) ;
2018-07-08 10:20:54 +02:00
2018-07-07 21:41:53 +02:00
//end of the Header
2018-07-07 23:50:28 +02:00
//display.setLetterSpacing(1);
2018-07-07 21:41:53 +02:00
display . set2X ( ) ;
display . setCursor ( 64 - ( display . strWidth ( content_to_char ) / 2 ) , 3 ) ;
display . print ( content_to_char ) ;
//end of the Content
display . set1X ( ) ;
display . setCursor ( 0 , 6 ) ;
2018-07-07 23:50:28 +02:00
display . setLetterSpacing ( 0 ) ;
display . print ( " ---------------------------- " ) ;
2018-07-07 22:00:53 +02:00
display . setCursor ( 64 - ( display . strWidth ( footer_to_char ) / 2 ) , 7 ) ;
display . print ( footer_to_char ) ;
2018-07-07 18:47:18 +02:00
}
}
2018-07-06 23:56:33 +02:00
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 ) {
2018-07-07 18:47:18 +02:00
digitalWrite ( READY_LED , LEDStates [ state ] [ 0 ] ) ;
digitalWrite ( RUN_LED , LEDStates [ state ] [ 1 ] ) ;
digitalWrite ( FAIL_LED , LEDStates [ state ] [ 2 ] ) ;
2018-07-06 23:56:33 +02:00
if ( warn = = true ) {
2018-07-07 18:47:18 +02:00
digitalWrite ( WARN_LED , WARN_LED_ON ) ;
2018-07-06 23:56:33 +02:00
}
else
{
2018-07-07 18:47:18 +02:00
digitalWrite ( WARN_LED , WARN_LED_OFF ) ;
2018-07-06 23:56:33 +02:00
}
}
}
void startSequence ( void )
{
// set the startime - this is the current time plus the length of this sequence
running_time_offset = mean_time_offset ;
2018-07-07 18:47:18 +02:00
start_time = millis ( ) + STARTSEQ_LENGTH_MS ;
Serial . print ( " Start time is: " ) ;
Serial . println ( start_time ) ;
2018-07-06 23:56:33 +02:00
// 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
2018-07-07 23:13:48 +02:00
update_statemessage ( timer_new_state ) ;
2018-07-07 18:47:18 +02:00
if ( timer_new_state = = TIMER_RUNNING ) {
2018-07-07 23:51:35 +02:00
wait ( STARTSEQ_STARTPAUSE_MS ) ;
2018-07-07 18:47:18 +02:00
}
2018-07-06 23:56:33 +02:00
// first tone
2018-07-07 23:13:48 +02:00
update_statemessage ( timer_new_state ) ;
2018-07-07 18:47:18 +02:00
if ( timer_new_state = = TIMER_RUNNING ) {
tone ( PIEZO_PIN , STARTSEQ_TON_1_2_FREQUENCY , STARTSEQ_TON_1_2_LENGTH_MS ) ;
2018-07-07 23:51:35 +02:00
wait ( STARTSEQ_TONEPAUSE_MS ) ;
2018-07-07 18:47:18 +02:00
}
2018-07-06 23:56:33 +02:00
//second tone
2018-07-07 23:13:48 +02:00
update_statemessage ( timer_new_state ) ;
2018-07-07 18:47:18 +02:00
if ( timer_new_state = = TIMER_RUNNING ) {
tone ( PIEZO_PIN , STARTSEQ_TON_1_2_FREQUENCY , STARTSEQ_TON_1_2_LENGTH_MS ) ;
2018-07-07 23:51:35 +02:00
wait ( STARTSEQ_TONEPAUSE_MS ) ;
2018-07-07 18:47:18 +02:00
}
2018-07-06 23:56:33 +02:00
//third tone
2018-07-07 23:13:48 +02:00
update_statemessage ( timer_new_state ) ;
2018-07-07 18:47:18 +02:00
if ( timer_new_state = = TIMER_RUNNING ) {
tone ( PIEZO_PIN , STARTSEQ_TON_3_FREQUENCY , STARTSEQ_TON_3_LENGTH_MS ) ;
2018-07-07 23:51:35 +02:00
wait ( STARTSEQ_TON_3_LENGTH_MS ) ;
2018-07-07 18:47:18 +02:00
}
}
2018-07-06 23:56:33 +02:00
2018-07-07 18:47:18 +02:00
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 ) ;
}
2018-07-06 23:56:33 +02:00
2018-07-07 18:47:18 +02:00
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 ( ) ;
2018-07-07 23:13:48 +02:00
if ( ( timer_state = = TIMER_STARTED ) & ( timer_new_state = = TIMER_RUNNING ) ) {
2018-07-07 18:47:18 +02:00
timer_new_state = TIMER_FAIL ;
noTone ( PIEZO_PIN ) ;
2018-07-07 23:13:48 +02:00
Serial . println ( " ** Interrupt service routine detected false_start. Set new state to TIMER_FAIL ** " ) ;
update_statemessage ( timer_new_state ) ;
detachInterrupt ( digitalPinToInterrupt ( FAILSTARTBUTTON_IN ) ) ;
2018-07-07 18:47:18 +02:00
} else {
2018-07-07 22:50:05 +02:00
if ( ( timer_state = = TIMER_RUNNING ) | ( timer_new_state = = TIMER_RUNNING ) ) {
2018-07-07 18:47:18 +02:00
// disable this interrupt;
detachInterrupt ( digitalPinToInterrupt ( FAILSTARTBUTTON_IN ) ) ;
}
}
}
2018-07-07 23:51:35 +02:00
void wait ( unsigned long ms ) {
unsigned long current = 0 ;
unsigned long started = millis ( ) ;
do {
current = millis ( ) - started ;
} while ( current < ms ) ;
}