This commit is contained in:
Rens Pastoor
2025-05-27 22:41:46 +02:00
parent d141296aea
commit 11b391b8a1
416 changed files with 25232 additions and 0 deletions

View File

@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

View File

@@ -0,0 +1,39 @@
#include <Arduino.h>
#ifndef SERIALPROCESS_H
#define SERIALPROCESS_H
class SerialProcess {
private:
uint8_t ndx; // Current index for the buffer
const char beginMarker = '#'; // Marker to indicate the start of a message
const char endMarker = ';'; // Marker to indicate the end of a message
char rc; // Character read from Serial
int address; // Device address
bool newData; // Flag for new data availability
static const uint8_t numChars = 255; // Maximum size of the buffer
char receivedChars[numChars]; // Buffer for incoming data
bool rcCheck;
public:
// Constructor
explicit SerialProcess(int addr);
// Store Serial Input (if available)
void SerialInput();
// Check if new data is available
bool isNewDataAvailable();
// Get the received data
char* getReceivedData();
// Process the received message
void getPayload(char* payload);
// Send message in the correct format
void sendMessage(int receiver, const char* payload);
void changeAddress(int addr);
};
#endif // SERIALPROCESS_H

View File

@@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into the executable file.
The source code of each library should be placed in a separate directory
("lib/your_library_name/[Code]").
For example, see the structure of the following example libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
Example contents of `src/main.c` using Foo and Bar:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
The PlatformIO Library Dependency Finder will find automatically dependent
libraries by scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

View File

@@ -0,0 +1,16 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps = plerup/EspSoftwareSerial@^8.2.0

View File

@@ -0,0 +1,74 @@
#include "SerialProcess.h"
#include <Arduino.h>
// Constructor
SerialProcess::SerialProcess(int addr)
: address(addr), ndx(0), rc(0), newData(false), rcCheck(false) {
Serial.begin(115200);
}
// Processes Serial Input
void SerialProcess::SerialInput() {
while (Serial.available() > 0) {
rc = static_cast<char>(Serial.read());
if (rc == beginMarker) {
rcCheck = true; // Start reading after the begin marker
ndx = 0; // Reset index for new message
}
if (rcCheck) {
// Store the character if within bounds
if (ndx < numChars - 1) {
receivedChars[ndx++] = rc;
}
// Check for end marker
if (rc == endMarker) {
receivedChars[ndx] = '\0'; // Null-terminate the string
newData = true; // Mark new data as available
rcCheck = false; // Stop reading until the next begin marker
}
}
}
}
// Check if new data is available
bool SerialProcess::isNewDataAvailable() {
return newData;
}
// Get the received data
char* SerialProcess::getReceivedData() {
if (newData) {
newData = false; // Reset the flag after accessing the data
return receivedChars;
}
return nullptr; // No new data
}
// Process the received message
void SerialProcess::getPayload(char *payload) {
if (newData) {
uint8_t source;
uint8_t destination;
char data[255]; // Allocate a buffer for the data
int parsed = sscanf(receivedChars, "#%hhu:%hhu:%63s;", &source, &destination, data);
if (parsed == 3 && destination == address) { // Ensure all fields are parsed correctly
strcpy(payload, data); // Copy data to the provided buffer
newData = false; // Mark the data as processed
} else if (address != source) {
Serial.print(receivedChars); // Forward the message
}
}
}
// Send a message in the correct format
void SerialProcess::sendMessage(int receiver, const char* payload) {
Serial.printf("#%u:%u:%s;", address, receiver, payload);
}
void SerialProcess::changeAddress(int addr) {
address = addr; // Update the device address
}

View File

