ver 0.9.9 / adde support for Relay Race (Network mode)

This commit is contained in:
Luca Borsari 2023-08-19 18:29:32 +02:00
parent 88755ac355
commit 0f10fff4fe
10 changed files with 516 additions and 270 deletions

View file

@ -1,5 +1,86 @@
# OLR-Arduino # OLR-Arduino - Minimalist race game with LED strip
Software running on OLR Board (Arduino) implementing a 'Car Race' where a 'car' is a light moving along a LED Strip (WS2812/WS2813).
Manage up to 4 'cars' and optionals Slope (with gravity effect), Pitlane, Electric cars mode (need to recharge battery in Pitlane), etc
Players use push-button controllers to move the 'cars' - The quicker you push the button the faster the light (car) moves along the LED Strip.
The software can receive configuration commands via Serial interface: (--see: doc/OLR_Protocol_Serial.pdf)
## Standalone mode
The software running on OLR Board (Arduino) implements a race as described above where up to 4 people can play using the push buttons.
## Network mode / Relay Race
A "NetworkClient" software, running on an external 'Host' (Computer, SBC,..) controls the Software running on OLR Board (Arduino).
Together they implements a Relay Race where 'cars' starts a Race in Racetrack 'A', than goes to Racetrack 'B', etc.
-- see: https://gitlab.com/open-led-race-network/networkclient
## Hardware
Tested on [Arduino Nano] and [Arduino Every].
Change settings in [olr-settings.h] to adapt to your hardware configuration.
```
///////////////////////////////////////////////////////////////////////////////
// __________________________LED Strip____________________________________ //
//
// For WS2812 LED Strip:
// _______ __ ____[WS2812 LED Strip connector]____
// |__Arduino_ | | |
// | +5V |>---------------------->| V+ (usually Red cable) |
// | GND |>---------------------->| GND (usually White cable) |
// | PIN_LED |>---->[R 500 ohms]----->| DI (data in - usually Green cable)|
// \_________/ \__________________________________/
//
//
// For WS2813 LED Strip:
// WS2813 have a 4th cable: Backup data lines (BI- usually Blue cable)
// Connect BI cable to GND
// ___________ ____[WS2813 LED Strip connector]_____
// |__Arduino_ | | |
// | +5V |>---------------------->| V+ (usually Red cable) |
// | GND |>----------------o----->| GND (usually White cable) |
// | | \---->| BI (backup in - usually Blue cable)|
// | PIN_LED |>---->[R 500 ohms]----->| DI (data in - usually Green cable) |
// \_________/ \___________________________________/
//
// __________________________Loudspeaker___________________________________ //
//
// ___________ _____________
// |__Arduino_ | | |
// | GND |>--------------------->o| Loudspeaker |
// | PIN_AUDIO |>----->[CAP 2uF]------>o| |
// \_________/ |_____________|
//
///////////////////////////////////////////////////////////////////////////////
enum hw_setup { // If you have a custom hardware (i.e not the OLR PCB),
PIN_LED = 2, // set PIN_LED and PIN_AUDIO accordingly
PIN_AUDIO = 3,
};
///////////////////////////////////////////////////////////////////////////////
// __________________ Digital Controllers (Buttons)_______________________ //
//
// ________________
// |____Arduino____ | ________________
// | GND |>-------->o| Button 1 (Red) |
// | DIG_CTRL_1_PIN |>-------->o|________________|
// | | __________________
// | GND |>-------->o| Button 2 (Green) |
// | DIG_CTRL_2_PIN |>-------->o|__________________|
// | | _________________
// | GND |>-------->o| Button 3 (Blue) |
// | DIG_CTRL_3_PIN |>-------->o|_________________|
// | | __________________
// | GND |>-------->o| Button 4 (White) |
// | DIG_CTRL_4_PIN |>-------->o|__________________|
// \______________/
//
///////////////////////////////////////////////////////////////////////////////
#define DIG_CTRL_1_PIN A2 // switch player 1 to PIN and GND
#define DIG_CTRL_2_PIN A0 // switch player 2 to PIN and GND
#define DIG_CTRL_3_PIN A3 // switch player 3 to PIN and GND
#define DIG_CTRL_4_PIN A1 // switch player 4 to PIN and GND
```
Minimalist race game with an LED strip.
4 Players and Pit Lane Version

View file

@ -1,6 +1,14 @@
Revisions history Revisions history
----------------- -----------------
* 2023-08-19: Ver 0.9.9 - Luca - Branch: "lab" ---> "master"
- Implements Network (Relay Race) functionality:
- Works as usual in Standalone mode
- Works with NetworkClient [0.9.8] (Relay Race)
- Demo mode now force a temporary [Autostart] mode when active
- Added [olr-settings.h] file containing Compile-time settings
- PIN_LED, PIN_AUDIO, etc
* 2023-07-20: Ver 0.9.8 - Luca - Branch: "lab" * 2023-07-20: Ver 0.9.8 - Luca - Branch: "lab"
- Added "Demo" mode: - Added "Demo" mode:
- When Board has [demo_mode=ON] in the EEPROM configuration, - When Board has [demo_mode=ON] in the EEPROM configuration,

View file

