From cc1c937458f3429bf1eb053133aa366cc147052b Mon Sep 17 00:00:00 2001 From: Luca Borsari Date: Thu, 30 Jul 2020 12:10:39 +0200 Subject: [PATCH] Ver 0.9.d --- changelog.txt | 17 + doc/30_Standalone_Protocol_Serial.md | 294 +++++++----- open-led-race/AsyncSerialLib.cpp | 678 +++++++++++++-------------- open-led-race/AsyncSerialLib.h | 202 ++++---- open-led-race/olr-controller.c | 1 - open-led-race/olr-lib.c | 49 +- open-led-race/olr-lib.h | 9 +- open-led-race/olr-param.c | 18 +- open-led-race/olr-param.h | 22 +- open-led-race/open-led-race.ino | 149 ++++-- 10 files changed, 829 insertions(+), 610 deletions(-) diff --git a/changelog.txt b/changelog.txt index ecd53c5..de4931a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,6 +1,23 @@ Revisions history ----------------- + * 2020-07-28: Ver 0.9.d - Luca + - Tested OK on Arduino Every + - Configuration Values NOW SAVED in EEPROM to enable + OLR Configuration via a Software client running on a computer. + - Laps (Single Race duration) + - Led Number in the Racetrack (MAXLED) + - Box Length + - Ramp: init,center,end,high + The User Interface running on the Computer is currently under development. + Advanced users can already change Cfg Values via Serial (See Protocol documentation) + Function Activation: + Even if you can configure Box and Slope parameters, the activation is + still managed by user via Controls + + - Winner Visual effect changed (too long for 1200 MAXLED) + + * 2020-07-16: Ver 0.9.c - Luca - Changes in [I/O Pin]<>[Car Color] association to match the desired Phisical Buttons Layout (Quick Start Guide) diff --git a/doc/30_Standalone_Protocol_Serial.md b/doc/30_Standalone_Protocol_Serial.md index b52fcd3..ac6dea5 100644 --- a/doc/30_Standalone_Protocol_Serial.md +++ b/doc/30_Standalone_Protocol_Serial.md @@ -1,15 +1,6 @@ # Serial Protocol (OLRBoard←→Host) - - -- - - - -**Revisions:** -- - -- - - -- In the present doc the terms Board and Host indicate: - ***Board***: OLR Board - The microcontroller managing the led strip (Arduino) - ***Host***: The Host running the OpenLedRace COnfiguration software (PC, RPI, etc) @@ -25,16 +16,11 @@ The Board is currently connected to the Host via Serial interface (USB) ## Message formats - Messages are composed by 2 parts: **Command**, **Parameters**. - - Messages with multiple parameters, the char **'.'** is used as **"Parameters Separator"** + - Messages with multiple parameters, the char **','** is used as **"Parameters Separator"** - Messages sending back command confirmation uses "**commandOK**" and "**commandNOK**" - - Example: **CNOK** is the 'error' answer sent for a C command - - Telemetry Messages (see below) have fixed lenght parameters, and no - message terminator. - - Any other message ends with the "EOC" (End Of Command) char: - - [LF] - Line Feed = ASCII 10/0x0A = new line = ‘\n’ - - The following command, for example, is used by a OLR Device (Arduino) - to send the “Setup OK - Configuration Complete” message: - - `R0[LF] ` + - Example: **CNOK** is the 'error' answer sent for a **C** command + -Messages end with the "EOC" (End Of Command) char: + - [EOC] - Line Feed = ASCII 10/0x0A = new line = ‘\n’ * * * @@ -47,12 +33,13 @@ $ | Get UID | Get Board Unique Id % | Get Version | Get Board Software version : | Set Unique ID | Set Board Unique ID ! | Send log/error msg | Send a log/error message to peer -**C** | **C**onfiguration Race | Set basic race configuration +**C** | **C**onfiguration Race | Set basic race configuration (Number of **laps** for a single race) +**R** | Race phase | Command used to Change/Notify current Race phase +**T** | Track length configuration | Command used to configure the Total Number of LEDs in the track. +**B** | Box length configuration | Command used to configure the number of LEDS at the end of the LED Strip reserved for Boxes (Pitlane). +**A** | Ramp configuration | Command used to configure the Ramp in the track. +**D** | Load Track and ramp defult | Command used to Reset to Default parameters (Race, Ramp, Pitlane) **Q** | Query board cfg | Host request the current situation of the Config Parameters Set -**R** | Race phase | Command used to notify current Race phase -**T** | Track configuration | Command used to configure a new track setup. -**A** | Ramp configuration | Command used to configure a ramp in the track. -**D** | Load Track and ramp defult | Command used to set default parameter for ramp and track **p** | Car current position in OLR | Current position of the car in the OLR **w** | Car Win the Race | A car just win the current race @@ -64,33 +51,32 @@ $ | Get UID | Get Board Unique Id In the following sections the column "**Initiate**" contains the id of the board sending the message. - ***B*** - ***Board***: OLR Board (Arduino Nano) - - ***H*** - ***Host***: Host where the OpenLedRace Manger program is running (RPI, PC, ...). + - ***H*** - ***Host***: Host where the OpenLedRace Manger program is running (Computer). Same rule applies to the "***From***" column in "***Response***" Some commands may be originated by both peers (ex: Handshake command) -The string **_[LF]_** indicates the EOC (End of Command) char = "line feed / new line", (ASCII 10/0A) +The string **_[EOC]_** indicates the EOC (End of Command) char, currently = "line feed", (ASCII 0A) - - - -### [#] - Protocol Handshaking [Implmented] +### [#] - Protocol Handshaking |initiate| Syntax | Description |------|--------|------------ -|B, H|**#**_[LF]_ | **Protocol Handshaking** +|B, H|**#**_[EOC]_ | **Protocol Handshaking** || | Sent to initialize a connection (Board and Host) | |**Response**| **From** | **Notes** -|**#**_[LF]_ |H, B | The connection opens succesfully when a “**#**” is received 'back' from the peer -||| **Please Note:** -||| Board and Host send back only one ACK (send back a '#' just once) +|**#**_[EOC]_ |H, B | The connection opens succesfully when a “**#**” is received 'back' from the peer + - - - ### [@] - Reset [To be implemented] |initiate| Syntax | Description |------|--------|------------ -|H |**@**_[LF]_|**OLR Board Reset request** +|H |**@**_[EOC]_|**OLR Board Reset request** | | | Sent from Host to Reset the OLR Board to the initial state (before handshake) |**Response**| **From** | **Notes** | | | No response expected from Board @@ -98,78 +84,95 @@ The string **_[LF]_** indicates the EOC (End of Command) char = "line feed / new - - - -### [$] - Get Board UID [Implemented] +### [$] - Get Board UID | initiate | Syntax | Description | |----------|-------------|------------------------------------| -| H | **$**_[LF]_ | **OLR Board UID request** | +| H | **$**_[EOC]_ | **OLR Board UID request** | | | | Sent from Host to get Board's UID | |**Response**| **From** | **Notes** |------|--------|------------ -|**$**Id[LF] | B | Send the UID strings +|**$**Id[EOC] | B | Send the UID strings #### UID String format --- to be defined +Unique Board Id (UID) string format:
+**^[\x33-\x7E]{16}$** + +- Lenght: 16 chars +- Valid Chars: Ascii 7-bit Printable Chars excluding ‘space’=ASCII 32 (this means ASCII chars between 33 (0x21) and 126 (0x7E) inclusive + + #### Examples |Origin|Command|| |---|----|----| -|H|**$[LF]**| Host send a **get info** request -|B|**?3179c3ec6e28a[LF]**|The message from the Board contains Id="3179c3ec6e28a" +|H|**$[EOC]**| Host send a **get info** request +|B|**?3179c3ec6e28a[EOC]**|Board answer: Id="3179c3ec6e28a" |Origin|Command|| |---|----|----| -|H|**?[LF]**| Host send a **get info** request -|B|**?[LF]**|The message from the Board indicates ID not set. +|H|**?[EOC]**| Host send a **get info** request +|B|**??????????[EOC]**|The Board send back an invalid UID (if you are looking at it in a Serial Console, you usually see a bunch of question marks or other chars / non-printable ASCII).
This usually happens when the UID is not set yet, so the Board send back the contents of the area of the EEPROM where the UID is supposed to be stored. - - - -### [%] - Get Software Version [Implemented] +### [%] - Get Software Version Used to check software compatibility between Board and Host program's versions | initiate | Syntax | Description | |----------|-------------|------------------------------------| -| H | **%** [LF] | **OLR Board software version request** | +| H | **%** [EOC] | **OLR Board software version request** | |**Response**| **From** | **Notes** |------|--------|------------ -|**%**Ver[LF] | B | String representing the Software Version +|**%**Ver[EOC] | B | String representing the Software Version #### Software Version String format --- to be defined +[0-9]+\.[0-9]+\.[0-9a-zA-Z]+ + +Two dot-separated decimal numbers plus a third part composed by numbers and/or letters. #### Examples |Origin|Command|| |---|----|----| -|H|**%[LF]**| Host send a **get info** request -|B|**%1.0[LF]**|The message from the Board indicates Version="1.0.1" +|H|**%[EOC]**| Host send a **get info** request +|B|**%0.9.d[EOC]**|The message from the Board indicates Version="0.9.d" + +#### Guidelines to Assign a version number to the Arduino Software: + + +The three numbers represents the “Major.Minor.Patch” version. + + • Major version zero (0.y.z) is for initial development. Anything MAY change at any time. + • Version 1.0.0 defines first ‘Stable’ version + • Increment: + ◦ MAJOR version when you make incompatible changes + ◦ MINOR version when you add functionality in a backwards compatible manner + ◦ PATCH version when you make backwards compatible bug fixes. + + + + - - - -### [:] - Set board Unique Id [Implemented] - - -The software running on the Board contains a routine to write an ID to EEPROM.
-The first time a Board is connected to a OLRNetwork the Unique Id may be empty (not every Board comes with the ID preloaded in EEPROM).
-The Host calculates an ID and send this **Set Id** command to the Board that will store -it in EEPROM.
-From now on this is the ID the board will send back when receiving a **Get Info '$'** command. +### [:] - Set board Unique Id |initiate| Syntax | Description |------|--------|------------ -|H |**:**id[LF]|**OLR Board Set UniqueId request** +|H |**:**id[EOC]|**OLR Board Set UniqueId request** || | Sent from Host to Set Board's Unique Id |Parameters | | | @@ -179,13 +182,13 @@ From now on this is the ID the board will send back when receiving a **Get Info |Response| | |---|--- -|**OK**[LF] | Board sends "OK" string (ACK) -|**NOK**[LF] | Board indicates that something went wrong +|**OK**[EOC] | Board sends "OK" string (ACK) +|**NOK**[EOC] | Board indicates that something went wrong - - - -### [!] - Send log/error message [Work in progress] +### [!] - Send log/error message The software running on the Board use this command to send messages to be written into the Host logfile.
The Host will log the message and decide what to do with the relay race according to the "Severity" parameter (nothing, stop it, etc.) @@ -193,7 +196,7 @@ The Host will log the message and decide what to do with the relay race accordin |initiate| Syntax | Description |------|--------|------------ -|B |**!**Severity,Message[LF]|**OLR Board Sends an error message to Host** +|B |**!**Severity,Message[EOC]|**OLR Board Sends an error message to Host** |Parameters | | | |----------------|---|---| @@ -215,12 +218,14 @@ The Host will log the message and decide what to do with the relay race accordin - - - -### [**C**] - Set basic race configuration [Implemented] +### [**C**] - Set basic race configuration + +This configuration is stored in non-volatile memory. |initiate| Syntax | Description |------|--------|------------ -|H |**C**start.nlap.repeat.finish[LF] |**Host Set basic race configuration** +|H |**C**start.nlap.repeat.finish[EOC] |**Host Set basic race configuration** @@ -228,114 +233,182 @@ The Host will log the message and decide what to do with the relay race accordin | Parameter |Format| Description |--------|---|--------- -| **start** | [0-1] |**Start Line** of the race is in this Board (Y/N) (0=No, 1=Yes) -| **nlap** | [1-9][0-9]? |Number of consecutive laps in each **section** of the Relay Race -| | | max 2 chars (range 1-99)
Number of consecutive laps the cars will “run” before race finish **or** car get trough the OutTunnel -| **repeat** |[1-9][0-9]?| Number of times to **repeat the configured section** of ‘nlap’ laps. -| | | max 2 chars (range 1-99)
How many times the section of ‘L’ laps will be repeated -| **finish** |[0-1] |**Finish Line** of the race is in this Board (Y/N) (0=No, 1=Yes) +| **start** | [0-1] | OLRNetwork Only **Always 1 for standalone OLR** +| **nlap** | [1-9][0-9]? |Number of laps of a Race +| | | max 2 chars (range 1-99) +| **repeat** |[1-9][0-9]?| OLRNetwork Only **Always 1 for standalone OLR** +| | | +| **finish** |[0-1] | OLRNetwork Only **Always 1 for standalone OLR** |Response| | |---|--- -|**OK**[LF] | Board sends "OK" string (ACK) -|**NOK**[LF] |Board indicates that something went wrong +|**OK**[EOC] | Board sends "OK" string (ACK) +|**NOK**[EOC] |Board indicates that something went wrong #### Examples |Origin|Command|| |---|----|----| -|H|**C0,5,2,1**|**start=0**: The Race starts in another OLR – The Board will be waiting for messages like “Race Started”, “Car 1 Leaving”, Car 1 Leaved”, etc... -|||**laps=5**: Each car will need to complete 5 laps before it can cross the Finish Line **or** get to the next OLR through the OutTunne.
(see 'repeat' param) -|||**repeat=2**: Each car will need to repoeat 2 times the section of ‘nlap’ laps.
This means we’ll expect each car will be sent back here (through the InTunnel) after we previously sent it out to another Racetrack. -|||**finish=1**: The Race ends here.This OLR will manage the Finsh Line Procedure. -|B|**OK[LF]**| This is the Response from the Board to the previous example(ACK) -|||The message from the Board indicates that the value for Position,laps, repeat and finish line has been set correctly as requested by the host. -| | | | -|H|**C1,2,3,0[LF]**| Position in Race is “1” The Race starts here -|||The Board will be managing the Start Race phase (Semaphore, etc.) | -|||Each car will need to complete 2 loops here before can get to the next Racetrack (through the OutTunne) . -|||Each car will need to repoeat 3 times the section of ‘nlap’ laps. -|||The Race ends in another OLR. -|B|**NOK[LF]**| This is a Response from the Board (ACK) -|||The [NOK] value from the Board indicates that something went wrong (the board received some invalid paramenter value). | +|H|**C1,3,1,1**|**laps=3**: Each car will need to complete 3 laps before it can cross the Finish Line +|B|**OK[EOC]**| This is the Response from the Board to the previous example(ACK) +|||The message from the Board indicates that the value for Position,Laps, Repeat and Finish line has been set correctly as requested by the host. - - - -### [T] - **T**rack configuration [ Implemented ] +### [T] - **T**rack configuration - Total LEDs Number This configuration is stored in non-volatile memory. |initiate| Syntax | Description |------|--------|------------ -|H |**T**box.tbd[LF] |**Host Set basic race configuration** +|H |**T**nled[EOC] |**Host Set Racetrack Length Configuration** #### Parameters | Parameter |Format| Description |--------|---|--------- -| **box** | [0-MAXLED] | Number of the led where the box starts. Set 0 to remove box. -| **tbd** | [TBD] | Not used yet, set to 0. - +| **nled** | Total number of LEDs in the Track | Ex: 300 for a single 5mt - 60 LED/mt LED Strip
**Please Note:
**After changing the LEDs number ** you need to reboot the board ** |Response| | |---|--- -|**TOK**[LF] | Board sends "OK" string (ACK) -|**TNOK**[LF] |Board indicates that something went wrong +|**TOK**[EOC] | Board sends "OK" string (ACK) +|**TNOK**[EOC] |Board indicates that something went wrong |Origin|Command|| |---|----|----| -|H|**T260,0**|: Set the box line in led number 260. +|H|**T600**| Total Length is 600 (2 x 300 LED Strip connected). + - - - -### [A] - r**A**ramp configuration [ Implemented ] +### [B] - **T**rack configuration - Pitlane Lenght (Boxes) This configuration is stored in non-volatile memory. |initiate| Syntax | Description |------|--------|------------ -|H |**A**center.high[LF] |**Host Set basic race configuration** +|H |**B**nled[EOC] |**Host Set Pitlane (boxex) Length Configuration** #### Parameters | Parameter |Format| Description |--------|---|--------- -| **center** | [0-MAXLED] | Number of the led where ramp is centered. Set 0 to remove box. +| **nled** | Total number of LEDs, at the end of the Racetrack, reserved for the Pitlane | Ex: 120 + +|Response| | +|---|--- +|**BOK**[EOC] | Board sends "OK" string (ACK) +|**BNOK**[EOC] |Board indicates that something went wrong + +|Origin|Command|| +|---|----|----| +|H|**B120**| Total Length for Pitlane is 120 + + + + +- - - + +### [A] - r**A**ramp configuration + +This configuration is stored in non-volatile memory. + +|initiate| Syntax | Description +|------|--------|------------ +|H |**A**start,center,end,high[EOC] |**Host Set basic Ramp configuration** + + +#### Parameters + +| Parameter |Format| Description +|--------|---|--------- +| **start** | | LED number where the ramp Starts +| **center** | | LED Number where ramp is centered. +| **end** | | LED number where the ramp ends | **height** | [ 0 - 1023] | Ramp elevation |Response| | |---|--- -|**AOK**[LF] | Board sends "OK" string (ACK) -|**ANOK**[LF] |Board indicates that something went wrong +|**AOK**[EOC] | Board sends "OK" string (ACK) +|**ANOK**[EOC] |Board indicates that something went wrong |Origin|Command|| |---|----|----| -|H|**A150,12**|: Set the ramp centered in led 150. +|H|**A140,150,160,12**|: Set the ramp centered in led 150, starts 10 LED before it and ends 10 LEDs after it, Elevation 12. - - - ### [D] - **D**efault configuration [ Implemented ] -Set default configuration to track and ramp settings. +Reset to default configuration parametrs (Track lenght, Ramp, Boxes and Race Laps). + |initiate| Syntax | Description |------|--------|------------ -|H |**D**[LF] |**Host Set basic race configuration** +|H |**D**[EOC] |**Host Request Board to Reset configuration parameters to Default** + + +- - - + + +### [Q] - Query current parameters set + + +| initiate | Syntax | Description | +|----------|-------------|------------------------------------| +| H | **Q**_[EOC]_ | **Get Current Parameters request** | +| | | Sent from Host to get Board's Cfg | + + +#### Returned Parameters format + + +|**Response**| **From** | **Notes** +|------|--------|------------ +|Board issue 3 answers:
**TRACK:**a,b,c,d,e[EOC]
**RAMP:**a,b,c,d[EOC]
**RACE:**a,b,c,d[EOC]
| B | Send the Parameters Set +| | | | +| **TRACK** params | | | +| | **nled_total** | Total number of LEDs in the Racetrack (**configurable with "T" command**) | +| | nled_main | Internal parameter (when Pitlane is active: number of LEDs currently in the Main Path) | +| | nled_aux | Internal parameter (when Pitlane is active: number of LEDs currently in the Pitlane Path)| +| | nled_init_aux | Internal parameter (position of the Pitlane entrance) | +| | **box_len** | Total number of LEDs, at the end of the Racetrack, reserved for the Pitlane (**configurable with "B" command**) | +| **RAMP** params | | | +|| **start** | LED number where the ramp Starts +|| **center** | LED Number where ramp is centered. +|| **end** | LED number where the ramp ends +|| **height** | Ramp elevation +| **RACE** params | | | +|| **start** | OLRNetwork Only **Always 1 for standalone OLR** +|| **nlap** |Number of laps of a Race (**Configurable with 2nd parameter of "C" Command**) +|| **repeat** | OLRNetwork Only **Always 1 for standalone OLR** +|| **finish** | OLRNetwork Only **Always 1 for standalone OLR** + + + + + +#### Examples +|Origin|Command|| +|---|----|----| +|H|**Q[EOC]**| Host send a **get current paremeters Set** request +|B|**TRACK:1200,1200,0,-1,60[EOC]
RAMP:180,190,200,15[EOC]
RACE:1,2,1,1[EOC]
**|Messages from the Board with the current cfg values + - - - -### [**p**] - Current Car **p**osition in Race [Implemented] +### [**p**] - Current Car **p**osition in Race |initiate| Syntax | Description |------|--------|------------ -|B|**p**NumTrackNlapRpos[LF]|**Position for each car in the race** +|B|**p**NumTrackNlapRpos[EOC]|**Position for each car in the race** |||Sent during race for each car currently in this Board. |Parameters | | | @@ -357,16 +430,16 @@ Set default configuration to track and ramp settings. #### Examples |Origin|Command|| |---|----|----| -|B|**p**1B1.95**p**2M5.45[LF]| Two cars are currentry "running" in the Board. Car "1" is in Track "B" in Lap number "1" Relative Lap Position 95%. Car "2" is in Track "M" in Lap number "5" Relative Lap Position 45% +|B|**p**1B1.95**p**2M5.45[EOC]| Two cars are currentry "running" in the Board. Car "1" is in Track "B" in Lap number "1" Relative Lap Position 95%. Car "2" is in Track "M" in Lap number "5" Relative Lap Position 45% - - - -### [w] - Car Win te Race [Implemented] +### [w] - Car Win te Race |initiate| Syntax | Description |------|--------|------------ -|B|**w**Num[LF]|**Car 'Num' just win the race** +|B|**w**Num[EOC]|**Car 'Num' just win the race** |||Sent by the circuit managing the "Finish Line" when a car cross it. |Parameters | | | @@ -383,5 +456,16 @@ Set default configuration to track and ramp settings. |---|----|----| |B|**w**1| Car "1" win the race -30_Network_Protocol_Serial.md -Mostrando 30_Network_Protocol_Serial.md. \ No newline at end of file + + + +- - - + +**Revisions:** +- 2020 07 28 + - Command T: Syntax mofied + - Command A: Syntax mofied + - Command B: Added + - + +- - - diff --git a/open-led-race/AsyncSerialLib.cpp b/open-led-race/AsyncSerialLib.cpp index 428ca48..64d120e 100644 --- a/open-led-race/AsyncSerialLib.cpp +++ b/open-led-race/AsyncSerialLib.cpp @@ -1,339 +1,339 @@ -/*************************************************** -Copyright (c) 2018 Luis Llamas -(www.luisllamas.es) - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License - ****************************************************/ - -#include "AsyncSerialLib.h" - -AsyncSerial::AsyncSerial(byte* buffer, size_t bufferLength, - AsyncSerialCallback onRecievedOk, AsyncSerialCallback onTimeout = nullptr, AsyncSerialCallback onOverflow = nullptr) -{ - Init(buffer, bufferLength, &Serial); - OnRecievedOk = onRecievedOk; - OnTimeout = onTimeout; - OnOverflow = onOverflow; - _startTime = millis(); -} - -void AsyncSerial::Init(byte *buffer, size_t bufferLength, Stream* stream) -{ - _status = RECIEVING_DATA; - _startTime = millis(); - _stream = stream == NULL ? &Serial : stream; - _buffer = buffer; - _bufferLength = bufferLength; - _bufferIndex = 0; -} - - -AsyncSerial::Status AsyncSerial::AsyncRecieve() -{ - if (_status == IDDLE) { return; } - - if (IsExpired()) - { - if (OnTimeout != nullptr) OnTimeout(*this); - _status = TIMEOUT; - } - - if (_status >= MESSAGE_RECIEVED) - { - _startTime = millis(); - _status = AutoReset ? RECIEVING_DATA : IDDLE; - } - - if (_status == RECIEVING_DATA || _status == RECIEVING_DATA_OVERFLOW) - { - asyncRecieve(); - } - - return _status; -} - -AsyncSerial::Status AsyncSerial::AsyncRecieve(int timeOut) -{ - Timeout = timeOut; - AsyncRecieve(); - return _status; -} - -AsyncSerial::Status AsyncSerial::Recieve(int timeOut) -{ - _startTime = millis(); - _status = RECIEVING_DATA; - - bool expired = false; - while (!expired && _status < MESSAGE_RECIEVED) - { - AsyncRecieve(); - expired = ((unsigned long)(millis() - _startTime) >= Timeout); - } - - if (expired) - { - _status = TIMEOUT; - if (OnTimeout != nullptr) OnTimeout(*this); - } - - return _status; -} - - -void AsyncSerial::AsyncSend(bool waitAck) -{ - AsyncSend(_buffer, _bufferLength, waitAck); -} - -void AsyncSerial::AsyncSend(byte* data, size_t dataLength, bool waitAck) -{ - if (_status == IDDLE) return; - - if (_status == TIMEOUT) - { - _status = AutoReset ? SENDING_DATA : IDDLE; - return; - } - - if (_status != WAITING_ACK) - { - _stream->write(data, dataLength); - - if (waitAck) - { - _status = WAITING_ACK; - _startTime = millis(); - } - else - { - _status = AutoReset ? MESSAGE_SENDED : IDDLE; - if (OnRecievedOk != nullptr) OnRecievedOk(*this); - } - } - - if (_status == WAITING_ACK) - { - if (IsExpired()) - { - _status = TIMEOUT; - _startTime = millis(); - if (OnTimeout != nullptr) OnTimeout(*this); - } - else - { - if (_stream->read() == AckChar) - { - _status = AutoReset ? MESSAGE_SENDED : IDDLE; - if (OnRecievedOk != nullptr) OnRecievedOk(*this); - } - } - } -} - -void AsyncSerial::ProcessByte(byte data) -{ - LastByte = data; - - if (data == (byte)FinishChar) finishRecieve(); - else processNewData(); -} - -void AsyncSerial::Send(bool waitAck) -{ - Send(_buffer, _bufferLength, waitAck); -} - -void AsyncSerial::Send(byte* data, size_t dataLength, bool waitAck) -{ - _stream->write(data, dataLength); - - if (waitAck) - { - _startTime = millis(); - while (!IsExpired()) - { - if (_stream->read() == AckChar) - { - _status = AutoReset ? MESSAGE_SENDED : IDDLE; - if (OnRecievedOk != nullptr) OnRecievedOk(*this); - return; - } - } - _status = TIMEOUT; - if (OnTimeout != nullptr) OnTimeout(*this); - } - else - { - _status = AutoReset ? MESSAGE_SENDED : IDDLE; - if (OnRecievedOk != nullptr) OnRecievedOk(*this); - } - -} - - -uint8_t AsyncSerial::GetLastIndex() -{ - return (_bufferIndex - 1 + _bufferLength) % _bufferLength; -} - -byte AsyncSerial::GetLastData() -{ - return _buffer[GetLastIndex()]; -} - -byte * AsyncSerial::GetContent() -{ - return _buffer; -} - -uint8_t AsyncSerial::GetContentLength() -{ - return _status == MESSAGE_RECIEVED_OVERFLOW ? _bufferLength : _bufferIndex; -} - -void AsyncSerial::OrderBuffer() -{ - orderBuffer(_buffer, 0, _bufferLength - 1, GetLastIndex()); -} - -void AsyncSerial::Start() -{ - _status = RECIEVING_DATA; - _bufferIndex = 0; - _startTime = millis(); -} - -void AsyncSerial::Stop() -{ - _status = IDDLE; -} - -inline bool AsyncSerial::IsExpired() -{ - if (Timeout == 0) return false; - return ((unsigned long)(millis() - _startTime) > Timeout); -} - - -void AsyncSerial::asyncRecieve() -{ - while (_stream->available()) - { - byte newData = _stream->read(); - - ProcessByte(newData); - } -} - -void AsyncSerial::processNewData() -{ - if (LastByte != (byte)IgnoreChar) - { - if (OnByteProcessed != nullptr) OnByteProcessed(*this); - - if (_bufferIndex >= _bufferLength) - { - _bufferIndex %= _bufferLength; - if (_status != RECIEVING_DATA_OVERFLOW) - { - if (OnOverflow != nullptr) OnOverflow(*this); - } - _status = RECIEVING_DATA_OVERFLOW; - } - - _buffer[_bufferIndex] = LastByte; - _bufferIndex++; - } -} - -void AsyncSerial::finishRecieve() -{ - _status = (_status == RECIEVING_DATA_OVERFLOW ? MESSAGE_RECIEVED_OVERFLOW : MESSAGE_RECIEVED); - - if (_status == MESSAGE_RECIEVED) - { - if (OnRecievedOk != nullptr) OnRecievedOk(*this); - } - else - { - if (AllowOverflow) - { - OrderBuffer(); - if (OnRecievedOk != nullptr) OnRecievedOk(*this); - if (SendAck) _stream->write(AckChar); - } - } - - _bufferIndex = 0; -} - -void AsyncSerial::orderBuffer(byte buffer[], size_t start, size_t end, size_t index) -{ - size_t leftBlockLength = index - start + 1; - size_t rigthBlockLength = end - index; - - while (leftBlockLength != 0 && rigthBlockLength != 0) - { - if (leftBlockLength <= rigthBlockLength) - { - // RIGHT BLOCK SHIFT - swapBufferBlock(buffer, start, leftBlockLength); - start += leftBlockLength; - index += leftBlockLength; - } - else - { - // LEFT BLOCK SHIFT - swapBufferBlock(buffer, index - rigthBlockLength + 1, rigthBlockLength); - end -= rigthBlockLength; - index -= rigthBlockLength; - } - leftBlockLength = index - start + 1; - rigthBlockLength = end - index; - } -} - -void AsyncSerial::swapBufferBlock(byte buffer[], size_t start, size_t length) -{ - byte temp; - for (size_t i = 0; i < length; i++) - { - temp = buffer[start + i]; - buffer[start + i] = buffer[start + i + length]; - buffer[start + i + length] = temp; - } -} - - -void AsyncSerial::debugStatus() -{ - switch (_status) - { - IDDLE: _stream->println("IDDLE"); break; - RECIEVING_DATA: _stream->println("RECIEVING_DATA"); break; - RECIEVING_DATA_OVERFLOW: _stream->println("RECIEVING_DATA_OVERFLOW"); break; - MESSAGE_RECIEVED: _stream->println("MESSAGE_RECIEVED"); break; - MESSAGE_RECIEVED_OVERFLOW: _stream->println("MESSAGE_RECIEVED_OVERFLOW"); break; - TIMEOUT: _stream->println("TIMEOUT"); break; - WAITING_ACK: _stream->println("WAITING_ACK"); break; - MESSAGE_SENDED: _stream->println(" "); break; - default: break; - } -} - -void AsyncSerial::debugBuffer() -{ - for (int i = 0; i < _bufferLength; i++) - { - _stream->print((char)_buffer[i]); - _stream->print("\t"); - } - _stream->println(); - - for (int i = 0; i < _bufferLength; i++) - _stream->print(i == GetLastIndex() ? "^" : "\t"); - _stream->println(); -} +/*************************************************** +Copyright (c) 2018 Luis Llamas +(www.luisllamas.es) + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License + ****************************************************/ + +#include "AsyncSerialLib.h" + +AsyncSerial::AsyncSerial(byte* buffer, size_t bufferLength, + AsyncSerialCallback onRecievedOk, AsyncSerialCallback onTimeout = nullptr, AsyncSerialCallback onOverflow = nullptr) +{ + Init(buffer, bufferLength, &Serial); + OnRecievedOk = onRecievedOk; + OnTimeout = onTimeout; + OnOverflow = onOverflow; + _startTime = millis(); +} + +void AsyncSerial::Init(byte *buffer, size_t bufferLength, Stream* stream) +{ + _status = RECIEVING_DATA; + _startTime = millis(); + _stream = stream == NULL ? &Serial : stream; + _buffer = buffer; + _bufferLength = bufferLength; + _bufferIndex = 0; +} + + +AsyncSerial::Status AsyncSerial::AsyncRecieve() +{ + if (_status == IDDLE) { return; } + + if (IsExpired()) + { + if (OnTimeout != nullptr) OnTimeout(*this); + _status = TIMEOUT; + } + + if (_status >= MESSAGE_RECIEVED) + { + _startTime = millis(); + _status = AutoReset ? RECIEVING_DATA : IDDLE; + } + + if (_status == RECIEVING_DATA || _status == RECIEVING_DATA_OVERFLOW) + { + asyncRecieve(); + } + + return _status; +} + +AsyncSerial::Status AsyncSerial::AsyncRecieve(int timeOut) +{ + Timeout = timeOut; + AsyncRecieve(); + return _status; +} + +AsyncSerial::Status AsyncSerial::Recieve(int timeOut) +{ + _startTime = millis(); + _status = RECIEVING_DATA; + + bool expired = false; + while (!expired && _status < MESSAGE_RECIEVED) + { + AsyncRecieve(); + expired = ((unsigned long)(millis() - _startTime) >= Timeout); + } + + if (expired) + { + _status = TIMEOUT; + if (OnTimeout != nullptr) OnTimeout(*this); + } + + return _status; +} + + +void AsyncSerial::AsyncSend(bool waitAck) +{ + AsyncSend(_buffer, _bufferLength, waitAck); +} + +void AsyncSerial::AsyncSend(byte* data, size_t dataLength, bool waitAck) +{ + if (_status == IDDLE) return; + + if (_status == TIMEOUT) + { + _status = AutoReset ? SENDING_DATA : IDDLE; + return; + } + + if (_status != WAITING_ACK) + { + _stream->write(data, dataLength); + + if (waitAck) + { + _status = WAITING_ACK; + _startTime = millis(); + } + else + { + _status = AutoReset ? MESSAGE_SENDED : IDDLE; + if (OnRecievedOk != nullptr) OnRecievedOk(*this); + } + } + + if (_status == WAITING_ACK) + { + if (IsExpired()) + { + _status = TIMEOUT; + _startTime = millis(); + if (OnTimeout != nullptr) OnTimeout(*this); + } + else + { + if (_stream->read() == AckChar) + { + _status = AutoReset ? MESSAGE_SENDED : IDDLE; + if (OnRecievedOk != nullptr) OnRecievedOk(*this); + } + } + } +} + +void AsyncSerial::ProcessByte(byte data) +{ + LastByte = data; + + if (data == (byte)FinishChar) finishRecieve(); + else processNewData(); +} + +void AsyncSerial::Send(bool waitAck) +{ + Send(_buffer, _bufferLength, waitAck); +} + +void AsyncSerial::Send(byte* data, size_t dataLength, bool waitAck) +{ + _stream->write(data, dataLength); + + if (waitAck) + { + _startTime = millis(); + while (!IsExpired()) + { + if (_stream->read() == AckChar) + { + _status = AutoReset ? MESSAGE_SENDED : IDDLE; + if (OnRecievedOk != nullptr) OnRecievedOk(*this); + return; + } + } + _status = TIMEOUT; + if (OnTimeout != nullptr) OnTimeout(*this); + } + else + { + _status = AutoReset ? MESSAGE_SENDED : IDDLE; + if (OnRecievedOk != nullptr) OnRecievedOk(*this); + } + +} + + +uint8_t AsyncSerial::GetLastIndex() +{ + return (_bufferIndex - 1 + _bufferLength) % _bufferLength; +} + +byte AsyncSerial::GetLastData() +{ + return _buffer[GetLastIndex()]; +} + +byte * AsyncSerial::GetContent() +{ + return _buffer; +} + +uint8_t AsyncSerial::GetContentLength() +{ + return _status == MESSAGE_RECIEVED_OVERFLOW ? _bufferLength : _bufferIndex; +} + +void AsyncSerial::OrderBuffer() +{ + orderBuffer(_buffer, 0, _bufferLength - 1, GetLastIndex()); +} + +void AsyncSerial::Start() +{ + _status = RECIEVING_DATA; + _bufferIndex = 0; + _startTime = millis(); +} + +void AsyncSerial::Stop() +{ + _status = IDDLE; +} + +inline bool AsyncSerial::IsExpired() +{ + if (Timeout == 0) return false; + return ((unsigned long)(millis() - _startTime) > Timeout); +} + + +void AsyncSerial::asyncRecieve() +{ + while (_stream->available()) + { + byte newData = _stream->read(); + + ProcessByte(newData); + } +} + +void AsyncSerial::processNewData() +{ + if (LastByte != (byte)IgnoreChar) + { + if (OnByteProcessed != nullptr) OnByteProcessed(*this); + + if (_bufferIndex >= _bufferLength) + { + _bufferIndex %= _bufferLength; + if (_status != RECIEVING_DATA_OVERFLOW) + { + if (OnOverflow != nullptr) OnOverflow(*this); + } + _status = RECIEVING_DATA_OVERFLOW; + } + + _buffer[_bufferIndex] = LastByte; + _bufferIndex++; + } +} + +void AsyncSerial::finishRecieve() +{ + _status = (_status == RECIEVING_DATA_OVERFLOW ? MESSAGE_RECIEVED_OVERFLOW : MESSAGE_RECIEVED); + + if (_status == MESSAGE_RECIEVED) + { + if (OnRecievedOk != nullptr) OnRecievedOk(*this); + } + else + { + if (AllowOverflow) + { + OrderBuffer(); + if (OnRecievedOk != nullptr) OnRecievedOk(*this); + if (SendAck) _stream->write(AckChar); + } + } + + _bufferIndex = 0; +} + +void AsyncSerial::orderBuffer(byte buffer[], size_t start, size_t end, size_t index) +{ + size_t leftBlockLength = index - start + 1; + size_t rigthBlockLength = end - index; + + while (leftBlockLength != 0 && rigthBlockLength != 0) + { + if (leftBlockLength <= rigthBlockLength) + { + // RIGHT BLOCK SHIFT + swapBufferBlock(buffer, start, leftBlockLength); + start += leftBlockLength; + index += leftBlockLength; + } + else + { + // LEFT BLOCK SHIFT + swapBufferBlock(buffer, index - rigthBlockLength + 1, rigthBlockLength); + end -= rigthBlockLength; + index -= rigthBlockLength; + } + leftBlockLength = index - start + 1; + rigthBlockLength = end - index; + } +} + +void AsyncSerial::swapBufferBlock(byte buffer[], size_t start, size_t length) +{ + byte temp; + for (size_t i = 0; i < length; i++) + { + temp = buffer[start + i]; + buffer[start + i] = buffer[start + i + length]; + buffer[start + i + length] = temp; + } +} + + +void AsyncSerial::debugStatus() +{ + switch (_status) + { + IDDLE: _stream->println("IDDLE"); break; + RECIEVING_DATA: _stream->println("RECIEVING_DATA"); break; + RECIEVING_DATA_OVERFLOW: _stream->println("RECIEVING_DATA_OVERFLOW"); break; + MESSAGE_RECIEVED: _stream->println("MESSAGE_RECIEVED"); break; + MESSAGE_RECIEVED_OVERFLOW: _stream->println("MESSAGE_RECIEVED_OVERFLOW"); break; + TIMEOUT: _stream->println("TIMEOUT"); break; + WAITING_ACK: _stream->println("WAITING_ACK"); break; + MESSAGE_SENDED: _stream->println(" "); break; + default: break; + } +} + +void AsyncSerial::debugBuffer() +{ + for (int i = 0; i < _bufferLength; i++) + { + _stream->print((char)_buffer[i]); + _stream->print("\t"); + } + _stream->println(); + + for (int i = 0; i < _bufferLength; i++) + _stream->print(i == GetLastIndex() ? "^" : "\t"); + _stream->println(); +} diff --git a/open-led-race/AsyncSerialLib.h b/open-led-race/AsyncSerialLib.h index e4f6b1a..798054b 100644 --- a/open-led-race/AsyncSerialLib.h +++ b/open-led-race/AsyncSerialLib.h @@ -1,101 +1,101 @@ -/*************************************************** -Copyright (c) 2018 Luis Llamas -(www.luisllamas.es) - -Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License - ****************************************************/ - -#ifndef _ASYNCSERIALLIB_h -#define _ASYNCSERIALLIB_h - -#if defined(ARDUINO) && ARDUINO >= 100 - #include "Arduino.h" -#else - #include "WProgram.h" -#endif - -const char CARRIAGE_RETURN = '\r'; -const char NEW_LINE = '\n'; -const char ACK = 0x06; - -class AsyncSerial -{ - typedef void(*AsyncSerialCallback)(AsyncSerial& sender); - - public: - typedef enum - { - IDDLE, - RECIEVING_DATA, - RECIEVING_DATA_OVERFLOW, - MESSAGE_RECIEVED, - MESSAGE_RECIEVED_OVERFLOW, - TIMEOUT, - SENDING_DATA, - WAITING_ACK, - MESSAGE_SENDED - } Status; - - AsyncSerial(byte *buffer, size_t bufferLength, - AsyncSerialCallback OnRecievedOk, AsyncSerialCallback OnOverflow = nullptr, AsyncSerialCallback OnTimeout = nullptr ); - - void Init(byte *buffer, size_t bufferLength, Stream* stream = NULL); - - Status AsyncRecieve(); - AsyncSerial::Status AsyncRecieve(int timeOut); - AsyncSerial::Status Recieve(int timeOut); - - void AsyncSend(bool waitAck = false); - void AsyncSend(byte* data, size_t dataLength, bool waitAck = false); - void ProcessByte(byte data); - void Send(bool waitAck = false); - void Send(byte* data, size_t dataLength, bool waitAck = false); - - - uint8_t GetLastIndex(); - uint8_t GetLastData(); - byte* GetContent(); - uint8_t GetContentLength(); - void OrderBuffer(); - void Start(); - void Stop(); - inline bool IsExpired(); - - AsyncSerialCallback OnRecievedOk; - AsyncSerialCallback OnOverflow; - AsyncSerialCallback OnTimeout; - AsyncSerialCallback OnByteProcessed; - - unsigned long Timeout = 0; - bool AutoReset = true; - bool AllowOverflow = false; - bool SendAck; - byte LastByte; - char FinishChar = NEW_LINE; - char IgnoreChar = CARRIAGE_RETURN; - char AckChar = ACK; - - - protected: - Stream* _stream; - byte *_buffer; - size_t _bufferIndex; - size_t _bufferLength; - - unsigned long _startTime; - bool _sendAck = false; - Status _status; - - void asyncRecieve(); - void processNewData(); - void finishRecieve(); - static void orderBuffer(byte buffer[], size_t start, size_t end, size_t index); - static void swapBufferBlock(byte buffer[], size_t start, size_t length); - - void debugBuffer(); - void debugStatus(); -}; - -#endif +/*************************************************** +Copyright (c) 2018 Luis Llamas +(www.luisllamas.es) + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License + ****************************************************/ + +#ifndef _ASYNCSERIALLIB_h +#define _ASYNCSERIALLIB_h + +#if defined(ARDUINO) && ARDUINO >= 100 + #include "Arduino.h" +#else + #include "WProgram.h" +#endif + +const char CARRIAGE_RETURN = '\r'; +const char NEW_LINE = '\n'; +const char ACK = 0x06; + +class AsyncSerial +{ + typedef void(*AsyncSerialCallback)(AsyncSerial& sender); + + public: + typedef enum + { + IDDLE, + RECIEVING_DATA, + RECIEVING_DATA_OVERFLOW, + MESSAGE_RECIEVED, + MESSAGE_RECIEVED_OVERFLOW, + TIMEOUT, + SENDING_DATA, + WAITING_ACK, + MESSAGE_SENDED + } Status; + + AsyncSerial(byte *buffer, size_t bufferLength, + AsyncSerialCallback OnRecievedOk, AsyncSerialCallback OnOverflow = nullptr, AsyncSerialCallback OnTimeout = nullptr ); + + void Init(byte *buffer, size_t bufferLength, Stream* stream = NULL); + + Status AsyncRecieve(); + AsyncSerial::Status AsyncRecieve(int timeOut); + AsyncSerial::Status Recieve(int timeOut); + + void AsyncSend(bool waitAck = false); + void AsyncSend(byte* data, size_t dataLength, bool waitAck = false); + void ProcessByte(byte data); + void Send(bool waitAck = false); + void Send(byte* data, size_t dataLength, bool waitAck = false); + + + uint8_t GetLastIndex(); + uint8_t GetLastData(); + byte* GetContent(); + uint8_t GetContentLength(); + void OrderBuffer(); + void Start(); + void Stop(); + inline bool IsExpired(); + + AsyncSerialCallback OnRecievedOk; + AsyncSerialCallback OnOverflow; + AsyncSerialCallback OnTimeout; + AsyncSerialCallback OnByteProcessed; + + unsigned long Timeout = 0; + bool AutoReset = true; + bool AllowOverflow = false; + bool SendAck; + byte LastByte; + char FinishChar = NEW_LINE; + char IgnoreChar = CARRIAGE_RETURN; + char AckChar = ACK; + + + protected: + Stream* _stream; + byte *_buffer; + size_t _bufferIndex; + size_t _bufferLength; + + unsigned long _startTime; + bool _sendAck = false; + Status _status; + + void asyncRecieve(); + void processNewData(); + void finishRecieve(); + static void orderBuffer(byte buffer[], size_t start, size_t end, size_t index); + static void swapBufferBlock(byte buffer[], size_t start, size_t length); + + void debugBuffer(); + void debugStatus(); +}; + +#endif diff --git a/open-led-race/olr-controller.c b/open-led-race/olr-controller.c index 653b5e0..1b8e55c 100644 --- a/open-led-race/olr-controller.c +++ b/open-led-race/olr-controller.c @@ -73,4 +73,3 @@ float controller_getAccel ( void ) { bool controller_isActive( int pin ) { return !digitalRead( pin ); } - diff --git a/open-led-race/olr-lib.c b/open-led-race/olr-lib.c index 096c5b9..d259323 100644 --- a/open-led-race/olr-lib.c +++ b/open-led-race/olr-lib.c @@ -23,6 +23,7 @@ void update_track( track_t* tck, car_t* car ) { controller_t* ct = car->ct; struct cfgtrack const* cfg = &tck->cfg.track; + 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 @@ -98,27 +99,65 @@ void car_resetPosition( car_t* car) { } void box_init( track_t* tck ) { - tck->boxactive = true; + tck->boxactive = true; } bool box_isactive( track_t* tck ) { return tck->boxactive; } -int box_configure( track_t* tck, int init_box ) { + + +int tracklen_configure( track_t* tck, int nled ) { struct cfgtrack* cfg = &tck->cfg.track; - if( init_box >= cfg->nled_main ) return -1; + if( nled <= 0 ) return -1; + cfg->nled_total = nled; + return 0; +} + +int boxlen_configure( track_t* tck, int box_len ) { + struct cfgtrack* cfg = &tck->cfg.track; + + if( box_len <= 0 || box_len >= cfg->nled_total ) return -1; + cfg->box_len = box_len; + return 0; +} + + +int track_configure( track_t* tck, int init_box ) { + struct cfgtrack* cfg = &tck->cfg.track; + + if(init_box >= cfg->nled_total ) return -1; cfg->nled_main = ( init_box == 0 ) ? cfg->nled_total : init_box; cfg->nled_aux = ( init_box == 0 ) ? 0 : cfg->nled_total - init_box; cfg->init_aux = init_box - 1; return 0; } -int ramp_configure( track_t* tck, int center, int high ) { + +int ramp_configure( track_t* tck, int init, int center, int end, int high ) { struct cfgramp* ramp = &tck->cfg.ramp; - if ( center >= tck->cfg.track.nled_main || center <= 0 ) return -1; + if ( init >= tck->cfg.track.nled_main || init <= 0 ) return -1; + if ( center >= tck->cfg.track.nled_main || center <= 0 ) return -2; + if ( end >= tck->cfg.track.nled_main || end <= 0 ) return -3; + if ( ! (center > init && center < end) ) return -4; + + ramp->init = init; ramp->center = center; + ramp->end = end; ramp->high = high; return 0; } + +int race_configure( track_t* tck, int startline, int nlap, int nrepeat, int finishline ) { + struct cfgrace* race = &tck->cfg.race; + + if ( startline != 0 && startline != 1 ) return -1; + if ( finishline != 0 && finishline != 1 ) return -1; + race->startline = startline; + race->finishline = finishline; + race->nlap = nlap; + race->nrepeat = nrepeat; + return 0; +} diff --git a/open-led-race/olr-lib.h b/open-led-race/olr-lib.h index 3a030e6..a008f5a 100644 --- a/open-led-race/olr-lib.h +++ b/open-led-race/olr-lib.h @@ -76,14 +76,19 @@ void box_init( track_t* tck ); bool box_isactive( track_t* tck ); -int box_configure( track_t* tck, int init_box ); +int tracklen_configure( track_t* tck, int nled ); + +int boxlen_configure( track_t* tck, int box_len ); + +int track_configure( track_t* tck, int init_box ); void ramp_init( track_t* tck ); bool ramp_isactive( track_t* tck ); -int ramp_configure( track_t* tck, int center, int high ); +int ramp_configure( track_t* tck, int init, int center, int end, int high ); +int race_configure( track_t* tck, int startline, int nlap, int nrepeat, int finishline ); #ifdef __cplusplus } // extern "C" diff --git a/open-led-race/olr-param.c b/open-led-race/olr-param.c index 8fd0a81..02966ef 100644 --- a/open-led-race/olr-param.c +++ b/open-led-race/olr-param.c @@ -3,19 +3,21 @@ void param_setdefault( struct cfgparam* cfg ) { cfg->setted = true; + cfg->race.startline = true; + cfg->race.nlap = NUMLAP; + cfg->race.nrepeat = 1; + cfg->race.finishline = true; + cfg->ramp.init = 80; cfg->ramp.center = 90; cfg->ramp.end = 100; - cfg->ramp.high = 2; + cfg->ramp.high = 3; cfg->track.nled_total = MAXLED; - cfg->track.nled_main = 300; //240 - cfg->track.nled_aux = 0; //60 - cfg->track.init_aux = -1; //239 + 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.kf = 0.015; //friction constant cfg->track.kg = 0.003; //gravity constant } - - - - diff --git a/open-led-race/olr-param.h b/open-led-race/olr-param.h index 30f3012..3f990e7 100644 --- a/open-led-race/olr-param.h +++ b/open-led-race/olr-param.h @@ -11,20 +11,35 @@ extern "C"{ #include #include -#define MAXLED 240+60 // 466 MAX LEDs actives on strip +#define MAXLED 300 +#define BOXLEN 60 +#define NUMLAP 5 + + enum{ LEN_UID = 16, - CFG_VER = 3, + CFG_VER = 4, // "4" in V0.9.d }; +struct cfgrace{ + bool startline; // Used only in OLRNetwork + int nlap; + int nrepeat; // Used only in OLRNetwork + bool finishline; // Used only in OLRNetwork +}; -// ramp centred in LED 100 with 10 led fordward and 10 backguard +// 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. + // 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) + float kf; float kg; }; @@ -43,6 +58,7 @@ struct brdinfo { struct cfgparam { bool setted; + struct cfgrace race; // added in ver 0.9.d struct cfgtrack track; struct cfgramp ramp; struct brdinfo info; diff --git a/open-led-race/open-led-race.ino b/open-led-race/open-led-race.ino index 0478124..cf22a4b 100644 --- a/open-led-race/open-led-race.ino +++ b/open-led-race/open-led-race.ino @@ -18,24 +18,22 @@ First public version by: Angel Maldonado (https://gitlab.com/angeljmc) + Gerardo Barbarov (gbarbarov AT singulardevices DOT com) Basen on original idea and 2 players code by: - gbarbarov@singulardevices.com for Arduino day Seville 2019 + Gerardo Barbarov for Arduino day Seville 2019 https://github.com/gbarbarov/led-race Public Repository for this code: https://gitlab.com/open-led-race/olr-arduino - - 2020/07/16 - Ver 0.9.c - --see changelog.txt - - - */ -char const version[] = "0.9.c"; + +// 2020/07/29 - Ver 0.9.d +// --see changelog.txt +char const version[] = "0.9.d"; @@ -87,12 +85,6 @@ typedef struct ack{ }ack_t; -struct cfgrace{ - bool startline; - int nlap; - int nrepeat; - bool finishline; -}; struct cfgcircuit{ int outtunnel; @@ -165,7 +157,8 @@ AsyncSerial asyncSerial(data, dataLength, [](AsyncSerial& sender) { ack_t ack = parseCommands( sender ); sendresponse( &ack ); } ); -Adafruit_NeoPixel track = Adafruit_NeoPixel( MAXLED, PIN_LED, NEO_GRB + NEO_KHZ800 ); +//Adafruit_NeoPixel track = Adafruit_NeoPixel( MAXLED, PIN_LED, NEO_GRB + NEO_KHZ800 ); +Adafruit_NeoPixel track; char tmpmsg [20]; @@ -177,6 +170,8 @@ void setup() { controller_setup( ); param_load( &tck.cfg ); + track = Adafruit_NeoPixel( tck.cfg.track.nled_total, PIN_LED, NEO_GRB + NEO_KHZ800 ); + controller_init( &switchs[0], DIGITAL_MODE, DIG_CONTROL_1 ); car_init( &cars[0], &switchs[0], COLOR1 ); controller_init( &switchs[1], DIGITAL_MODE, DIG_CONTROL_2 ); @@ -201,7 +196,11 @@ void setup() { // Check Box before Physic/Sound to allow user to have Box and Physics with no sound if ( digitalRead( DIG_CONTROL_2 ) == 0 ) { //push switch 2 on reset for activate boxes (pit lane) box_init( &tck ); - box_configure( &tck, 240 ); + //box_configure( &tck, 240 ); + //box_configure( &tck, MAXLED - BOXLEN ); + track_configure( &tck, tck.cfg.track.nled_total - tck.cfg.track.box_len ); + } else{ + track_configure( &tck, 0 ); } if ( digitalRead( DIG_CONTROL_1 ) == 0 ) { //push switch 1 on reset for activate physics @@ -215,11 +214,11 @@ void setup() { } + race.cfg.startline = tck.cfg.race.startline;// true; + race.cfg.nlap = tck.cfg.race.nlap;// NUMLAP; + race.cfg.nrepeat = tck.cfg.race.nrepeat;// 1; + race.cfg.finishline = tck.cfg.race.finishline;// true; - race.cfg.startline = true; - race.cfg.nlap = 5; - race.cfg.nrepeat = 1; - race.cfg.finishline = true; race.phase = READY; } @@ -456,7 +455,7 @@ void draw_coin( track_t* tck ) { void draw_winner( track_t* tck, uint32_t color) { struct cfgtrack const* cfg = &tck->cfg.track; - for(int i=16; i < cfg->nled_main; i=i+2){ + for(int i=16; i < cfg->nled_main; i=i+(8 * cfg->nled_main / 300 )){ track.setPixelColor( i , color ); track.setPixelColor( i-16 ,0 ); track.show(); @@ -541,7 +540,6 @@ ack_t parseCommands(AsyncSerial &serial) { } } else if( cmd[0] == 'C' ) { //Parse race configuration -> C1.2.3.0 - struct cfgrace cfg; ack.type = cmd[0]; char * pch = strtok (cmd,"C"); @@ -549,21 +547,33 @@ ack_t parseCommands(AsyncSerial &serial) { pch = strtok (pch, "," ); if( !pch ) return ack; - cfg.startline = atoi( pch ); + //cfg.startline = atoi( pch ); + int startline = atoi( pch ); pch = strtok (NULL, ","); if( !pch ) return ack; - cfg.nlap = atoi( pch ); + //cfg.nlap = atoi( pch ); + int nlap = atoi( pch ); pch = strtok (NULL, ","); if( !pch ) return ack; - cfg.nrepeat = atoi( pch ); + //cfg.nrepeat = atoi( pch ); + int nrepeat = atoi( pch ); pch = strtok (NULL, ","); if( !pch ) return ack; - cfg.finishline = atoi( pch ); + //cfg.finishline = atoi( pch ); + int finishline = atoi( pch ); - race.cfg = cfg; + int err = race_configure( &tck, startline, nlap, nrepeat, finishline); + if( err ) return ack; + EEPROM.put( eeadrInfo, tck.cfg ); + + race.cfg.startline = tck.cfg.race.startline; + race.cfg.nlap = tck.cfg.race.nlap; + race.cfg.nrepeat = tck.cfg.race.nrepeat; + race.cfg.finishline = tck.cfg.race.finishline; + race.newcfg = true; ack.rp = OK; if ( verbose >= DEBUG ) { //VERBOSE @@ -575,50 +585,81 @@ ack_t parseCommands(AsyncSerial &serial) { printdebug( txbuff, DEBUG ); } } - else if( cmd[0] == 'T' ) { //Parse track configuration -> T1,2 + else if( cmd[0] == 'T' ) { //Parse Track configuration -> Track length ack.type = cmd[0]; char * pch = strtok (cmd,"T"); if( !pch ) return ack; - pch = strtok (pch, "," ); - if( !pch ) return ack; - int init_aux = atoi( pch ); - - pch = strtok (NULL, ","); - if( !pch ) return ack; - - int err = box_configure( &tck, init_aux ); + int nled = atoi( cmd + 1 ); + int err = tracklen_configure( &tck, nled); + if( err ) return ack; + track_configure( &tck, 0); if( err ) return ack; - EEPROM.put( eeadrInfo, tck.cfg ); - box_init( &tck ); + EEPROM.put( eeadrInfo, tck.cfg ); + ack.rp = OK; if ( verbose >= DEBUG ) { //VERBOSE struct cfgtrack const* cfg = &tck.cfg.track; - sprintf( txbuff, "%s %d, %d, %d, %d", "TRACK CONFIG: ", + sprintf( txbuff, "%s %d, %d, %d, %d, %d", "TRACK CONFIG: ", cfg->nled_total, cfg->nled_main, cfg->nled_aux, - cfg->init_aux ); + cfg->init_aux, + cfg->box_len); printdebug( txbuff, DEBUG ); } + } - else if( cmd[0] == 'P' ) { //Parse ramp configuration -> T1,2 + else if( cmd[0] == 'B' ) { //Parse BoxLenght Configuration ack.type = cmd[0]; - char * pch = strtok (cmd,"R"); + char * pch = strtok (cmd,"B"); + if( !pch ) return ack; + + int boxlen = atoi( cmd + 1 ); + int err = boxlen_configure( &tck, boxlen); + if( err ) return ack; + + EEPROM.put( eeadrInfo, tck.cfg ); + + ack.rp = OK; + if ( verbose >= DEBUG ) { //VERBOSE + struct cfgtrack const* cfg = &tck.cfg.track; + sprintf( txbuff, "%s %d, %d, %d, %d, %d", "TRACK CONFIG: ", + cfg->nled_total, + cfg->nled_main, + cfg->nled_aux, + cfg->init_aux, + cfg->box_len); + printdebug( txbuff, DEBUG ); + } + + } + else if( cmd[0] == 'A' ) { // Parse Ramp configuration -> A
. + ack.type = cmd[0]; + + char * pch = strtok (cmd,"A"); if( !pch ) return ack; pch = strtok (pch, "," ); if( !pch ) return ack; + int init = atoi( pch ); + + pch = strtok (NULL, "," ); + if( !pch ) return ack; int center = atoi( pch ); + pch = strtok (NULL, "," ); + if( !pch ) return ack; + int end = atoi( pch ); + pch = strtok (NULL, ","); if( !pch ) return ack; int high = atoi( pch ); - int err = ramp_configure( &tck, center, high ); + int err = ramp_configure( &tck, init, center, end, high ); if( err ) return ack; EEPROM.put( eeadrInfo, tck.cfg ); @@ -634,6 +675,7 @@ ack_t parseCommands(AsyncSerial &serial) { printdebug( txbuff, DEBUG ); } } + else if( cmd[0] == 'D') { ack.type = cmd[0]; param_setdefault( &tck.cfg ); @@ -666,20 +708,29 @@ ack_t parseCommands(AsyncSerial &serial) { } else if( cmd[0] == 'Q' ) { // Get configuration Info struct cfgparam const* cfg = &tck.cfg; - sprintf( txbuff, "%s:%d,%d,%d,%d%c", "TCFG ", + sprintf( txbuff, "%s:%d,%d,%d,%d,%d%c", "TRACK", cfg->track.nled_total, cfg->track.nled_main, cfg->track.nled_aux, cfg->track.init_aux, + cfg->track.box_len, EOL ); Serial.print( txbuff ); - sprintf( txbuff, "%s:%d,%d,%d,%d%c", "RCFG: ", + sprintf( txbuff, "%s:%d,%d,%d,%d%c", "RAMP", cfg->ramp.init, cfg->ramp.center, cfg->ramp.end, cfg->ramp.high, EOL ); Serial.print( txbuff ); + sprintf( txbuff, "%s:%d,%d,%d,%d%c", "RACE", + cfg->race.startline, + cfg->race.nlap, + cfg->race.nrepeat, + cfg->race.finishline, + EOL ); + Serial.print( txbuff ); + ack.rp = NOTHING; } @@ -701,19 +752,25 @@ void sendresponse( ack_t *ack) { memset( &cmd, '\0' , sizeof(cmd) ); } + + 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 Ver:", cfgversion, EOL ); + Serial.print( txbuff ); + if ( cfgversion != CFG_VER ) { param_setdefault( &tck.cfg ); eeAdress = 0; EEPROM.put( eeAdress, tck.cfg ); eeAdress += sizeof( cfgparam ); EEPROM.put( eeAdress, CFG_VER ); - Serial.print("LOAD DEFAULT\n"); + Serial.print("DEFAULT PAREMETRS LOADED (and Stored in EEPROM)\n"); } }