@@ -0,0 +1,238 @@
#include <Arduino.h>
#include "SerialProcess.h"
#define LEDRED 14
#define LEDORANGE 13
#define LEDGREEN 12
unsigned long previousMillis = 0;
const unsigned long greenDuration = 5000;
const unsigned long yellowDuration = 2000;
const unsigned long redDuration = 5000;
const unsigned long transitionDuration = 2000;
const unsigned long heartbeatInterval = 1000;
const unsigned long heartbeatTimeout = 3000;
const unsigned long blinkInterval = 500;
unsigned long lastHeartbeatMillis = 0;
unsigned long lastBlinkMillis = 0;
bool blinkState = false;
enum State { GREEN, YELLOW, RED, TRANSITION, ERROR };
State currentState = GREEN;
const char *slavecheck = "#slvchck;";
const char *slaveack = "#slvack;";
const char *masterack = "#mstack;";
const char *turnRed = "tr";
const char *turnOrange = "to";
const char *turnGreen = "tg";
const char *heartbeat = "hb";
int node; // other bord addres number
int address = 0; // Device address
void setRed(){
digitalWrite(LEDRED, HIGH);
digitalWrite(LEDORANGE, LOW);
digitalWrite(LEDGREEN, LOW);
}
void setOrange(){
digitalWrite(LEDRED, LOW);
digitalWrite(LEDORANGE, HIGH);
digitalWrite(LEDGREEN, LOW);
}
void setGreen(){
digitalWrite(LEDRED, LOW);
digitalWrite(LEDORANGE, LOW);
digitalWrite(LEDGREEN, HIGH);
}
SerialProcess serialcom(0);
bool MasterCheck() {
SerialProcess serialcomchecker(1000);
const unsigned long timeout = 2000;
unsigned long startTime = millis();
bool isMaster = true;
bool checkSent = false;
bool gotResponse = false;
delay(random(100, 600)); // Randomize startup slightly
Serial.print(slavecheck); // Send check to see if someone replies
checkSent = true;
while (millis() - startTime < timeout) {
if (Serial.available()) {
serialcomchecker.SerialInput();
char* payload = serialcomchecker.getReceivedData();
if (strcmp(payload, slavecheck) == 0) {
// Got a check while we also sent a check — respond and become SLAVE
Serial.print(slaveack);
isMaster = false;
break;
} else if (strcmp(payload, slaveack) == 0) {
// Got an ACK from the other side — we are master
Serial.print(masterack);
isMaster = true;
break;
} else if (strcmp(payload, masterack) == 0) {
// Got master ack — we must be slave
isMaster = false;
break;
}
}
}
// Failsafe: no response at all
if (!Serial.available() && !gotResponse) {
// Assume we are master
isMaster = true;
Serial.print(masterack);
}
return isMaster;
}
void updateLights() {
switch (currentState) {
case GREEN:
setGreen();
serialcom.sendMessage(node, turnGreen);
break;
case YELLOW:
setOrange();
serialcom.sendMessage(node, turnOrange);
break;
case RED:
setGreen();
serialcom.sendMessage(node, turnRed);
break;
case TRANSITION:
serialcom.sendMessage(node, turnOrange);
break;
case ERROR:
if (millis() - lastBlinkMillis >= blinkInterval) {
blinkState = !blinkState;
digitalWrite(LEDORANGE, blinkState ? HIGH : LOW);
lastBlinkMillis = millis();
}
break;
}
}
void sendHeartbeat() {
serialcom.sendMessage(node,heartbeat);
Serial.println("Sent: Heartbeat");
}
void master(){
bool running = true;
while (running){
unsigned long currentMillis = millis();
if (currentMillis - lastHeartbeatMillis >= heartbeatInterval) {
sendHeartbeat();
lastHeartbeatMillis = currentMillis;
}
if (currentMillis - lastHeartbeatMillis > heartbeatTimeout) {
currentState = ERROR;
updateLights();
return;
}
switch (currentState) {
case GREEN:
if (currentMillis - previousMillis >= greenDuration) {
currentState = YELLOW;
previousMillis = currentMillis;
updateLights();
}
break;
case YELLOW:
if (currentMillis - previousMillis >= yellowDuration) {
currentState = RED;
previousMillis = currentMillis;
updateLights();
}
break;
case RED:
if (currentMillis - previousMillis >= redDuration) {
currentState = TRANSITION;
previousMillis = currentMillis;
updateLights();
}
break;
case TRANSITION:
if (currentMillis - previousMillis >= transitionDuration) {
currentState = GREEN;
previousMillis = millis();
updateLights();
}
break;
case ERROR:
updateLights();
break;
}
}
}
void setup() {
Serial.begin(115200);
pinMode(LEDGREEN, OUTPUT);
pinMode(LEDORANGE, OUTPUT);
pinMode(LEDRED, OUTPUT);
bool MorS = MasterCheck(); // Check if master or slave
//set address for master or slave
if (MorS == false){
address = 2; // Set address for this slave
node = 1; // Set address for master
} else {
address = 1; // Set address for this master
node = 2; // Set address for slave
}
previousMillis = millis();
lastHeartbeatMillis = millis();
updateLights();
setRed();
serialcom.changeAddress(address); // Set address for serial communication
}
void slave(){
bool running = true;
char *command;
while (running && Serial.available() > 0){
serialcom.SerialInput();
serialcom.getPayload(command);
if (strcmp(command, turnRed)) setRed();
else if (strcmp(command, turnOrange)) setOrange();
else if (strcmp(command, turnGreen)) setGreen();
else if (strcmp(command, heartbeat)) {
lastHeartbeatMillis = millis();
digitalWrite(LEDRED, LOW); // Reset the orange blink pattern
digitalWrite(LEDORANGE, LOW);
}
else {
Serial.print("slave: unknown command");
}
}
if (millis() - lastHeartbeatMillis > heartbeatTimeout) {
// Blink the red and yellow LEDs to indicate an error (orange light)
if (millis() - lastBlinkMillis >= blinkInterval) {
blinkState = !blinkState;
digitalWrite(LEDORANGE, blinkState ? HIGH : LOW);
lastBlinkMillis = millis();
}
}
}
void loop(){
serialcom.changeAddress(2);
if (address == 1) slave(); //master
else if (address == 2) slave(); //slave
else Serial.print("master slave issue");
}

View File

@@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html