@ -1,10 +1,9 @@
#include "olr-controller.h" #include "olr-controller.h"
enum { enum {
DELTA_ANALOG = 5, DELTA_ANALOG = 5,
}; };
int DIGITAL_CTRL[4]; int DIGITAL_CTRL[MAX_PLAYERS];
static float const ACEL = 0.2; static float const ACEL = 0.2;
@ -24,7 +23,6 @@ void controller_setup( void ) {
DIGITAL_CTRL[CTRL_3]= DIG_CTRL_3_PIN; DIGITAL_CTRL[CTRL_3]= DIG_CTRL_3_PIN;
DIGITAL_CTRL[CTRL_4]= DIG_CTRL_4_PIN; DIGITAL_CTRL[CTRL_4]= DIG_CTRL_4_PIN;
pinMode( DIG_CTRL_1_PIN, INPUT_PULLUP); //pull up in adc pinMode( DIG_CTRL_1_PIN, INPUT_PULLUP); //pull up in adc
pinMode( DIG_CTRL_2_PIN, INPUT_PULLUP); pinMode( DIG_CTRL_2_PIN, INPUT_PULLUP);
pinMode( DIG_CTRL_3_PIN, INPUT_PULLUP); pinMode( DIG_CTRL_3_PIN, INPUT_PULLUP);
@ -53,7 +51,9 @@ byte controller_getStatus( controller_t* ct ) {
} }
else if( ct->mode == DEMO_MODE ){ else if( ct->mode == DEMO_MODE ){
ct->adc++; ct->adc++;
if( ct->adc >= 15){ int rnd = rand();
long threshold = 1800 - rnd;
if( ct->adc >= (threshold)){
ct->adc = 0; ct->adc = 0;
return 1; return 1;
} }

View file

@ -6,18 +6,15 @@
extern "C"{ extern "C"{
#endif #endif
#include "Arduino.h" #include <Arduino.h>
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
extern int DIGITAL_CTRL[]; // Global Array containig PINs used for the Digital Controllers (ex: Push Buttons) #include "olr-settings.h"
#define DIG_CTRL_1_PIN A2 // switch player 1 to PIN and GND extern int DIGITAL_CTRL[MAX_PLAYERS]; // Global Array containig PINs used for the Digital Controllers (ex: Push Buttons)
#define DIG_CTRL_2_PIN A0 // switch player 2 to PIN and GND //int DIGITAL_CTRL[MAX_PLAYERS]; // Global Array containig PINs used for the Digital Controllers (ex: Push Buttons)
#define DIG_CTRL_3_PIN A3 // switch player 3 to PIN and GND
#define DIG_CTRL_4_PIN A1 // switch player 4 to PIN and GND
enum ctr_idx { // Used to access controller by "name" (and not via zero-offset index) enum ctr_idx { // Used to access controller by "name" (and not via zero-offset index)
@ -29,7 +26,6 @@ enum ctr_idx { // Used to access controller by "name" (and not via zero-offset
#define PIN_VCC_ADC1 6 #define PIN_VCC_ADC1 6
#define PIN_VCC_ADC2 7 #define PIN_VCC_ADC2 7

View file

@ -2,7 +2,6 @@
#include "olr-lib.h" #include "olr-lib.h"
void car_init( car_t* car, controller_t* ct, uint32_t color ) { void car_init( car_t* car, controller_t* ct, uint32_t color ) {
car->ct = ct; car->ct = ct;
car->color = color; car->color = color;
@ -63,6 +62,7 @@ void process_aux_track( track_t* tck, car_t* car ){
} }
void process_main_track( track_t* tck, car_t* car ) { void process_main_track( track_t* tck, car_t* car ) {
struct cfgtrack const* cfg = &tck->cfg.track; struct cfgtrack const* cfg = &tck->cfg.track;
@ -127,12 +127,12 @@ bool ramp_isactive( track_t* tck ) {
void car_resetPosition( car_t* car, bool reset_speed) { void car_resetPosition( car_t* car, bool reset_speed) {
car->trackID = TRACK_MAIN; car->trackID = TRACK_MAIN;
car->speed = 0; if(reset_speed) car->speed = 0 ;
car->dist = 0; car->dist = 0;
car->dist_aux = 0; car->dist_aux = 0;
car->nlap = 1; car->nlap = 1;
car->leaving = false; car->leaving = false;
car->battery = 100; car->battery = 100; // Todo: propagate car's battery status in relay races !!!
} }
void car_setSpeed( car_t* car, float speed) { void car_setSpeed( car_t* car, float speed) {

View file

@ -1,4 +1,3 @@
#ifndef _OLR_LIB_h #ifndef _OLR_LIB_h
#define _OLR_LIB_h #define _OLR_LIB_h

View file

@ -10,6 +10,8 @@ extern "C"{
#include <stdint.h> #include <stdint.h>
#include <stdbool.h> #include <stdbool.h>
#include "olr-settings.h"
// Default values loaded on "D" command received (Serial Protocol) // Default values loaded on "D" command received (Serial Protocol)
////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////
#define MAXLED 300 #define MAXLED 300
@ -45,16 +47,17 @@ enum cfgpar {
LEN_UID = 16, LEN_UID = 16,
}; };
struct cfgrace{
bool startline; // Used only in OLRNetwork typedef struct cfgrace{
bool startline; // Standalone mode: Always 1
uint8_t nlap; uint8_t nlap;
uint8_t nrepeat; // Used only in OLRNetwork uint8_t nrepeat; // Standalone mode: Always 1
bool finishline; // Used only in OLRNetwork bool finishline; // Standalone mode: Always 1
}; } cfgrace_t;
struct cfgbattery{ // added in ver 0.9.7 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 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 min; // Battery charge does not goes below this "min" percentage
uint8_t speed_boost_scaler; uint8_t speed_boost_scaler;
} ; } ;
@ -87,7 +90,8 @@ struct brdinfo {
struct cfgparam { struct cfgparam {
uint8_t ver; // Version of this [cfgparam] struct 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) 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 cfgrace race; // added in ver 0.9.d
cfgrace_t race; // added in ver 0.9.d
struct cfgbattery battery; struct cfgbattery battery;
struct cfgtrack track; struct cfgtrack track;
struct cfgramp ramp; struct cfgramp ramp;

View file

@ -0,0 +1,140 @@
#ifndef _OLR_COMMON__h
#define _OLR_COMMON__h
#ifdef __cplusplus
extern "C"{
#endif
////////////////////
// Hardware Setup //
////////////////////
///////////////////////////////////////////////////////////////////////////////
// __________________________LED Strip____________________________________ //
//
// For WS2812 LED Strip:
// _______ __ ____[WS2812 LED Strip connector]____
// |__Arduino_ | | |
// | +5V |>---------------------->| V+ (usually Red cable) |
// | GND |>---------------------->| GND (usually White cable) |
// | PIN_LED |>---->[R 500 ohms]----->| DI (data in - usually Green cable)|
// \_________/ \__________________________________/
//
//
// For WS2813 LED Strip:
// WS2813 have a 4th cable: Backup data lines (BI- usually Blue cable)
// Connect BI cable to GND
// ___________ ____[WS2813 LED Strip connector]_____
// |__Arduino_ | | |
// | +5V |>---------------------->| V+ (usually Red cable) |
// | GND |>----------------o----->| GND (usually White cable) |
// | | \---->| BI (backup in - usually Blue cable)|
// | PIN_LED |>---->[R 500 ohms]----->| DI (data in - usually Green cable) |
// \_________/ \___________________________________/
//
// __________________________Loudspeaker___________________________________ //
//
// ___________ _____________
// |__Arduino_ | | |
// | GND |>--------------------->o| Loudspeaker |
// | PIN_AUDIO |>----->[CAP 2uF]------>o| |
// \_________/ |_____________|
//
///////////////////////////////////////////////////////////////////////////////
enum hw_setup { // If you have a custom hardware (i.e not the OLR PCB),
PIN_LED = 2, // set PIN_LED and PIN_AUDIO accordingly
PIN_AUDIO = 3,
};
///////////////////////////////////////////////////////////////////////////////
// __________________ Digital Controllers (Buttons)_______________________ //
//
// ________________
// |____Arduino____ | ________________
// | GND |>-------->o| Button 1 (Red) |
// | DIG_CTRL_1_PIN |>-------->o|________________|
// | | __________________
// | GND |>-------->o| Button 2 (Green) |
// | DIG_CTRL_2_PIN |>-------->o|__________________|
// | | _________________
// | GND |>-------->o| Button 3 (Blue) |
// | DIG_CTRL_3_PIN |>-------->o|_________________|
// | | __________________
// | GND |>-------->o| Button 4 (White) |
// | DIG_CTRL_4_PIN |>-------->o|__________________|
// \______________/
//
///////////////////////////////////////////////////////////////////////////////
#define DIG_CTRL_1_PIN A2 // switch player 1 to PIN and GND
#define DIG_CTRL_2_PIN A0 // switch player 2 to PIN and GND
#define DIG_CTRL_3_PIN A3 // switch player 3 to PIN and GND
#define DIG_CTRL_4_PIN A1 // switch player 4 to PIN and GND
////////////////////
// Software Setup //
////////////////////
///////////////////////////////////////////////////////////////////////////////
// __________________Colors setup (Racing lights, Ramp, etc)________________ //
//
#define COLOR1 track.Color(255,0,0) // Light controlled by DIG_CTRL_1_PIN
#define COLOR2 track.Color(0,255,0) // Light controlled by DIG_CTRL_2_PIN
#define COLOR3 track.Color(0,0,255) // Light controlled by DIG_CTRL_3_PIN
#define COLOR4 track.Color(255,255,255) // Light controlled by DIG_CTRL_4_PIN
#define COLOR_RAMP track.Color(64,0,64)
#define COLOR_COIN track.Color(40,34,0)
#define COLOR_BOXMARKS track.Color(64,64,0)
#define WARNING_BLINK_COLOR track.Color(32,20,0)
#define LED_SEMAPHORE 12 // LED in the Stip used as a Semaphore (Countdown phase)
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// _______________________________Delays ___________________________________ //
//
enum delays_setup { // If you have a custom hardware (i.e not the OLR PCB),
CONTDOWN_PHASE_DURATION = 2000, // (mSec)
CONTDOWN_STARTSOUND_DURATION = 40, // (mSec)
NEWRACE_DELAY = 5000, // (mSec)
INACTIVITY_TIMEOUT_DELAY = 300, // (Sec) When demo_mode is active, board goes into demo mode after this inactivity time
TELEMETRY_DELAY = 250, // (mSec) Telemetry data sent every TELEMETRY_DELAY mSec
};
///////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
// !!!!!!!!!!!!!!! DO NOT CHANGE ANYTHING BELOW !!!!!!!!!!!!!!!!! //
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //
////////////////////////////////////////////////////////////////////
enum internal_setup {
REC_COMMAND_BUFLEN = 32,// received 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
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
MAX_PLAYERS = 4, // DO NOT Change: Current software supports max 4 controllers
};
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View file

@ -0,0 +1,95 @@
#ifndef _OPEN_LED_RACE_h
#define _OPEN_LED_RACE_h
#ifdef __cplusplus
extern "C"{
#endif
#include "olr-settings.h"
#include "olr-lib.h"
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Definitons related to Serial Communication Protocol
/////////////////////////////////////////////////////////////////////////////////////////////////////
// !!! A change in definitions below requires a corresponding modification in:
// !!! - Protocol definition doc
// !!! - Every Host Software used with this Firmware (Configuration App, Network Race Enabler, ...)
/////////////////////////////////////////////////////////////////////////////////////////////////////
enum loglevel { // used in Serial Protocol "!" command (send log/error message)
LOG = 1,
WARNING = 2,
ERROR = 3
};
// Race Phases
enum phases {
IDLE = 0,
CONFIG,
CONFIG_OK,
READY,
COUNTDOWN,
RACING,
PAUSE,
RESUME,
COMPLETE,
RACE_PHASES
};
#define EOL '\n' // End of Command char used in Protocol
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
// Types for ack.type
enum resp{ //
NOK = -1,
NOTHING = 0,
OK = 1
};
// Answer sent after processing a command received from Host
typedef struct ack{
enum resp rp;
char type;
}ack_t;
typedef struct cfgcircuit{
uint8_t outtunnel;
} cfgcircuit_t;
typedef struct race {
cfgrace_t cfg;
cfgcircuit_t circ;
bool newcfg;
enum phases phase;
byte numcars;
byte winner;
bool demo_mode;
bool demo_mode_on_received;
bool demo_mode_off_received;
bool network_race;
} race_t;
/* ----------- Function prototypes ------------------- */
void sendResponse( ack_t *ack);
ack_t manageSerialCommand();
void printdebug( const char * msg, int errlevel );
void print_cars_positions( car_t* cars);
void run_racecycle( void );
void draw_winner( track_t* tck, uint32_t color);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

View file

@ -4,7 +4,7 @@
| | | |_ __ ___ _ __ | | | |__ | | | | | |__) |__ _ ___ ___ | | | |_ __ ___ _ __ | | | |__ | | | | | |__) |__ _ ___ ___
| | | | '_ \ / _ \ '_ \ | | | __| | | | | | _ // _` |/ __/ _ \ | | | | '_ \ / _ \ '_ \ | | | __| | | | | | _ // _` |/ __/ _ \
| |__| | |_) | __/ | | | | |____| |____| |__| | | | \ \ (_| | (_| __/ | |__| | |_) | __/ | | | | |____| |____| |__| | | | \ \ (_| | (_| __/
\____/| .__/ \___|_| |_| |______|______|_____/ |_| \_\__,_file:///home/buka/Desktop/OpenLedRace/Code/olr-arduino/Current/open-led-race|\___\___| \____/| .__/ \___|_| |_| |______|______|_____/ |_| \_\__,_|\___\___|
| | | |
|_| |_|
Open LED Race Open LED Race
@ -18,12 +18,10 @@
Current Version by: Current Version by:
LucaBuka (https://gitlab.com/lucabuka) LucaBuka (https://gitlab.com/lucabuka)
First public version by:
Angel Maldonado (https://gitlab.com/angeljmc)
Gerardo Barbarov (gbarbarov AT singulardevices DOT com) Gerardo Barbarov (gbarbarov AT singulardevices DOT com)
Angel Maldonado (https://gitlab.com/angeljmc)
Basen on original idea and 2 players code by: Basen on an original idea and 2 players code by:
Gerardo Barbarov for Arduino day Seville 2019 Gerardo Barbarov for Arduino day Seville 2019
https://github.com/gbarbarov/led-race https://github.com/gbarbarov/led-race
@ -33,163 +31,65 @@
*/ */
/**
* ____________HARDWARE CONFIGURATION____________________
* __ __
* __ Compile-time settings (PIN_LED, PIN_AUDIO, etc) __
* __ are defined in [olr-settings.h] file __
* ______________________________________________________
*/
char const softwareId[] = "A4P0"; // A4P -> A = Open LED Race, 4P0 = Game ID (4P = 4 Players, 0=Type 0) char const softwareId[] = "A4P0"; // A4P -> A = Open LED Race, 4P0 = Game ID (4P = 4 Players, 0=Type 0)
char const version[] = "0.9.8"; char const version[] = "0.9.9";
#include "open-led-race.h"
#include <Adafruit_NeoPixel.h> #include <Adafruit_NeoPixel.h>
#include <EEPROM.h> #include <EEPROM.h>
#include "olr-lib.h" #include "olr-lib.h"
#include "olr-controller.h"
#include "olr-param.h" #include "olr-param.h"
#include "SoftTimer.h" #include "SoftTimer.h"
#include "SerialCommand.h" #include "SerialCommand.h"
#define PIN_LED 2 // R 500 ohms to DI pin for WS2812 and WS2813, for WS2813 BI pin of first LED to GND , CAP 1000 uF to VCC 5v/GND,power supply 5V 2A
#define PIN_AUDIO 3 // through CAP 2uf to speaker 8 ohms
#define REC_COMMAND_BUFLEN 32 // received 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)
#define COLOR2 track.Color(0,255,0)
#define COLOR3 track.Color(0,0,255)
#define COLOR4 track.Color(255,255,255)
#define COLOR_RAMP track.Color(64,0,64)
#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
#define NEWRACE_DELAY 5000
#define INACTIVITY_TIMEOUT_DELAY 15000
enum{
MAX_CARS = 4,
};
enum loglevel { // used in Serial Protocol "!" command (send log/error messageS)
ECHO = 0,
DISABLE = 0,
LOG = 1,
WARNING = 2,
ERROR = 3
};
enum resp{
NOK = -1,
NOTHING = 0,
OK = 1
};
typedef struct ack{
enum resp rp;
char type;
}ack_t;
struct cfgcircuit{
uint8_t outtunnel;
};
enum phases{
IDLE = 0,
CONFIG,
CONFIG_OK,
READY,
COUNTDOWN,
RACING,
PAUSE,
RESUME,
COMPLETE,
RACE_PHASES
};
struct race{
struct cfgrace cfg;
struct cfgcircuit circ;
bool newcfg;
enum phases phase;
byte numcars;
byte winner;
bool demo_mode;
bool demo_mode_on_received;
bool demo_mode_off_received;
bool network_race;
};
byte SMOTOR=0;
int TBEEP=0;
int FBEEP=0;
/*------------------------------------------------------*/ /*------------------------------------------------------*/
enum loglevel verbose = DISABLE;
static struct race race;
static car_t cars[ MAX_CARS ];
static controller_t switchs[ MAX_CARS ];
static track_t tck;
static int const eeadrInfo = 0;
static unsigned long last_telemetry_millis = 0;
unsigned long last_activity_millis = 0;
SoftTimer startRace_delay = SoftTimer(); // non blocking delay() for Autostart, Countdown
SoftTimer demoMode_delay = SoftTimer(); // non blocking delay() for activate Demo Mode on inactivity
// Used to manage countdown phases
int countdown_phase=1;
bool countdown_new_phase=true;
int win_music[] = { int win_music[] = {
2637, 2637, 0, 2637, 2637, 2637, 0, 2637,
0, 2093, 2637, 0, 0, 2093, 2637, 0,
3136 3136
}; };
/*------------------------------------------------------*/
char tracksID[ NUM_TRACKS ][2] ={"U","M","B","I","O"};
/* ----------- Function prototypes ------------------- */ static race_t race;
static car_t cars[ MAX_PLAYERS ];
static controller_t switchs[ MAX_PLAYERS ];
static track_t tck;
char tracksID[ NUM_TRACKS ][2] ={"U","M","B","I","O"};
void sendResponse( ack_t *ack); static int countdown_phase=1;
static bool countdown_new_phase=true;
ack_t manageSerialCommand(); static int const eeadrInfo = 0;
// non blocking delays
SoftTimer startRace_delay = SoftTimer(); // Autostart, Countdown
SoftTimer demoMode_delay = SoftTimer(); // Activate Demo Mode on inactivity
SoftTimer telemetry_delay = SoftTimer(0); // Send Telemetry data
static byte s_motor=0;
static int t_beep=0;
static int f_beep=0;
void printdebug( const char * msg, int errlevel );
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() char cmd[REC_COMMAND_BUFLEN]; // Stores command received by ReadSerialComand()
SerialCommand serialCommand = SerialCommand(cmd, REC_COMMAND_BUFLEN, EOL, &Serial); // get complete command from serial SerialCommand serialCommand = SerialCommand(cmd, REC_COMMAND_BUFLEN, EOL, &Serial); // get complete command from serial
char txbuff[TX_COMMAND_BUFLEN]; char txbuff[TX_COMMAND_BUFLEN];
Adafruit_NeoPixel track; Adafruit_NeoPixel track;
static uint32_t car_color[]={ static uint32_t car_color[]={
COLOR1, COLOR1,
COLOR2, COLOR2,
@ -235,10 +135,10 @@ void setup() {
init_cars(race.numcars); init_cars(race.numcars);
track.begin(); track.begin();
strip_clear( &tck ); strip_clear( &tck , false);
// Check Box before Physic/Sound to allow user to have Box and Physics with no sound // Check Box before Physic/Sound to allow user to have Box and Physics with no sound
if(digitalRead(DIGITAL_CTRL[CTRL_2])==0 || param_option_is_active(&tck.cfg, BOX_MODE_OPTION) ) { //push switch 2 on reset for activate boxes (pit lane) if(controller_isActive( DIGITAL_CTRL[CTRL_2]) || param_option_is_active(&tck.cfg, BOX_MODE_OPTION) ) { //push switch 2 on reset for activate boxes (pit lane)
box_init( &tck ); box_init( &tck );
track_configure( &tck, tck.cfg.track.nled_total - tck.cfg.track.box_len ); track_configure( &tck, tck.cfg.track.nled_total - tck.cfg.track.box_len );
draw_box_entrypoint( &tck ); draw_box_entrypoint( &tck );
@ -246,13 +146,13 @@ void setup() {
track_configure( &tck, 0 ); track_configure( &tck, 0 );
} }
if( digitalRead(DIGITAL_CTRL[CTRL_1])==0 || param_option_is_active(&tck.cfg, SLOPE_MODE_OPTION) ) { // push switch 1 on reset for activate physics if( controller_isActive( DIGITAL_CTRL[CTRL_3]) || param_option_is_active(&tck.cfg, SLOPE_MODE_OPTION) ) { // push switch 1 on reset for activate physics
ramp_init( &tck ); ramp_init( &tck );
draw_ramp( &tck ); draw_ramp( &tck );
track.show(); track.show();
delay(2000); delay(2000);
if ( digitalRead( DIGITAL_CTRL[CTRL_1] ) == 0 ) { //retain push switch on reset for activate FX sound if ( controller_isActive( DIGITAL_CTRL[CTRL_1] ) ) { //retain push switch on reset for activate FX sound
SMOTOR=1; s_motor=1;
tone(PIN_AUDIO,100);} tone(PIN_AUDIO,100);}
} }
@ -268,7 +168,9 @@ void setup() {
startRace_delay.start(0); // first race starts with no delay startRace_delay.start(0); // first race starts with no delay
race.phase = READY; // READY is the first status for Standalone mode race.phase = READY; // READY is the first status for Standalone mode
last_activity_millis = millis(); // last_activity_millis = millis();
} }
/* /*
@ -287,7 +189,7 @@ void loop() {
exit_demo_mode(); exit_demo_mode();
} }
// If demo_mode option is set in board configuration // If demo_mode option is set in board configuration
// -> Enter demo mode after INACTIVITY_TIMEOUT_DELAY // -> Enter demo mode after INACTIVITY_TIMEOUT_DELAY sec
if( race.demo_mode_on_received || (param_option_is_active(&tck.cfg, DEMO_MODE_OPTION) && race.demo_mode==false && ready_for_demo_mode()) ) { if( race.demo_mode_on_received || (param_option_is_active(&tck.cfg, DEMO_MODE_OPTION) && race.demo_mode==false && ready_for_demo_mode()) ) {
activate_demo_mode(); activate_demo_mode();
} }
@ -304,63 +206,73 @@ void loop() {
case CONFIG: case CONFIG:
{ {
if( race.newcfg ) { if( race.newcfg ) { // Exit_Config command received
race.newcfg = false; race.newcfg = false;
countdownReset(); countdownReset();
startRace_delay.start(0); startRace_delay.start(0);
// for Standalone mode, gets into READY status // for Standalone mode, gets into READY status
// for Network races gets into CONFIGURATION OK statue // for Network races gets into CONFIGURATION OK status
race.phase = ( race.network_race == false ) ? READY : CONFIG_OK; race.phase = ( race.network_race == false ) ? READY : CONFIG_OK;
send_phase( race.phase ); send_phase( race.phase );
} }
} }
break; break;
case CONFIG_OK: // OLR Network only
case READY:
{ {
if(param_option_is_active(&tck.cfg, AUTOSTART_MODE_OPTION)){ // Auto-Start Mode ON ; // In a Relay Race the configuration is sent (via 'C' command) by the
if(startRace_delay.elapsed()) { // Host ("Nerwork Client" program running on another Computer)
for( int i = 0; i < race.numcars; ++i) { // When the board reach the CONFIG_OK status...it does nothing but wait for
car_resetPosition( &cars[i], true ); // the next Command coming form the Host.
cars[i].repeats = 0; // Same thing for the IDLE status (reached at the end of a relay race)
} // In other words, in Network mode (Relay races), some Status changes comes from the Host
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], true );
//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; break;
case READY:
{
bool goOn=false;
if( race.cfg.startline ) { // Standalone: Always true - Network mode: only racetrack where race starts
if(param_option_is_active(&tck.cfg,AUTOSTART_MODE_OPTION) || race.demo_mode ) { // Autostart parameters ON
if(startRace_delay.elapsed()) goOn=true; // Automatically start Countdown after a defined Delay
// Note: In DemoMode always use AutoStart
} else { // Autostart OFF:
int pstart=0; // Wait for every controller be active (button pressed) to start Countdown
strip_clear( &tck, true );
for( int i = 0; i < race.numcars; ++i) {
if (controller_getStatus(cars[i].ct)==false) {
track.setPixelColor(i,cars[i].color);
pstart++;
}
}
track.setPixelColor(LED_SEMAPHORE , ((millis()/5)%64)*0x010100 );
track.show();
// if every controller activated -> Ready for Countdown
if (pstart==race.numcars) goOn=true;
};
}
if(goOn || (!race.cfg.startline)) { // Standalone mode is Ready for Countdown __OR__ Network mode and Race does not starts here
for( int i = 0; i < race.numcars; ++i) {
car_resetPosition( &cars[i], true );
cars[i].repeats = 0;
cars[i].st = CAR_WAITING; // Network race -> cleanup status of previous race
}
tck.ledcoin = COIN_RESET;
race.phase = COUNTDOWN;
if(race.network_race != true) send_phase( race.phase );
srand((unsigned long) analogRead(A6) + analogRead(A7)); // used in demo_mode (see olr_controllers.h)
}
}
break;
case COUNTDOWN: case COUNTDOWN:
{ {
if( race.cfg.startline ){ if( race.cfg.startline ) { // Standalone: Always true - Network mode: only racetrack where race starts
// Countdown: semaphore and tones // Countdown: semaphore and tones
if(start_race_done()) { // Countdown done if(start_race_done()) { // Countdown done
for( int i = 0; i < race.numcars; ++i ) { for( int i = 0; i < race.numcars; ++i ) {
@ -375,12 +287,7 @@ void loop() {
case RACING: case RACING:
{ {
strip_clear( &tck ); strip_clear( &tck, true );
if( ramp_isactive( &tck ) )
draw_ramp( &tck );
if( box_isactive( &tck ) )
draw_box_entrypoint( &tck );
if( box_isactive( &tck ) ) { if( box_isactive( &tck ) ) {
if( tck.ledcoin == COIN_RESET ) { if( tck.ledcoin == COIN_RESET ) {
@ -416,14 +323,14 @@ void loop() {
} }
track.show(); track.show();
if (SMOTOR==1) tone(PIN_AUDIO,FBEEP+int(cars[0].speed*440*1)+int(cars[1].speed*440*2)+int(cars[2].speed*440*3)+int(cars[3].speed*440*4)); if (s_motor==1) tone(PIN_AUDIO,f_beep+int(cars[0].speed*440*1)+int(cars[1].speed*440*2)+int(cars[2].speed*440*3)+int(cars[3].speed*440*4));
if (TBEEP>0) {TBEEP--;} else {FBEEP=0;}; if (t_beep>0) {t_beep--;} else {f_beep=0;};
// Print p command!!! // Send Telemetry data
unsigned long nowmillis = millis(); if(telemetry_delay.elapsed()) {
if( abs( nowmillis - last_telemetry_millis ) > 250 ){
last_telemetry_millis = nowmillis;
print_cars_positions( cars ); print_cars_positions( cars );
telemetry_delay.start(TELEMETRY_DELAY);
} }
// ---------------- // ----------------
} }
@ -431,13 +338,11 @@ void loop() {
case COMPLETE : case COMPLETE :
{ {
strip_clear( &tck ); strip_clear( &tck, false );
track.show(); track.show();
if ( race.cfg.finishline ){ draw_winner( &tck, cars[race.winner].color );
draw_winner( &tck, cars[race.winner].color ); sound_winner( &tck, race.winner );
sound_winner( &tck, race.winner ); strip_clear( &tck, false );
strip_clear( &tck );
}
track.show(); track.show();
startRace_delay.start(NEWRACE_DELAY); startRace_delay.start(NEWRACE_DELAY);
@ -448,15 +353,9 @@ void loop() {
} }
break; break;
case CONFIG_OK: // OLR Network only
case IDLE: // OLR Network only case IDLE: // OLR Network only
{ {
; // In a Relay Race the configuration is sent (via 'C' command) by the ; // -- see comment in CONFIG_OK status
// Host ("Nerwork Client" program running on another Computer)
// When the board reach the CONFIG_OK status...it does nothing but wait for
// the next Command coming form the Host.
// Same thing for the IDLE status (reached at the end of a relay race)
// In other words, in Relay Races, some Status changes comes from the Host
} }
break; break;
@ -498,11 +397,11 @@ bool players_actity(uint8_t numcars ) {
} }
/* /*
* Check if Controllers (players) were incative for more than INACTIVITY_TIMEOUT_DELAY * Check if Controllers (players) were incative for more than INACTIVITY_TIMEOUT_DELAY sec
*/ */
bool ready_for_demo_mode(void) { bool ready_for_demo_mode(void) {
if(players_actity(race.numcars)){ if(players_actity(race.numcars)){
demoMode_delay.start(INACTIVITY_TIMEOUT_DELAY); // Reset timeout when somebody is using controllers demoMode_delay.start(INACTIVITY_TIMEOUT_DELAY * 1000); // Reset timeout when somebody is using controllers
} }
return (demoMode_delay.elapsed()); return (demoMode_delay.elapsed());
} }
@ -516,7 +415,7 @@ void activate_demo_mode(void){
race.demo_mode = true; race.demo_mode = true;
race.demo_mode_on_received = false; // reset flag race.demo_mode_on_received = false; // reset flag
set_controllers_mode(race.numcars, DEMO_MODE ) ; set_controllers_mode(race.numcars, DEMO_MODE ) ;
race.winner=0; // Fake set (used in Status=Complete by draw_winner()) race.winner=0; // force a fake winner (used in Status=Complete by draw_winner())
race.phase = COMPLETE; race.phase = COMPLETE;
sprintf(txbuff, "%c%d%c", 'M', 1 , EOL ); sprintf(txbuff, "%c%d%c", 'M', 1 , EOL );
@ -531,7 +430,7 @@ void exit_demo_mode(void){
race.demo_mode = false; race.demo_mode = false;
race.demo_mode_off_received = false; // reset flag race.demo_mode_off_received = false; // reset flag
set_controllers_mode(race.numcars, DIGITAL_MODE ) ; set_controllers_mode(race.numcars, DIGITAL_MODE ) ;
race.winner=0; // Fake set (used in Status=Complete by draw_winner()) race.winner=0; // force a fake winner (used in Status=Complete by draw_winner())
race.phase = COMPLETE; race.phase = COMPLETE;
sprintf(txbuff, "%c%d%c", 'M', 0 , EOL ); sprintf(txbuff, "%c%d%c", 'M', 0 , EOL );
@ -544,7 +443,7 @@ void send_phase( int phase ) {
} }
void run_racecycle( car_t *car, int i ) { void run_racecycle( car_t *car, int caridx ) {
struct cfgtrack const* cfg = &tck.cfg.track; struct cfgtrack const* cfg = &tck.cfg.track;
// if( car->st == CAR_COMING ) { // OLR Network only // if( car->st == CAR_COMING ) { // OLR Network only
@ -552,29 +451,16 @@ void run_racecycle( car_t *car, int i ) {
// } // }
if( car->st == CAR_ENTER ) { if( car->st == CAR_ENTER ) {
// Standalone mode => On Race start the Speed get RESET (speed=0) // Standalone mode => On Race start the Speed get RESET (speed=0)
// Network race => Car speed set when receiving the Car_Enter Serial command // Network race => Car speed set when receiving the Car_Enter Serial command
(race.network_race == true) ? car_resetPosition( car, false ) : car_resetPosition( car, true ); (race.network_race == true) ? car_resetPosition( car, false ) : car_resetPosition( car, true );
// In DEMO_MODE Red car gets a different bost on start (allows to see all cars in the circuit)
if( switchs[0].mode == DEMO_MODE ){
cars[0].speed = 1.2;
float dec = 0.4;
for( uint8_t i = 1; i < race.numcars; ++i ) {
cars[i].speed = 1.2 - dec;
dec += 0.4;
}
}
if( car->repeats < race.cfg.nrepeat ) if( car->repeats < race.cfg.nrepeat )
car->st = CAR_RACING; car->st = CAR_RACING;
else else
car->st = CAR_GO_OUT; car->st = CAR_GO_OUT;
} }
if( car->st == CAR_RACING ) { if( car->st == CAR_RACING ) {
update_track( &tck, car ); update_track( &tck, car );
car_updateController( car ); car_updateController( car );
@ -600,15 +486,15 @@ void run_racecycle( car_t *car, int i ) {
if( car->st == CAR_LEAVING ) { // OLR Network only if( car->st == CAR_LEAVING ) { // OLR Network only
car->st = CAR_RACING; car->st = CAR_RACING;
sprintf( txbuff, "r%d%c", i + 1, EOL ); sprintf( txbuff, "r%d%c", caridx + 1, EOL );
serialCommand.sendCommand(txbuff); serialCommand.sendCommand(txbuff);
} }
if( car->st == CAR_GO_OUT ) { // OLR Network only if( car->st == CAR_GO_OUT ) { // OLR Network only
car->st = CAR_WAITING; car->st = CAR_WAITING;
//#warning Insert function to map speed! //map car number in 3 higher bits and car speed in 5 lower bits
byte const speed = car->speed * 10; byte const speed = car->speed * 10;
byte const data = (i + 1) << 5 | ( 0b00011111 & speed ); byte const data = (caridx + 1) << 5 | ( 0b00011111 & speed );
sprintf( txbuff, "s%c%c", data, EOL ); sprintf( txbuff, "s%c%c", data, EOL );
serialCommand.sendCommand(txbuff);; serialCommand.sendCommand(txbuff);;
car_resetPosition( car, true ); car_resetPosition( car, true );
@ -617,7 +503,7 @@ void run_racecycle( car_t *car, int i ) {
if ( car->st == CAR_FINISH ){ if ( car->st == CAR_FINISH ){
car->trackID = NOT_TRACK; car->trackID = NOT_TRACK;
sprintf( txbuff, "w%d%c", i + 1, EOL ); sprintf( txbuff, "w%d%c", caridx + 1, EOL );
serialCommand.sendCommand(txbuff); serialCommand.sendCommand(txbuff);
car_resetPosition(car, true); car_resetPosition(car, true);
@ -666,15 +552,13 @@ void print_cars_positions( car_t* cars ) {
/* /*
* non-blocking version * non-blocking
*/ */
boolean start_race_done( ) { boolean start_race_done( ) {
if(countdown_new_phase){ if(countdown_new_phase){
countdown_new_phase=false; countdown_new_phase=false;
startRace_delay.start(CONTDOWN_PHASE_DURATION); startRace_delay.start(CONTDOWN_PHASE_DURATION);
strip_clear( &tck ); strip_clear( &tck , true);
if(ramp_isactive( &tck )) draw_ramp( &tck );
if(box_isactive( &tck )) draw_box_entrypoint( &tck );
switch(countdown_phase) { switch(countdown_phase) {
case 1: case 1:
tone(PIN_AUDIO,400); tone(PIN_AUDIO,400);
@ -730,13 +614,20 @@ void sound_winner( track_t* tck, byte winner ) {
} }
void strip_clear( track_t* tck ) { void strip_clear( track_t* tck, bool show_settings ) {
struct cfgtrack const* cfg = &tck->cfg.track; struct cfgtrack const* cfg = &tck->cfg.track;
for( int i=0; i < cfg->nled_main; i++) for( int i=0; i < cfg->nled_main; i++)
track.setPixelColor( i, track.Color(0,0,0) ); track.setPixelColor( i, track.Color(0,0,0) );
for( int i=0; i < cfg->nled_aux; i++) for( int i=0; i < cfg->nled_aux; i++)
track.setPixelColor( cfg->nled_main+i, track.Color(0,0,0) ); track.setPixelColor( cfg->nled_main+i, track.Color(0,0,0) );
if(show_settings) {
if( ramp_isactive( tck ))
draw_ramp( tck );
if( box_isactive( tck ) )
draw_box_entrypoint( tck );
}
} }
@ -805,11 +696,7 @@ void draw_car( track_t* tck, car_t* car ) {
* *
*/ */
void show_cfgpars_onstrip(){ void show_cfgpars_onstrip(){
strip_clear( &tck ); strip_clear( &tck, true );
if( ramp_isactive( &tck ) )
draw_ramp( &tck );
if( box_isactive( &tck ) )
draw_box_entrypoint( &tck );
track.show(); track.show();
} }
@ -857,6 +744,7 @@ ack_t manageSerialCommand() {
int clen = serialCommand.checkSerial(); int clen = serialCommand.checkSerial();
if(clen == 0) return ack; // No commands received if(clen == 0) return ack; // No commands received
if(clen < 0) { // Error receiving command if(clen < 0) { // Error receiving command
sprintf( txbuff, "Error reading serial command:[%d]",clen); sprintf( txbuff, "Error reading serial command:[%d]",clen);
printdebug( txbuff, WARNING ); printdebug( txbuff, WARNING );
@ -865,7 +753,16 @@ ack_t manageSerialCommand() {
// clen > 0 ---> Command with length=clen ready in cmd[] // clen > 0 ---> Command with length=clen ready in cmd[]
ack.rp=NOK; ack.rp=NOK;
// Debug only
//if(race.network_race == true) {
// sprintf( txbuff, "Recv cmd:%s", cmd);
// printdebug( txbuff, WARNING );
//}
switch (cmd[0]) { switch (cmd[0]) {
case '#': // Handshake case '#': // Handshake
{ {
ack.type = cmd[0]; ack.type = cmd[0];
@ -900,10 +797,21 @@ ack_t manageSerialCommand() {
{ {
ack.type = cmd[0]; ack.type = cmd[0];
uint8_t const phase = atoi( cmd + 1); uint8_t const phase = atoi( cmd + 1);
/**
* Reintrodotto momentaneamente R1=enter config per testare RelayRace con Networkclient esistente
// Does not accept anymore R=1 as Enter Configuration / Use command @ instead // Does not accept anymore R=1 as Enter Configuration / Use command @ instead
if( 0 > phase || RACE_PHASES <= phase || phase == CONFIG) return ack; if( 0 > phase || RACE_PHASES <= phase || phase == CONFIG) return ack;
race.phase = (enum phases) phase; race.phase = (enum phases) phase;
ack.rp = OK; ack.rp = OK;
**/
// Codice vecchio con R1=Enter Configuration
if( 0 > phase || RACE_PHASES <= phase) return ack;
race.phase = (enum phases) phase;
ack.rp = OK;
if ( race.phase == CONFIG ) { // accept R1 as a EnterConfigurationMode command - DEPRECATED
enter_configuration_mode();
}
} }
break; break;
@ -917,8 +825,9 @@ ack_t manageSerialCommand() {
cars[ncar-1].st = CAR_ENTER; cars[ncar-1].st = CAR_ENTER;
cars[ncar-1].speed = (float) speed / 10; cars[ncar-1].speed = (float) speed / 10;
ack.rp = OK; ack.rp = OK;
ack.rp = NOTHING;
if( false ) { if( false ) {
sprintf( txbuff, "%s %d, %s %d, %s %d", "CAR: ", ncar, "STATUS: ", cars[ncar-1].st, "SPEED: ", (int)cars[ncar-1].speed * 10 ); sprintf( txbuff, "%s %d, %s %d, %s %d", "CAR: ", ncar, "STATUS: ", cars[ncar-1].st, "SPEED: ", (int)(cars[ncar-1].speed * 10) );
printdebug( txbuff, LOG ); printdebug( txbuff, LOG );
} }
} }
@ -938,6 +847,20 @@ ack_t manageSerialCommand() {
} }
break; break;
case 'w' : // Car Wins the race - OLR Network only
// Standalone mode: Board _NEVER_ receives a 'w' command !!!
{ // Network mode: 1) Command "w" sent by the Board where the race ends
// 2) Every other participant (Board) receives 'w' command
ack.type = cmd[0];
byte const ncar = atoi( cmd + 1);
if( 0 >= ncar || race.numcars < ncar) return ack;
if( race.network_race && (!race.cfg.finishline)) {
race.winner = (byte) ncar-1; // Set the Winner
}
ack.rp = NOTHING;
}
break;
case 'C' : //Parse race configuration -> C1,2,3,0 case 'C' : //Parse race configuration -> C1,2,3,0
{ {
@ -1339,7 +1262,7 @@ void printdebug( const char * msg, int errlevel ) {
*/ */
void enter_configuration_mode(){ void enter_configuration_mode(){
noTone(PIN_AUDIO); noTone(PIN_AUDIO);
strip_clear( &tck ); strip_clear( &tck, false );
track.show(); track.show();
} }
@ -1357,8 +1280,8 @@ void param_load( struct cfgparam* cfg ) {
EEPROM.get( eeadrInfo, tck.cfg ); EEPROM.get( eeadrInfo, tck.cfg );
sprintf( txbuff, "%s:%d%c", "EEPROM-v", tck.cfg.ver, EOL ); // sprintf( txbuff, "%s:%d%c", "EEPROM-v", tck.cfg.ver, EOL );
serialCommand.sendCommand(txbuff); // serialCommand.sendCommand(txbuff);
if ( tck.cfg.ver != CFGPARAM_VER ) { // [cfgparam.ver] read form EEPROM != [#define CFGPARAM_VER] in the code 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 // Each time a new version of the code modify the [cfgparam] struct, [#define CFGPARAM_VER] is also