diff --git a/changelog.txt b/changelog.txt index d9163ba..2b2efd7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,8 +1,30 @@ Revisions history ----------------- - * 2020-12-17: Ver 0.9.6- Luca // Gitlab Commit = 0.9.6a - ....................................................... + * 2021-11-20: Ver 0.9.7 - Luca - Branch: "lab" + ............................................... + - Changed Version Number to 0.9.7 + - ready to merge with master branch + - ver 0.9.7 managed by companion desktopApp + + * 2021-07-20: Ver 0.9.6 - Luca - Branch: "lab" + - Manage config parameters (load/save/protocol) for: + - NEW: Autostart ("G") + - NEW: Battery ("E") + - NEW: Players number ("P") + - UPD: "Q" ("Get configuration" output changed) + -- Not compatible with previous versions + - UPD: "~" ---> "*" (Commmand ID for "Leave configuration mode" changed) + + * 2021-07-13: Ver 0.9.6 - Gerardo - Branch: "lab" + - Charge battery function and telemetry test code (add BATTERY ( ",<0-100 value> to end of "p" serial status )) + - Add BATTERY_DELTA variable for decremet battery on push buton flag change + - Add BATTERY_MIN for user warning on low battery status + - Add blink efect on min battery condition + - Quit tail lap efect + - Add coin to main track for BATTERY_MODE=1 + + * 2020-12-17: Ver 0.9.6- Luca // Gitlab Commit = 0.9.6a - Removed dependency from "AsyncSerialLib" - new class SerialCommand() - Remove delay() (blocking) in Countdown phase diff --git a/doc/OLRN_Protocol_Serial.pdf b/doc/OLRN_Protocol_Serial.pdf index 44ace3b..96f5017 100644 Binary files a/doc/OLRN_Protocol_Serial.pdf and b/doc/OLRN_Protocol_Serial.pdf differ diff --git a/open-led-race/olr-controller.c b/open-led-race/olr-controller.c index 1b8e55c..311e9cf 100644 --- a/open-led-race/olr-controller.c +++ b/open-led-race/olr-controller.c @@ -66,6 +66,7 @@ float controller_getSpeed( controller_t* ct) { return speed; } + float controller_getAccel ( void ) { return ACEL; } diff --git a/open-led-race/olr-controller.h b/open-led-race/olr-controller.h index 87fad3a..6eed6d3 100644 --- a/open-led-race/olr-controller.h +++ b/open-led-race/olr-controller.h @@ -19,8 +19,6 @@ extern "C"{ #define PIN_VCC_ADC1 6 #define PIN_VCC_ADC2 7 - - enum ctr_type{ NOT_DEFINED = 0, DIGITAL_MODE, diff --git a/open-led-race/olr-lib.c b/open-led-race/olr-lib.c index 653fed8..75da1c3 100644 --- a/open-led-race/olr-lib.c +++ b/open-led-race/olr-lib.c @@ -10,10 +10,12 @@ void car_init( car_t* car, controller_t* ct, uint32_t color ) { car->speed=0; car->dist=0; car->dist_aux=0; + car->battery=100; + car->charging=0; } void car_updateController( car_t* car ) { - car->speed += controller_getSpeed( car->ct ); + car->speed += controller_getSpeed( car->ct )*car->battery/100; } void update_track( track_t* tck, car_t* car ) { @@ -23,8 +25,8 @@ void update_track( track_t* tck, car_t* car ) { if ( car->trackID == TRACK_MAIN && (int)car->dist % cfg->nled_main == (cfg->init_aux-(cfg->nled_aux)) - // && controller_getStatus( ct ) == 0 ) { //change track by switch - && (car->speed <= SPD_MIN_TRACK_AUX )) { //change track by low speed + && controller_getStatus( ct ) == 0 ) { //change track by switch + // && (car->speed <= SPD_MIN_TRACK_AUX )) { //change track by low speed car->trackID = TRACK_AUX; car->dist_aux = 0; @@ -46,11 +48,14 @@ void update_track( track_t* tck, car_t* car ) { void process_aux_track( track_t* tck, car_t* car ){ struct cfgtrack const* cfg = &tck->cfg.track; + struct cfgbattery const* battery = &tck->cfg.battery; if ( (int)car->dist_aux == tck->ledcoin && car->speed <= controller_getAccel() ) { - car->speed = controller_getAccel ()*50; + car->speed = controller_getAccel() * (1.0 * battery->speed_boost_scaler); + tck->ledcoin = COIN_RESET; + car->battery=100; }; car->speed -= car->speed * cfg->kf; @@ -72,10 +77,41 @@ void process_main_track( track_t* tck, car_t* car ) { //car->speed += cfg->kg * r->high * ( pos - r->center ); car->speed += cfg->kg * r->high ; } + + if(param_option_is_active(&tck->cfg, BATTERY_MODE_OPTION)){ // Battery Mode ON + struct cfgbattery const* battery = &tck->cfg.battery; + if ( cfg->nled_main-(int)(car->dist) % cfg->nled_main == tck->ledcoin + && controller_getStatus( car->ct ) == 0 //charge battery by push switch over coin + //&& car->speed <= controller_getAccel() + ) + {car->charging=1;}; + + if (car->charging==1){ + car->battery+= battery->delta / 100.0 * 2; + + car->speed =0; + if (car->battery >100){tck->ledcoin = COIN_RESET; + car->battery=100; + car->charging=0; + //car->speed = controller_getAccel()*SPEED_BOOST_SCALER; + car->speed = 0.1 * battery->speed_boost_scaler; + }; + }; + + if (car->ct->flag_sw==0) { + if ((car->battery)>=battery->min ) {car->battery-= battery->delta/100.0;}; + + }; + if (car->ct->flag_sw==1) { + if (car->charging==1) {car->charging=0; + car->speed = (0.1*battery->speed_boost_scaler)/2; + }; + }; + }; car->speed -= car->speed * cfg->kf; - car->dist += car->speed; - + car->dist += car->speed; + } void ramp_init( track_t* tck ) { @@ -96,6 +132,7 @@ void car_resetPosition( car_t* car) { car->dist_aux = 0; car->nlap = 1; car->leaving = false; + car->battery = 100; } void box_init( track_t* tck ) { @@ -115,16 +152,48 @@ int tracklen_configure( track_t* tck, int nled ) { return 0; } +int autostart_configure( track_t* tck, int autostart ) { + param_option_set(&tck->cfg, AUTOSTART_MODE_OPTION, (boolean) autostart); + return 0; +} + + + +int players_n_configure( track_t* tck, int val ) { + switch(val){ + case 2 : + param_option_set(&tck->cfg, PLAYER_3_OPTION, false); + param_option_set(&tck->cfg, PLAYER_4_OPTION, false); + break; + + case 3 : + param_option_set(&tck->cfg, PLAYER_3_OPTION, true); + param_option_set(&tck->cfg, PLAYER_4_OPTION, false); + break; + + case 4 : + param_option_set(&tck->cfg, PLAYER_3_OPTION, true); + param_option_set(&tck->cfg, PLAYER_4_OPTION, true); + break; + + default: + return(-1); + } + return(0); +} + + int boxlen_configure( track_t* tck, int box_len, int boxalwaysOn ) { struct cfgtrack* cfg = &tck->cfg.track; if ( boxalwaysOn != 0 && boxalwaysOn != 1 ) return -1; if( box_len <= 0 || box_len >= cfg->nled_total ) return -1; cfg->box_len = box_len; - cfg->box_alwaysOn = boxalwaysOn; - + //cfg->box_alwaysOn = boxalwaysOn; + param_option_set(&tck->cfg, BOX_MODE_OPTION, (boolean) boxalwaysOn); // Update track->boxactive tck->boxactive = boxalwaysOn; + return 0; } @@ -151,7 +220,7 @@ int track_configure( track_t* tck, int init_box ) { } -int ramp_configure( track_t* tck, int init, int center, int end, int high, int alwaysOn ) { +int ramp_configure( track_t* tck, int init, int center, int end, uint8_t high, int alwaysOn ) { struct cfgramp* ramp = &tck->cfg.ramp; if ( init >= tck->cfg.track.nled_main || init <= 0 ) return -1; @@ -164,18 +233,27 @@ int ramp_configure( track_t* tck, int init, int center, int end, int high, int a ramp->center = center; ramp->end = end; ramp->high = high; - ramp->alwaysOn = alwaysOn; + param_option_set(&tck->cfg, SLOPE_MODE_OPTION, (boolean) alwaysOn); // Update track->rampactive - /** - boolean rampactive = &tck->rampactive; - rampactive = alwaysOn; - **/ tck->rampactive = alwaysOn; return 0; } +int battery_configure( track_t* tck, int delta, int min, int boost, int active ){ + struct cfgbattery* battery = &tck->cfg.battery; + + battery->delta = delta; + battery->min = min; + battery->speed_boost_scaler = boost; + param_option_set(&tck->cfg, BATTERY_MODE_OPTION, (boolean) active); + + return 0; +} + + + int race_configure( track_t* tck, int startline, int nlap, int nrepeat, int finishline ) { struct cfgrace* race = &tck->cfg.race; diff --git a/open-led-race/olr-lib.h b/open-led-race/olr-lib.h index 81f84e8..48889cb 100644 --- a/open-led-race/olr-lib.h +++ b/open-led-race/olr-lib.h @@ -13,7 +13,12 @@ extern "C"{ #include "olr-controller.h" #include "olr-param.h" -#define SPD_MIN_TRACK_AUX 0.8 + +#define SPD_MIN_TRACK_AUX 0.8 // change track by low speed +//#define BATTERY_DELTA 0.03 // Decrease BATTERY_DELTA on each controller activation - used in charge rate too +//#define BATTERY_DELTA 3 // unsigned char value [1-254] / will be divided by 100 [0.01-2.54] +//#define BATTERY_MIN 60 // Battery does not descharge below BATTERY_MIN +//#define SPEED_BOOST_SCALER 10 enum stcoin{ COIN_RESET = -2, @@ -48,9 +53,11 @@ typedef struct{ byte nlap; byte repeats; uint32_t color; - int trackID; + uint8_t trackID; enum status st; bool leaving; + float battery; + bool charging; }car_t; @@ -82,6 +89,10 @@ bool box_isactive( track_t* tck ); int tracklen_configure( track_t* tck, int nled ); +int autostart_configure( track_t* tck, int autostart ); + +int players_n_configure( track_t* tck, int val ); + int boxlen_configure( track_t* tck, int box_len, int boxalwaysOn ); int physic_configure( track_t* tck, float kgp, float kfp ); @@ -92,7 +103,9 @@ void ramp_init( track_t* tck ); bool ramp_isactive( track_t* tck ); -int ramp_configure( track_t* tck, int init, int center, int end, int high, int alwaysOn ); +int ramp_configure( track_t* tck, int init, int center, int end, uint8_t high, int alwaysOn ); + +int battery_configure( track_t* tck, int delta, int min, int boost, int active ); int race_configure( track_t* tck, int startline, int nlap, int nrepeat, int finishline ); diff --git a/open-led-race/olr-param.c b/open-led-race/olr-param.c index 81290ab..0b897e0 100644 --- a/open-led-race/olr-param.c +++ b/open-led-race/olr-param.c @@ -1,26 +1,44 @@ #include "olr-param.h" void param_setdefault( struct cfgparam* cfg ) { - cfg->setted = true; + cfg->ver = CFGPARAM_VER; cfg->race.startline = true; cfg->race.nlap = NUMLAP; cfg->race.nrepeat = 1; cfg->race.finishline = true; + param_option_set(cfg, BATTERY_MODE_OPTION, BATTERY_MODE); + cfg->battery.delta = 3; + cfg->battery.min = 60; + cfg->battery.speed_boost_scaler = 10; + + param_option_set(cfg, AUTOSTART_MODE_OPTION, AUTOSTART_MODE); + cfg->ramp.init = 80; cfg->ramp.center = 90; cfg->ramp.end = 100; cfg->ramp.high = 6; - cfg->ramp.alwaysOn = false; + param_option_set(cfg, SLOPE_MODE_OPTION, SLOPE_ALWAYS_ON); - cfg->track.nled_total = MAXLED; + cfg->track.nled_total = MAXLED; // MAXLED: Total LED number in the racetrack (default:300 -> 5mt, 60LED/mt Strip) cfg->track.nled_main = MAXLED; // 240 when boxes length = 60 cfg->track.nled_aux = 0; // 60 cfg->track.init_aux = -1; // 239 cfg->track.box_len = BOXLEN; - cfg->track.box_alwaysOn = false; + param_option_set(cfg, BOX_MODE_OPTION, BOX_ALWAYS_ON); cfg->track.kf = 0.015; // friction constant cfg->track.kg = 0.006; // gravity constant - Used in Slope + + param_option_set(cfg, PLAYER_3_OPTION, PLAYER_3); + param_option_set(cfg, PLAYER_4_OPTION, PLAYER_4); + +} + +void param_option_set( struct cfgparam* cfg, uint8_t option, boolean value ) { + bitWrite(cfg->option, option, value); +} +boolean param_option_is_active( struct cfgparam* cfg, uint8_t option) { + return(bitRead(cfg->option, option)); } diff --git a/open-led-race/olr-param.h b/open-led-race/olr-param.h index 3535077..260be89 100644 --- a/open-led-race/olr-param.h +++ b/open-led-race/olr-param.h @@ -10,39 +10,65 @@ extern "C"{ #include #include -#define MAXLED 300 -#define BOXLEN 60 -#define NUMLAP 5 +// Default values loaded on "D" command received (Serial Protocol) +////////////////////////////////////////////////////////////////// +#define MAXLED 300 +#define BOXLEN 60 +#define NUMLAP 5 +#define BATTERY_MODE false +#define AUTOSTART_MODE false +#define BOX_ALWAYS_ON false +#define SLOPE_ALWAYS_ON false +#define PLAYER_3 false +#define PLAYER_4 false +////////////////////////////////////////////////////////////////// +// Position (bit) into the cfgparam.option byte for On|Off settings +// Used in param_option_set()/param_option_is_active() calls +enum cfgparam_option_bit { + BATTERY_MODE_OPTION = 0, + AUTOSTART_MODE_OPTION = 1, + BOX_MODE_OPTION = 2, + SLOPE_MODE_OPTION = 3, + PLAYER_3_OPTION = 4, + PLAYER_4_OPTION = 5, + NOT_USED_3_OPTION = 6, + NOT_USED_4_OPTION = 7, +}; -enum{ +enum cfgpar { + CFGPARAM_VER = 6, // Change this value (+=1) every time the [cfgparam] struct is modified + // This will force an update with the new [struct] to the settings + // stored in EEPROM with an old (invalid) struct LEN_UID = 16, - CFG_VER = 5, // "5" in V0.9.6 (manage "permanent" param for Box and Slope) }; struct cfgrace{ bool startline; // Used only in OLRNetwork - int nlap; - int nrepeat; // Used only in OLRNetwork + uint8_t nlap; + uint8_t nrepeat; // Used only in OLRNetwork bool finishline; // Used only in OLRNetwork }; -// +struct cfgbattery{ // added in ver 0.9.7 + uint8_t delta; // unsigned char value [1-254] / will be divided by 100 [0.01-2.54] + uint8_t min; // Battery does not descharge below this "min" percentage + uint8_t speed_boost_scaler; +} ; + struct cfgtrack { int nled_total; int nled_main; int nled_aux; int init_aux; - int box_len; // used to hold the Box Length if the default get changed. + int box_len; // used to hold the Box Length if the default is changed. // it's not possible to implicitly store it in nled_main,nled_aux // because, if these are different to the default, box gets always activated // (the software does not chek "box_isactive" to draw car position) - bool box_alwaysOn; // added in ver 0.9.6 - - float kf; float kg; + }; // ramp centred in LED 100 with 10 led fordward and 10 backguard @@ -50,8 +76,7 @@ struct cfgramp { int init; int center; int end; - int high; - bool alwaysOn; // added in ver 0.9.6 + uint8_t high; }; struct brdinfo { @@ -59,15 +84,19 @@ struct brdinfo { }; struct cfgparam { - bool setted; - struct cfgrace race; // added in ver 0.9.d - struct cfgtrack track; - struct cfgramp ramp; - struct brdinfo info; + uint8_t ver; // Version of this [cfgparam] struct + uint8_t option; // Bit-mapped byte to store 'active' on|off for options (Battery, AutoStart, BoxalwaysOn, etc) + struct cfgrace race; // added in ver 0.9.d + struct cfgbattery battery; + struct cfgtrack track; + struct cfgramp ramp; + struct brdinfo info; }; void param_setdefault( struct cfgparam* cfg ); +void param_option_set( struct cfgparam* cfg, uint8_t option, boolean value ); +boolean param_option_is_active( struct cfgparam* cfg, uint8_t option); #ifdef __cplusplus } // extern "C" diff --git a/open-led-race/open-led-race.ino b/open-led-race/open-led-race.ino index fa11eda..c5c731b 100644 --- a/open-led-race/open-led-race.ino +++ b/open-led-race/open-led-race.ino @@ -29,12 +29,11 @@ */ -// 2020/12/10 - Ver 0.9.6 +// 2021/07/20 - Ver 0.9.6 - lab branch // --see changelog.txt char const softwareId[] = "A4P0"; // A4P -> A = Open LED Race, 4P0 = Game ID (4P = 4 Players, 0=Type 0) -char const version[] = "0.9.6"; - +char const version[] = "0.9.7"; #include @@ -48,7 +47,14 @@ char const version[] = "0.9.6"; #define PIN_AUDIO 3 // through CAP 2uf to speaker 8 ohms #define REC_COMMAND_BUFLEN 32 // received command buffer size -#define TX_COMMAND_BUFLEN 80 // send command buffer size + // At the moment, the largest received command is RAMP CONFIGURATION (A) + // ex: A1400,1430,1460,12,0[EOC] (for a 1500 LED strip) + // 21 CHAR +#define TX_COMMAND_BUFLEN 48 // send command buffer size + // At the moment, the largest send command is Q + // ex: QTK:1500,1500,0,-1,60,0,0.006,0.015,1[EOC] (for a 1500 LED strip) + // 37 CHAR + #define EOL '\n' // End of Command char used in Protocol #define COLOR1 track.Color(255,0,0) @@ -57,9 +63,11 @@ char const version[] = "0.9.6"; #define COLOR4 track.Color(255,255,255) #define COLOR_RAMP track.Color(64,0,64) -#define COLOR_COIN track.Color(0,255,255) +#define COLOR_COIN track.Color(40,34,0) #define COLOR_BOXMARKS track.Color(64,64,0) #define LED_SEMAPHORE 12 +#define WARNING_BLINK_COLOR track.Color(32,20,0) + #define CONTDOWN_PHASE_DURATION 2000 #define CONTDOWN_STARTSOUND_DURATION 40 @@ -124,6 +132,7 @@ byte SMOTOR=0; int TBEEP=0; int FBEEP=0; + /*------------------------------------------------------*/ enum loglevel verbose = DISABLE; @@ -134,11 +143,6 @@ static track_t tck; static int const eeadrInfo = 0; - - - - - static unsigned long lastmillis = 0; SoftTimer customDelay = SoftTimer(); // non blocking delay() @@ -154,8 +158,6 @@ int win_music[] = { 3136 }; -//int TBEEP=3; - char tracksID[ NUM_TRACKS ][2] ={"U","M","B","I","O"}; /* ----------- Function prototypes ------------------- */ @@ -169,7 +171,6 @@ void print_cars_positions( car_t* cars); void run_racecycle( void ); void draw_winner( track_t* tck, uint32_t color); - char cmd[REC_COMMAND_BUFLEN]; // Stores command received by ReadSerialComand() SerialCommand serialCommand = SerialCommand(cmd, REC_COMMAND_BUFLEN, EOL, &Serial); // get complete command from serial @@ -197,13 +198,13 @@ void setup() { race.numcars = 2; - if( controller_isActive( DIG_CONTROL_3 )) { + if( controller_isActive( DIG_CONTROL_3 ) || param_option_is_active(&tck.cfg, PLAYER_3_OPTION) || param_option_is_active(&tck.cfg, PLAYER_4_OPTION) ) { controller_init( &switchs[2], DIGITAL_MODE, DIG_CONTROL_3 ); car_init( &cars[2], &switchs[2], COLOR3 ); ++race.numcars; } - if( controller_isActive( DIG_CONTROL_4 )) { + if( controller_isActive( DIG_CONTROL_4 ) || param_option_is_active(&tck.cfg, PLAYER_4_OPTION)) { controller_init( &switchs[3], DIGITAL_MODE, DIG_CONTROL_4 ); car_init( &cars[3], &switchs[3], COLOR4 ); ++race.numcars; @@ -214,7 +215,7 @@ void setup() { // Check Box before Physic/Sound to allow user to have Box and Physics with no sound - if(digitalRead(DIG_CONTROL_2)==0 || tck.cfg.track.box_alwaysOn ) { //push switch 2 on reset for activate boxes (pit lane) + if(digitalRead(DIG_CONTROL_2)==0 || param_option_is_active(&tck.cfg, BOX_MODE_OPTION) ) { //push switch 2 on reset for activate boxes (pit lane) box_init( &tck ); track_configure( &tck, tck.cfg.track.nled_total - tck.cfg.track.box_len ); draw_box_entrypoint( &tck ); @@ -222,7 +223,7 @@ void setup() { track_configure( &tck, 0 ); } - if( digitalRead(DIG_CONTROL_1)==0 || tck.cfg.ramp.alwaysOn ) { //push switch 1 on reset for activate physics + if( digitalRead(DIG_CONTROL_1)==0 || param_option_is_active(&tck.cfg, SLOPE_MODE_OPTION) ) { // push switch 1 on reset for activate physics ramp_init( &tck ); draw_ramp( &tck ); track.show(); @@ -274,16 +275,41 @@ void loop() { break; case READY: - { - if(customDelay.elapsed()) { - for( int i = 0; i < race.numcars; ++i) { - car_resetPosition( &cars[i] ); - cars[i].repeats = 0; + { + if(param_option_is_active(&tck.cfg, AUTOSTART_MODE_OPTION)){ // Auto-Start Mode ON + if(customDelay.elapsed()) { + for( int i = 0; i < race.numcars; ++i) { + car_resetPosition( &cars[i] ); + cars[i].repeats = 0; + } + tck.ledcoin = COIN_RESET; + race.phase = COUNTDOWN; + send_phase( race.phase ); } - tck.ledcoin = COIN_RESET; - race.phase = COUNTDOWN; - send_phase( race.phase ); - } + } else { + int pstart=0; + strip_clear( &tck ); + if( ramp_isactive( &tck ) ) + draw_ramp( &tck ); + if( box_isactive( &tck ) ) + draw_box_entrypoint( &tck ); + for( int i = 0; i < race.numcars; ++i) { + if (controller_getStatus(cars[i].ct)==false){ + car_resetPosition( &cars[i] ); + //Serial.println(i); + track.setPixelColor(i,cars[i].color); + cars[i].repeats = 0; + pstart++; + } + } + + track.setPixelColor(LED_SEMAPHORE , ((millis()/5)%64)*0x010100 ); + track.show(); + if (pstart==race.numcars){tck.ledcoin = COIN_RESET; + race.phase = COUNTDOWN; + send_phase( race.phase );} + + }; } break; @@ -305,8 +331,13 @@ void loop() { case RACING: { - strip_clear( &tck ); - + strip_clear( &tck ); + + if( ramp_isactive( &tck ) ) + draw_ramp( &tck ); + if( box_isactive( &tck ) ) + draw_box_entrypoint( &tck ); + if( box_isactive( &tck ) ) { if( tck.ledcoin == COIN_RESET ) { tck.ledcoin = COIN_WAIT; @@ -316,13 +347,20 @@ void loop() { draw_coin( &tck ); else if( millis() > tck.ledtime ) tck.ledcoin = random( 20, tck.cfg.track.nled_aux - 20 ); + + } else { + if ( param_option_is_active(&tck.cfg, BATTERY_MODE_OPTION) ) { // Battery Mode ON + if( tck.ledcoin == COIN_RESET ) { + tck.ledcoin = COIN_WAIT; + tck.ledtime = millis() + random(3000,8000); + } + if( tck.ledcoin > 0 ) + draw_coin( &tck ); + else if( millis() > tck.ledtime ) + tck.ledcoin = random( LED_SEMAPHORE+4, tck.cfg.track.nled_main - 60); //valid zone from random charge (semaphore to 1 meter before to start-finish position + } } - - if( ramp_isactive( &tck ) ) - draw_ramp( &tck ); - if( box_isactive( &tck ) ) - draw_box_entrypoint( &tck ); - + for( int i = 0; i < race.numcars; ++i ) { run_racecycle( &cars[i], i ); if( cars[i].st == CAR_FINISH ) { @@ -339,14 +377,14 @@ void loop() { // Print p command!!! unsigned long nowmillis = millis(); - if( abs( nowmillis - lastmillis ) > 100 ){ + if( abs( nowmillis - lastmillis ) > 250 ){ lastmillis = nowmillis; print_cars_positions( cars ); } // ---------------- } break; - + case COMPLETE : { strip_clear( &tck ); @@ -364,12 +402,12 @@ void loop() { default: { - sprintf( txbuff, "Software Error in main loop switch()"); + sprintf( txbuff, "SwErr-01"); printdebug( txbuff, WARNING ); break; } - } // switch + } // switch race.phase } @@ -457,22 +495,19 @@ void print_cars_positions( car_t* cars ) { for( int i = 0; i < race.numcars; ++i ) { int const rpos = get_relative_position( &cars[i] ); - sprintf( txbuff, "p%d%s%d,%d%c", i + 1, tracksID[cars[i].trackID], cars[i].nlap, rpos, EOL ); + sprintf( txbuff, "p%d%s%d,%d,%d%c", i + 1, tracksID[cars[i].trackID], cars[i].nlap, rpos,(int)cars[i].battery, EOL ); serialCommand.sendCommand(txbuff); - //sendCommand(txbuff); } } - /* * non-blocking version */ boolean start_race_done( ) { if(countdown_new_phase){ countdown_new_phase=false; - //customDelay.start(CONTDOWN_PHASE_DURATION); customDelay.start(CONTDOWN_PHASE_DURATION); strip_clear( &tck ); if(ramp_isactive( &tck )) draw_ramp( &tck ); @@ -493,7 +528,6 @@ boolean start_race_done( ) { track.setPixelColor(LED_SEMAPHORE-2, track.Color(0,255,0)); break; case 4: - //customDelay.start(CONTDOWN_STARTSOUND_DURATION); customDelay.start(CONTDOWN_STARTSOUND_DURATION); tone(PIN_AUDIO,880); track.setPixelColor(LED_SEMAPHORE-2, track.Color(0,0,0)); @@ -545,7 +579,7 @@ void strip_clear( track_t* tck ) { void draw_coin( track_t* tck ) { struct cfgtrack const* cfg = &tck->cfg.track; - track.setPixelColor( 1 + cfg->nled_main + cfg->nled_aux - tck->ledcoin,COLOR_COIN ); + track.setPixelColor( 1 + cfg->nled_main + cfg->nled_aux - tck->ledcoin,COLOR_COIN ); } void draw_winner( track_t* tck, uint32_t color) { @@ -557,7 +591,7 @@ void draw_winner( track_t* tck, uint32_t color) { } } -void draw_car( track_t* tck, car_t* car ) { +void draw_car_tail( track_t* tck, car_t* car ) { struct cfgtrack const* cfg = &tck->cfg.track; switch ( car->trackID ){ @@ -572,6 +606,36 @@ void draw_car( track_t* tck, car_t* car ) { } } +void draw_car( track_t* tck, car_t* car ) { + struct cfgtrack const* cfg = &tck->cfg.track; + struct cfgbattery const* battery = &tck->cfg.battery; + + switch ( car->trackID ){ + case TRACK_MAIN: + for(int i=0; i<=1; ++i ) + track.setPixelColor( ((word)car->dist % cfg->nled_main) - i, car->color ); + if(param_option_is_active(&tck->cfg, BATTERY_MODE_OPTION)){ // Battery Mode ON + if ( car->charging==1 ) { + track.setPixelColor( ((word)car->dist % cfg->nled_main) - 2, 0x010100 * 50*(millis()/(201-2*(byte)car->battery)%2)); + } else if (car->battery <= battery->min) + if ((millis()%100)>50) track.setPixelColor( ((word)car->dist % cfg->nled_main) - 2, WARNING_BLINK_COLOR ); + } + break; + case TRACK_AUX: + for(int i=0; i<=1; ++i ) + track.setPixelColor( (word)(cfg->nled_main + cfg->nled_aux - car->dist_aux) + i, car->color); + if(param_option_is_active(&tck->cfg, BATTERY_MODE_OPTION)){ // Battery Mode ON + + if ( car->charging==1 ) { + track.setPixelColor( (word)(cfg->nled_main + cfg->nled_aux - car->dist_aux) + 2, 0x010100 * 50*(millis()/(201-2*(byte)car->battery)%2)); + } else if (car->battery <= battery->min) + if ((millis()%100)>50) + track.setPixelColor( (word)(cfg->nled_main + cfg->nled_aux - car->dist_aux) + 2, WARNING_BLINK_COLOR); + } + break; + } +} + /* * Display on LED Strip current values for Slope and Pitlane @@ -659,7 +723,7 @@ ack_t manageSerialCommand() { } break; - case '~' : // Exit "Configure Mode" + case '*' : // Exit "Configure Mode" { ack.type = cmd[0]; if(race.phase == CONFIG) { // Ignore command if Board is not in "Configure Mode" @@ -800,7 +864,70 @@ ack_t manageSerialCommand() { show_cfgpars_onstrip(); } break; - + + case 'E' : // Parse Battery configuration -> Edelta,min,boost,active + { + ack.type = cmd[0]; + + char * pch = strtok (cmd,"E"); + if( !pch ) return ack; + + pch = strtok (pch, "," ); + if( !pch ) return ack; + int delta = atoi( pch ); + + pch = strtok (NULL, "," ); + if( !pch ) return ack; + int min = atoi( pch ); + + pch = strtok (NULL, "," ); + if( !pch ) return ack; + int boost = atoi( pch ); + + pch = strtok (NULL, ","); + if( !pch ) return ack; + int active = atoi( pch ); + + int err = battery_configure( &tck, delta, min, boost, active ); + if( err ) return ack; + ack.rp = OK; + + } + break; + + case 'G' : //Parse Autostart configuration -> Gautostart + { + ack.type = cmd[0]; + + char * pch = strtok (cmd,"G"); + if( !pch ) return ack; + + int autostart = atoi( cmd + 1 ); + int err = autostart_configure( &tck, autostart); + if( err ) return ack; + + ack.rp = OK; + } + break; + + case 'P' : //Parse Player 3/4 configuration -> P[2|3|4] + { + ack.type = cmd[0]; + + char * pch = strtok (cmd,"P"); + if( !pch ) return ack; + + int autostart = atoi( cmd + 1 ); + int err = players_n_configure( &tck, autostart); + if( err ) return ack; + + ack.rp = OK; + } + break; + + + + case 'K': // Parse Physic simulation parameters { ack.type = cmd[0]; @@ -835,8 +962,8 @@ ack_t manageSerialCommand() { // Update box/slope active in current Track Struct with values // just loaded (for show_cfgpars_onstrip()) struct cfgparam const* cfg = &tck.cfg; - tck.boxactive = cfg->track.box_alwaysOn; - tck.rampactive = cfg->ramp.alwaysOn; + tck.boxactive = param_option_is_active(&tck.cfg, BOX_MODE_OPTION); + tck.rampactive = param_option_is_active(&tck.cfg, SLOPE_MODE_OPTION); show_cfgpars_onstrip(); } @@ -880,32 +1007,45 @@ ack_t manageSerialCommand() { case 'Q': // Get current configuration Info { struct cfgparam const* cfg = &tck.cfg; - sprintf( txbuff, "%s:%d,%d,%d,%d,%d,%d,%d.%03d,%d.%03d%c", "QTRACK", + sprintf( txbuff, "%s:%d,%d,%d,%d,%d,%d,%d.%03d,%d.%03d,%d%c", "QTK", cfg->track.nled_total, cfg->track.nled_main, cfg->track.nled_aux, cfg->track.init_aux, cfg->track.box_len, - cfg->track.box_alwaysOn, + //cfg->track.box_alwaysOn, + param_option_is_active(&tck.cfg, BOX_MODE_OPTION), (int)cfg->track.kg, (int)(cfg->track.kg*1000)%1000, // std arduino sprintf() missing %f (int)cfg->track.kf, (int)(cfg->track.kf*1000)%1000, // std arduino sprintf() missing %f + param_option_is_active(&tck.cfg, AUTOSTART_MODE_OPTION), EOL ); serialCommand.sendCommand(txbuff); - sprintf( txbuff, "%s:%d,%d,%d,%d,%d%c", "QRAMP", + sprintf( txbuff, "%s:%d,%d,%d,%d,%d%c", "QRP", cfg->ramp.init, cfg->ramp.center, cfg->ramp.end, cfg->ramp.high, - cfg->ramp.alwaysOn, + //cfg->ramp.alwaysOn, + param_option_is_active(&tck.cfg, SLOPE_MODE_OPTION), EOL ); serialCommand.sendCommand(txbuff); - sprintf( txbuff, "%s:%d,%d,%d,%d%c", "QRACE", + sprintf( txbuff, "%s:%d,%d,%d,%d%c", "QBT", + cfg->battery.delta, + cfg->battery.min, + cfg->battery.speed_boost_scaler, + param_option_is_active(&tck.cfg, BATTERY_MODE_OPTION), + EOL ); + serialCommand.sendCommand(txbuff); + + sprintf( txbuff, "%s:%d,%d,%d,%d,%d,%d%c", "QRC", cfg->race.startline, cfg->race.nlap, cfg->race.nrepeat, cfg->race.finishline, + param_option_is_active(&tck.cfg, PLAYER_3_OPTION), + param_option_is_active(&tck.cfg, PLAYER_4_OPTION), EOL ); serialCommand.sendCommand(txbuff); @@ -964,46 +1104,29 @@ void enter_configuration_mode(){ void param_load( struct cfgparam* cfg ) { - int cfgversion; - int eeAdress = eeadrInfo; - EEPROM.get( eeAdress, tck.cfg ); - eeAdress += sizeof( cfgparam ); - EEPROM.get( eeAdress, cfgversion ); - sprintf( txbuff, "%s:%d%c", "Parameters Loaded from EEPROM - Cfg ver", cfgversion, EOL ); + /** + // Ignore EEPROM params during development of a new version of the [cfgparam] + param_setdefault( &tck.cfg ); + sprintf( txbuff, "%s%c", "Temporary....DEFAULT PAREMETRS LOADED ", EOL ); + serialCommand.sendCommand(txbuff); + return; + **/ + + EEPROM.get( eeadrInfo, tck.cfg ); + + sprintf( txbuff, "%s:%d%c", "EEPROM-v", tck.cfg.ver, EOL ); serialCommand.sendCommand(txbuff); - if ( cfgversion != CFG_VER ) { + if ( tck.cfg.ver != CFGPARAM_VER ) { // [cfgparam.ver] read form EEPROM != [#define CFGPARAM_VER] in the code + // Each time a new version of the code modify the [cfgparam] struct, [#define CFGPARAM_VER] is also + // changed to force the code enter here. + // The previous values stored in EEPROM are invalid and need to be reset-to-default and + // stored in the EEPROM again with the new "structure" param_setdefault( &tck.cfg ); - eeAdress = 0; - EEPROM.put( eeAdress, tck.cfg ); - eeAdress += sizeof( cfgparam ); - EEPROM.put( eeAdress, CFG_VER ); - sprintf( txbuff, "%s%c", "DEFAULT PAREMETRS LOADED (and Stored in EEPROM)", EOL ); + EEPROM.put( eeadrInfo, tck.cfg ); + sprintf( txbuff, "%s:%d%c", "DEFAULT->EEPROM-v)", tck.cfg.ver, EOL ); serialCommand.sendCommand(txbuff); - } - -} - - -/* - * Custon Non-Blocking Delay() functions - * customDelayStart(unsigned long timeout) - * customDelayElapsed - */ -/** -unsigned long customDelay_startTime=0; -unsigned long customDelay_timeout=0; -void customDelayStart(unsigned long tout) { - customDelay_timeout=tout; - customDelay_startTime=millis(); } -boolean customDelayElapsed(){ - if((millis() - customDelay_startTime) > customDelay_timeout) { - return(true); - } - return(false); -} -**/