mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 09:49:32 +02:00
Revert "New feature: Double LilyGo!"
This commit is contained in:
parent
375d3a84f2
commit
6e183f506b
11 changed files with 1 additions and 1067 deletions
|
@ -50,12 +50,7 @@ This video explains all the above mentioned steps:
|
|||
https://youtu.be/_mH2AjnAjDk
|
||||
|
||||
## Dependencies 📖
|
||||
This code uses the following libraries, already located in the lib folder for an easy start:
|
||||
- ESP32-Arduino-CAN (https://github.com/miwagner/ESP32-Arduino-CAN/) slightly modified for this usecase
|
||||
- eModbus library (https://github.com/eModbus/eModbus)
|
||||
- Adafruit Neopixel (https://github.com/adafruit/Adafruit_NeoPixel)
|
||||
- mackelec SerialDataLink (https://github.com/mackelec/SerialDataLink)
|
||||
- pierremolinaro acan2515 (https://github.com/pierremolinaro/acan2515)
|
||||
This code uses two libraries, ESP32-Arduino-CAN (https://github.com/miwagner/ESP32-Arduino-CAN/) slightly modified for this usecase, and the eModbus library (https://github.com/eModbus/eModbus). Both these are already located in the Software folder for an easy start.
|
||||
|
||||
It is also based on the info found in the following excellent repositories/websites:
|
||||
- https://gitlab.com/pelle8/gen24
|
||||
|
|
|
@ -11,15 +11,12 @@
|
|||
#include "src/lib/eModbus-eModbus/Logging.h"
|
||||
#include "src/lib/eModbus-eModbus/ModbusServerRTU.h"
|
||||
#include "src/lib/eModbus-eModbus/scripts/mbServerFCs.h"
|
||||
#include "src/lib/mackelec-SerialDataLink/SerialDataLink.h"
|
||||
#include "src/lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
|
||||
#include "src/lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
|
||||
// Interval settings
|
||||
int intervalUpdateValues = 4800; // Interval at which to update inverter values / Modbus registers
|
||||
const int interval1 = 1; // Interval for 1ms tasks
|
||||
const int interval10 = 10; // Interval for 10ms tasks
|
||||
unsigned long previousMillis1ms = 0;
|
||||
unsigned long previousMillis10ms = 50;
|
||||
unsigned long previousMillisUpdateVal = 0;
|
||||
|
||||
|
@ -131,9 +128,6 @@ void loop() {
|
|||
#ifdef DUAL_CAN
|
||||
receive_can2();
|
||||
#endif
|
||||
#ifdef SERIAL_LINK_TRANSMITTER_INVERTER
|
||||
receive_serial();
|
||||
#endif
|
||||
|
||||
// Process
|
||||
if (millis() - previousMillis10ms >= interval10) // Every 10ms
|
||||
|
@ -156,9 +150,6 @@ void loop() {
|
|||
#ifdef DUAL_CAN
|
||||
send_can2();
|
||||
#endif
|
||||
#ifdef SERIAL_LINK_RECEIVER_FROM_BATTERY
|
||||
send_serial();
|
||||
#endif
|
||||
}
|
||||
|
||||
// Initialization functions
|
||||
|
@ -226,13 +217,6 @@ void init_modbus() {
|
|||
pinMode(PIN_5V_EN, OUTPUT);
|
||||
digitalWrite(PIN_5V_EN, HIGH);
|
||||
|
||||
#if defined(SERIAL_LINK_RECEIVER_FROM_BATTERY) || defined(SERIAL_LINK_TRANSMITTER_INVERTER)
|
||||
Serial2.begin(9600); // If the Modbus RTU port will be used for serial link
|
||||
#if defined(BYD_MODBUS) || defined(LUNA2000_MODBUS)
|
||||
#error Modbus pins cannot be used for Serial and Modbus at the same time!
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BYD_MODBUS
|
||||
// Init Static data to the RTU Modbus
|
||||
handle_static_data_modbus_byd();
|
||||
|
@ -402,26 +386,6 @@ void send_can() {
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifdef SERIAL_LINK_RECEIVER_FROM_BATTERY
|
||||
void send_serial() {
|
||||
static unsigned long currentMillis = millis();
|
||||
if (currentMillis - previousMillis1ms >= interval1) {
|
||||
previousMillis1ms = currentMillis;
|
||||
manageSerialLinkReceiver();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SERIAL_LINK_TRANSMITTER_INVERTER
|
||||
void receive_serial() {
|
||||
static unsigned long currentMillis = millis();
|
||||
if (currentMillis - previousMillis1ms >= interval1) {
|
||||
previousMillis1ms = currentMillis;
|
||||
manageSerialLinkTransmitter();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef DUAL_CAN
|
||||
void receive_can2() { // This function is similar to receive_can, but just takes care of inverters in the 2nd bus.
|
||||
// Depending on which inverter is selected, we forward this to their respective CAN routines
|
||||
|
|
|
@ -42,7 +42,5 @@
|
|||
//#define CONTACTOR_CONTROL //Enable this line to have pins 25,32,33 handle automatic precharge/contactor+/contactor- closing sequence
|
||||
//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM logic for contactors, which lower power consumption and heat generation
|
||||
//#define DUAL_CAN //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 controller (Needed for FoxESS inverters)
|
||||
//#define SERIAL_LINK_RECEIVER_FROM_BATTERY //Enable this line to send battery data over Modbus pins to another Lilygo (This LilyGo interfaces with battery)
|
||||
//#define SERIAL_LINK_TRANSMITTER_INVERTER //Enable this line to receive battery data over Modbus pins from another Lilygo (This LilyGo interfaces with inverter)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,9 +32,4 @@
|
|||
#ifdef TEST_FAKE_BATTERY
|
||||
#include "TEST-FAKE-BATTERY.h" //See this file for more Fake battery settings
|
||||
#endif
|
||||
|
||||
#ifdef SERIAL_LINK_RECEIVER_FROM_BATTERY
|
||||
#include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,115 +0,0 @@
|
|||
// SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp
|
||||
|
||||
#include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h"
|
||||
|
||||
//#define INVERTER_SEND_NUM_VARIABLES 3 //--- comment out if nothing to send
|
||||
#define INVERTER_RECV_NUM_VARIABLES 16
|
||||
|
||||
#ifdef INVERTER_SEND_NUM_VARIABLES
|
||||
const uint8_t sendingNumVariables = INVERTER_SEND_NUM_VARIABLES;
|
||||
#else
|
||||
const uint8_t sendingNumVariables = 0;
|
||||
#endif
|
||||
|
||||
// txid,rxid, num_send,num_recv
|
||||
SerialDataLink dataLinkReceive(Serial2, 0, 0x01, sendingNumVariables,
|
||||
INVERTER_RECV_NUM_VARIABLES); // ...
|
||||
|
||||
void __getData() {
|
||||
SOC = (uint16_t)dataLinkReceive.getReceivedData(0);
|
||||
StateOfHealth = (uint16_t)dataLinkReceive.getReceivedData(1);
|
||||
battery_voltage = (uint16_t)dataLinkReceive.getReceivedData(2);
|
||||
battery_current = (uint16_t)dataLinkReceive.getReceivedData(3);
|
||||
capacity_Wh = (uint16_t)dataLinkReceive.getReceivedData(4);
|
||||
remaining_capacity_Wh = (uint16_t)dataLinkReceive.getReceivedData(5);
|
||||
max_target_discharge_power = (uint16_t)dataLinkReceive.getReceivedData(6);
|
||||
max_target_charge_power = (uint16_t)dataLinkReceive.getReceivedData(7);
|
||||
bms_status = (uint16_t)dataLinkReceive.getReceivedData(8);
|
||||
bms_char_dis_status = (uint16_t)dataLinkReceive.getReceivedData(9);
|
||||
stat_batt_power = (uint16_t)dataLinkReceive.getReceivedData(10);
|
||||
temperature_min = (uint16_t)dataLinkReceive.getReceivedData(11);
|
||||
temperature_max = (uint16_t)dataLinkReceive.getReceivedData(12);
|
||||
cell_max_voltage = (uint16_t)dataLinkReceive.getReceivedData(13);
|
||||
cell_min_voltage = (uint16_t)dataLinkReceive.getReceivedData(14);
|
||||
batteryAllowsContactorClosing = (uint16_t)dataLinkReceive.getReceivedData(15);
|
||||
}
|
||||
|
||||
void updateData() {
|
||||
// --- update with fresh data
|
||||
/*
|
||||
dataLinkReceive.updateData(0,var1);
|
||||
dataLinkReceive.updateData(1,var2);
|
||||
dataLinkReceive.updateData(2,var3);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* @ 9600bps, assume void manageSerialLinkReceiver()
|
||||
* is called every 1mS
|
||||
*/
|
||||
|
||||
void manageSerialLinkReceiver() {
|
||||
static bool lasterror = false;
|
||||
static unsigned long lastGood;
|
||||
static uint16_t lastGoodMaxCharge;
|
||||
static uint16_t lastGoodMaxDischarge;
|
||||
static bool initLink = false;
|
||||
|
||||
unsigned long currentTime = millis();
|
||||
|
||||
if (!initLink) {
|
||||
initLink = true;
|
||||
// sends variables every 5000mS even if no change
|
||||
dataLinkReceive.setUpdateInterval(5000);
|
||||
#ifdef SERIALDATALINK_MUTEACK
|
||||
dataLinkReceive.muteACK(true);
|
||||
#endif
|
||||
}
|
||||
dataLinkReceive.run();
|
||||
bool readError = dataLinkReceive.checkReadError(true); // check for error & clear error flag
|
||||
LEDcolor = GREEN;
|
||||
if (readError) {
|
||||
LEDcolor = RED;
|
||||
bms_status = 4; //FAULT
|
||||
Serial.print(currentTime);
|
||||
Serial.println(" - ERROR: Serial Data Link - Read Error");
|
||||
lasterror = true;
|
||||
} else {
|
||||
if (lasterror) {
|
||||
lasterror = false;
|
||||
Serial.print(currentTime);
|
||||
Serial.println(" - RECOVERY: Serial Data Link - Read GOOD");
|
||||
}
|
||||
lastGood = currentTime;
|
||||
}
|
||||
if (dataLinkReceive.checkNewData(true)) // true = clear Flag
|
||||
{
|
||||
__getData();
|
||||
lastGoodMaxCharge = max_target_charge_power;
|
||||
lastGoodMaxDischarge = max_target_discharge_power;
|
||||
}
|
||||
|
||||
unsigned long minutesLost = (currentTime - lastGood) / 60000UL;
|
||||
;
|
||||
if (minutesLost > 0 && lastGood > 0) {
|
||||
// lose 25% each minute of data loss
|
||||
if (minutesLost < 4) {
|
||||
max_target_charge_power = (lastGoodMaxCharge * (4 - minutesLost)) / 4;
|
||||
max_target_discharge_power = (lastGoodMaxDischarge * (4 - minutesLost)) / 4;
|
||||
} else {
|
||||
max_target_charge_power = 0;
|
||||
max_target_discharge_power = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long updateTime = 0;
|
||||
|
||||
#ifdef INVERTER_SEND_NUM_VARIABLES
|
||||
if (currentTime - updateTime > 100) {
|
||||
updateTime = currentTime;
|
||||
dataLinkReceive.run();
|
||||
bool sendError = dataLinkReceive.checkTransmissionError(true); // check for error & clear error flag
|
||||
updateData();
|
||||
}
|
||||
#endif
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
// SERIAL-LINK-RECEIVER-FROM-BATTERY.h
|
||||
|
||||
#ifndef SERIAL_LINK_RECEIVER_FROM_BATTERY_H
|
||||
#define SERIAL_LINK_RECEIVER_FROM_BATTERY_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "../../USER_SETTINGS.h"
|
||||
#include "../devboard/config.h" // Needed for LED defines
|
||||
#include "../lib/mackelec-SerialDataLink/SerialDataLink.h"
|
||||
|
||||
// https://github.com/mackelec/SerialDataLink
|
||||
|
||||
#define ABSOLUTE_MAX_VOLTAGE \
|
||||
4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge)
|
||||
#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint16_t SOC; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000)
|
||||
extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485)
|
||||
extern uint16_t capacity_Wh; //Wh, 0-60000
|
||||
extern uint16_t remaining_capacity_Wh; //Wh, 0-60000
|
||||
extern uint16_t max_target_discharge_power; //W, 0-60000
|
||||
extern uint16_t max_target_charge_power; //W, 0-60000
|
||||
extern uint16_t bms_status; //Enum, 0-5
|
||||
extern uint16_t bms_char_dis_status; //Enum, 0-2
|
||||
extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530)
|
||||
extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385)
|
||||
extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385)
|
||||
extern uint16_t cell_max_voltage; //mV, 0-4350
|
||||
extern uint16_t cell_min_voltage; //mV, 0-4350
|
||||
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
extern uint8_t LEDcolor; //Enum, 0-10
|
||||
|
||||
void manageSerialLinkReceiver();
|
||||
|
||||
#endif
|
|
@ -29,8 +29,4 @@
|
|||
#include "SOLAX-CAN.h"
|
||||
#endif
|
||||
|
||||
#ifdef SERIAL_LINK_TRANSMITTER_INVERTER
|
||||
#include "SERIAL-LINK-TRANSMITTER-INVERTER.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
//SERIAL-LINK-TRANSMITTER-INVERTER.cpp
|
||||
|
||||
#include "SERIAL-LINK-TRANSMITTER-INVERTER.h"
|
||||
|
||||
/*
|
||||
* SerialDataLink
|
||||
* txid=1, rxid=0 gives this the startup transmit priority_queue
|
||||
* Will transmit max 16 int variable - receive none
|
||||
*/
|
||||
|
||||
#define BATTERY_SEND_NUM_VARIABLES 16
|
||||
//#define BATTERY_RECV_NUM_VARIABLES 3 //--- comment out if nothing to receive
|
||||
|
||||
#ifdef BATTERY_RECV_NUM_VARIABLES
|
||||
const uint8_t receivingNumVariables = BATTERY_RECV_NUM_VARIABLES;
|
||||
#else
|
||||
const uint8_t receivingNumVariables = 0;
|
||||
#endif
|
||||
|
||||
// txid,rxid,num_tx,num_rx
|
||||
SerialDataLink dataLinkTransmit(Serial2, 0x01, 0, BATTERY_SEND_NUM_VARIABLES, receivingNumVariables);
|
||||
|
||||
void _getData() {
|
||||
/*
|
||||
var1 = dataLinkTransmit.getReceivedData(0);
|
||||
var2 = dataLinkTransmit.getReceivedData(1);
|
||||
var3 = dataLinkTransmit.getReceivedData(2);
|
||||
*/
|
||||
}
|
||||
|
||||
void manageSerialLinkTransmitter() {
|
||||
static bool initLink = false;
|
||||
static unsigned long updateTime = 0;
|
||||
static bool lasterror = false;
|
||||
|
||||
dataLinkTransmit.run();
|
||||
|
||||
#ifdef BATTERY_RECV_NUM_VARIABLES
|
||||
bool readError = dataLinkTransmit.checkReadError(true); // check for error & clear error flag
|
||||
if (dataLinkTransmit.checkNewData(true)) // true = clear Flag
|
||||
{
|
||||
_getData();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (millis() - updateTime > 100) {
|
||||
updateTime = millis();
|
||||
if (!initLink) {
|
||||
initLink = true;
|
||||
// sends variables every 5000mS even if no change
|
||||
dataLinkTransmit.setUpdateInterval(5000);
|
||||
}
|
||||
bool sendError = dataLinkTransmit.checkTransmissionError(true);
|
||||
LEDcolor = GREEN;
|
||||
if (sendError) {
|
||||
LEDcolor = RED;
|
||||
Serial.print(millis());
|
||||
Serial.println(" - ERROR: Serial Data Link - SEND Error");
|
||||
lasterror = true;
|
||||
} else {
|
||||
if (lasterror) {
|
||||
lasterror = false;
|
||||
Serial.print(millis());
|
||||
Serial.println(" - RECOVERY: Serial Data Link - Send GOOD");
|
||||
}
|
||||
}
|
||||
|
||||
dataLinkTransmit.updateData(0, SOC);
|
||||
dataLinkTransmit.updateData(1, StateOfHealth);
|
||||
dataLinkTransmit.updateData(2, battery_voltage);
|
||||
dataLinkTransmit.updateData(3, battery_current);
|
||||
dataLinkTransmit.updateData(4, capacity_Wh);
|
||||
dataLinkTransmit.updateData(5, remaining_capacity_Wh);
|
||||
dataLinkTransmit.updateData(6, max_target_discharge_power);
|
||||
dataLinkTransmit.updateData(7, max_target_charge_power);
|
||||
dataLinkTransmit.updateData(8, bms_status);
|
||||
dataLinkTransmit.updateData(9, bms_char_dis_status);
|
||||
dataLinkTransmit.updateData(10, stat_batt_power);
|
||||
dataLinkTransmit.updateData(11, temperature_min);
|
||||
dataLinkTransmit.updateData(12, temperature_max);
|
||||
dataLinkTransmit.updateData(13, cell_max_voltage);
|
||||
dataLinkTransmit.updateData(14, cell_min_voltage);
|
||||
dataLinkTransmit.updateData(15, batteryAllowsContactorClosing);
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
//SERIAL-LINK-TRANSMITTER-INVERTER.h
|
||||
|
||||
#ifndef SERIAL_LINK_TRANSMITTER_INVERTER_H
|
||||
#define SERIAL_LINK_TRANSMITTER_INVERTER_H
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "../../USER_SETTINGS.h"
|
||||
#include "../devboard/config.h" // Needed for LED defines
|
||||
#include "../lib/mackelec-SerialDataLink/SerialDataLink.h"
|
||||
|
||||
// These parameters need to be mapped for the inverter
|
||||
extern uint16_t SOC; //SOC%, 0-100.00 (0-10000)
|
||||
extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000)
|
||||
extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000)
|
||||
extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485)
|
||||
extern uint16_t capacity_Wh; //Wh, 0-60000
|
||||
extern uint16_t remaining_capacity_Wh; //Wh, 0-60000
|
||||
extern uint16_t max_target_discharge_power; //W, 0-60000
|
||||
extern uint16_t max_target_charge_power; //W, 0-60000
|
||||
extern uint16_t bms_status; //Enum, 0-5
|
||||
extern uint16_t bms_char_dis_status; //Enum, 0-2
|
||||
extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530)
|
||||
extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385)
|
||||
extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385)
|
||||
extern uint16_t cell_max_voltage; //mV, 0-4350
|
||||
extern uint16_t cell_min_voltage; //mV, 0-4350
|
||||
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
extern uint8_t LEDcolor; //Enum, 0-10
|
||||
|
||||
void manageSerialLinkTransmitter();
|
||||
|
||||
#endif
|
|
@ -1,568 +0,0 @@
|
|||
// SerialDataLink.cpp
|
||||
|
||||
#include "SerialDataLink.h"
|
||||
|
||||
|
||||
const uint16_t crcTable[256] = {
|
||||
0, 32773, 32783, 10, 32795, 30, 20, 32785,
|
||||
32819, 54, 60, 32825, 40, 32813, 32807, 34,
|
||||
32867, 102, 108, 32873, 120, 32893, 32887, 114,
|
||||
80, 32853, 32863, 90, 32843, 78, 68, 32833,
|
||||
32963, 198, 204, 32969, 216, 32989, 32983, 210,
|
||||
240, 33013, 33023, 250, 33003, 238, 228, 32993,
|
||||
160, 32933, 32943, 170, 32955, 190, 180, 32945,
|
||||
32915, 150, 156, 32921, 136, 32909, 32903, 130,
|
||||
33155, 390, 396, 33161, 408, 33181, 33175, 402,
|
||||
432, 33205, 33215, 442, 33195, 430, 420, 33185,
|
||||
480, 33253, 33263, 490, 33275, 510, 500, 33265,
|
||||
33235, 470, 476, 33241, 456, 33229, 33223, 450,
|
||||
320, 33093, 33103, 330, 33115, 350, 340, 33105,
|
||||
33139, 374, 380, 33145, 360, 33133, 33127, 354,
|
||||
33059, 294, 300, 33065, 312, 33085, 33079, 306,
|
||||
272, 33045, 33055, 282, 33035, 270, 260, 33025,
|
||||
33539, 774, 780, 33545, 792, 33565, 33559, 786,
|
||||
816, 33589, 33599, 826, 33579, 814, 804, 33569,
|
||||
864, 33637, 33647, 874, 33659, 894, 884, 33649,
|
||||
33619, 854, 860, 33625, 840, 33613, 33607, 834,
|
||||
960, 33733, 33743, 970, 33755, 990, 980, 33745,
|
||||
33779, 1014, 1020, 33785, 1000, 33773, 33767, 994,
|
||||
33699, 934, 940, 33705, 952, 33725, 33719, 946,
|
||||
912, 33685, 33695, 922, 33675, 910, 900, 33665,
|
||||
640, 33413, 33423, 650, 33435, 670, 660, 33425,
|
||||
33459, 694, 700, 33465, 680, 33453, 33447, 674,
|
||||
33507, 742, 748, 33513, 760, 33533, 33527, 754,
|
||||
720, 33493, 33503, 730, 33483, 718, 708, 33473,
|
||||
33347, 582, 588, 33353, 600, 33373, 33367, 594,
|
||||
624, 33397, 33407, 634, 33387, 622, 612, 33377,
|
||||
544, 33317, 33327, 554, 33339, 574, 564, 33329,
|
||||
33299, 534, 540, 33305, 520, 33293, 33287, 514
|
||||
};
|
||||
|
||||
union Convert
|
||||
{
|
||||
uint16_t u16;
|
||||
int16_t i16;
|
||||
struct
|
||||
{
|
||||
byte low;
|
||||
byte high;
|
||||
};
|
||||
}convert;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Constructor
|
||||
SerialDataLink::SerialDataLink(Stream &serial, uint8_t transmitID, uint8_t receiveID, uint8_t maxIndexTX, uint8_t maxIndexRX, bool enableRetransmit)
|
||||
: serial(serial), transmitID(transmitID), receiveID(receiveID), maxIndexTX(maxIndexTX), maxIndexRX(maxIndexRX), retransmitEnabled(enableRetransmit) {
|
||||
// Initialize buffers and state variables
|
||||
txBufferIndex = 0;
|
||||
isTransmitting = false;
|
||||
isReceiving = false;
|
||||
transmissionError = false;
|
||||
readError = false;
|
||||
newData = false;
|
||||
|
||||
// Initialize data arrays and update flags
|
||||
|
||||
memset(dataArrayTX, 0, sizeof(dataArrayTX));
|
||||
memset(dataArrayRX, 0, sizeof(dataArrayRX));
|
||||
memset(dataUpdated, 0, sizeof(dataUpdated));
|
||||
memset(lastSent , 0, sizeof(lastSent ));
|
||||
|
||||
// Additional initialization as required
|
||||
}
|
||||
|
||||
void SerialDataLink::updateData(uint8_t index, int16_t value)
|
||||
{
|
||||
if (index < maxIndexTX)
|
||||
{
|
||||
if (dataArrayTX[index] != value)
|
||||
{
|
||||
dataArrayTX[index] = value;
|
||||
dataUpdated[index] = true;
|
||||
lastSent[index] = millis();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16_t SerialDataLink::getReceivedData(uint8_t index)
|
||||
{
|
||||
if (index < dataArraySizeRX) {
|
||||
return dataArrayRX[index];
|
||||
} else {
|
||||
// Handle the case where the index is out of bounds
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialDataLink::checkTransmissionError(bool resetFlag)
|
||||
{
|
||||
bool currentStatus = transmissionError;
|
||||
if (resetFlag && transmissionError) {
|
||||
transmissionError = false;
|
||||
}
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
bool SerialDataLink::checkReadError(bool reset)
|
||||
{
|
||||
bool error = readError;
|
||||
if (reset) {
|
||||
readError = false;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
bool SerialDataLink::checkNewData(bool resetFlag) {
|
||||
bool currentStatus = newData;
|
||||
if (resetFlag && newData) {
|
||||
newData = false;
|
||||
}
|
||||
return currentStatus;
|
||||
}
|
||||
|
||||
void SerialDataLink::muteACK(bool mute)
|
||||
{
|
||||
muteAcknowledgement = mute;
|
||||
}
|
||||
|
||||
void SerialDataLink::run()
|
||||
{
|
||||
unsigned long currentTime = millis();
|
||||
static DataLinkState oldstate;
|
||||
|
||||
|
||||
// Check if state has not changed for a prolonged period
|
||||
if (oldstate != currentState)
|
||||
{
|
||||
lastStateChangeTime = currentTime;
|
||||
oldstate = currentState;
|
||||
}
|
||||
if ((currentTime - lastStateChangeTime) > stateChangeTimeout) {
|
||||
// Reset the state to Idle and perform necessary cleanup
|
||||
currentState = DataLinkState::Idle;
|
||||
// Perform any additional cleanup or reinitialization here
|
||||
// ...
|
||||
|
||||
lastStateChangeTime = currentTime; // Reset the last state change time
|
||||
}
|
||||
switch (currentState)
|
||||
{
|
||||
case DataLinkState::Idle:
|
||||
// Decide if the device should start transmitting
|
||||
currentState = DataLinkState::Receiving;
|
||||
if (shouldTransmit())
|
||||
{
|
||||
currentState = DataLinkState::Transmitting;
|
||||
}
|
||||
break;
|
||||
|
||||
case DataLinkState::Transmitting:
|
||||
if (isTransmitting)
|
||||
{
|
||||
sendNextByte(); // Continue sending the current data
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
constructPacket(); // Construct a new packet if not currently transmitting
|
||||
|
||||
if (muteAcknowledgement)
|
||||
{
|
||||
needToACK = false;
|
||||
needToNACK = false;
|
||||
}
|
||||
uint8_t ack;
|
||||
// now it is known which acknoledge need sending since last Reception
|
||||
if (needToACK)
|
||||
{
|
||||
needToACK = false;
|
||||
ack = (txBufferIndex > 5) ? ACK_RTT_CODE : ACK_CODE;
|
||||
serial.write(ack);
|
||||
}
|
||||
if (needToNACK)
|
||||
{
|
||||
needToNACK = false;
|
||||
ack = (txBufferIndex > 5) ? NACK_RTT_CODE : NACK_CODE;
|
||||
serial.write(ack);
|
||||
}
|
||||
}
|
||||
|
||||
if (maxIndexTX < 1)
|
||||
{
|
||||
currentState = DataLinkState::Receiving;
|
||||
}
|
||||
// Check if the transmission is complete
|
||||
if (transmissionComplete)
|
||||
{
|
||||
transmissionComplete = false;
|
||||
isTransmitting = false;
|
||||
currentState = DataLinkState::WaitingForAck; // Move to WaitingForAck state
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case DataLinkState::WaitingForAck:
|
||||
if (ackTimeout())
|
||||
{
|
||||
// Handle ACK timeout scenario
|
||||
transmissionError = true;
|
||||
isTransmitting = false;
|
||||
//handleAckTimeout();
|
||||
//--- if no ACK's etc received may as well move to Transmitting
|
||||
currentState = DataLinkState::Transmitting;
|
||||
}
|
||||
if (ackReceived())
|
||||
{
|
||||
// No data to send from the other device
|
||||
currentState = DataLinkState::Transmitting;
|
||||
}
|
||||
if (requestToSend)
|
||||
{
|
||||
// The other device has data to send (indicated by ACK+RTT)
|
||||
currentState = DataLinkState::Receiving;
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case DataLinkState::Receiving:
|
||||
read();
|
||||
if (readComplete)
|
||||
{
|
||||
readComplete = false;
|
||||
// transition to transmit mode
|
||||
currentState = DataLinkState::Transmitting;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
currentState = DataLinkState::Idle;
|
||||
}
|
||||
}
|
||||
|
||||
void SerialDataLink::updateState(DataLinkState newState)
|
||||
{
|
||||
if (currentState != newState)
|
||||
{
|
||||
currentState = newState;
|
||||
lastStateChangeTime = millis();
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialDataLink::shouldTransmit()
|
||||
{
|
||||
// Priority condition: Device with transmitID = 1 and receiveID = 0 has the highest priority
|
||||
if (transmitID == 1 && receiveID == 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SerialDataLink::constructPacket()
|
||||
{
|
||||
if (maxIndexTX <1) return;
|
||||
if (!isTransmitting)
|
||||
{
|
||||
lastTransmissionTime = millis();
|
||||
txBufferIndex = 0; // Reset the TX buffer index
|
||||
|
||||
addToTxBuffer(headerChar);
|
||||
addToTxBuffer(transmitID);
|
||||
addToTxBuffer(0); // EOT position - place holder
|
||||
unsigned long currentTime = millis();
|
||||
int count = txBufferIndex;
|
||||
|
||||
for (uint8_t i = 0; i < maxIndexTX; i++)
|
||||
{
|
||||
if (dataUpdated[i] || (currentTime - lastSent[i] >= updateInterval))
|
||||
{
|
||||
addToTxBuffer(i);
|
||||
convert.i16 = dataArrayTX[i];
|
||||
addToTxBuffer(convert.high);
|
||||
addToTxBuffer(convert.low);
|
||||
|
||||
dataUpdated[i] = false;
|
||||
lastSent[i] = currentTime; // Update the last sent time for this index
|
||||
}
|
||||
}
|
||||
|
||||
if (count == txBufferIndex)
|
||||
{
|
||||
// No data was added to the buffer, so no need to send a packet
|
||||
return;
|
||||
}
|
||||
|
||||
addToTxBuffer(eotChar);
|
||||
//----- assign EOT position
|
||||
txBuffer[2] = txBufferIndex - 1;
|
||||
uint16_t crc = calculateCRC16(txBuffer, txBufferIndex);
|
||||
convert.u16 = crc;
|
||||
addToTxBuffer(convert.high);
|
||||
addToTxBuffer(convert.low);
|
||||
isTransmitting = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SerialDataLink::addToTxBuffer(uint8_t byte)
|
||||
{
|
||||
if (txBufferIndex < txBufferSize)
|
||||
{
|
||||
txBuffer[txBufferIndex] = byte;
|
||||
txBufferIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialDataLink::sendNextByte()
|
||||
{
|
||||
if (!isTransmitting) return false;
|
||||
|
||||
if (txBufferIndex >= txBufferSize)
|
||||
{
|
||||
txBufferIndex = 0; // Reset the TX buffer index
|
||||
isTransmitting = false;
|
||||
return false; // Buffer was fully sent, end transmission
|
||||
}
|
||||
serial.write(txBuffer[sendBufferIndex]);
|
||||
sendBufferIndex++;
|
||||
|
||||
if (sendBufferIndex >= txBufferIndex)
|
||||
{
|
||||
isTransmitting = false;
|
||||
txBufferIndex = 0; // Reset the TX buffer index for the next packet
|
||||
sendBufferIndex = 0;
|
||||
transmissionComplete = true;
|
||||
return true; // Packet was fully sent
|
||||
}
|
||||
return false; // More bytes remain to be sent
|
||||
}
|
||||
|
||||
bool SerialDataLink::ackReceived()
|
||||
{
|
||||
// Check if there is data available to read
|
||||
if (serial.available() > 0)
|
||||
{
|
||||
// Peek at the next byte without removing it from the buffer
|
||||
uint8_t nextByte = serial.peek();
|
||||
|
||||
if (nextByte == headerChar)
|
||||
{
|
||||
requestToSend = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t receivedByte = serial.read();
|
||||
|
||||
switch (receivedByte)
|
||||
{
|
||||
case ACK_CODE:
|
||||
// Handle standard ACK
|
||||
return true;
|
||||
|
||||
case ACK_RTT_CODE:
|
||||
// Handle ACK with request to transmit
|
||||
requestToSend = true;
|
||||
return true;
|
||||
|
||||
case NACK_RTT_CODE:
|
||||
requestToSend = true;
|
||||
case NACK_CODE:
|
||||
transmissionError = true;
|
||||
return false;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false; // No ACK, NACK, or new packet received
|
||||
}
|
||||
|
||||
bool SerialDataLink::ackTimeout()
|
||||
{
|
||||
// Check if the current time has exceeded the last transmission time by the ACK timeout period
|
||||
if (millis() - lastTransmissionTime > ACK_TIMEOUT) {
|
||||
return true; // Timeout occurred
|
||||
}
|
||||
return false; // No timeout
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SerialDataLink::read()
|
||||
{
|
||||
if (maxIndexRX < 1) return;
|
||||
if (serial.available())
|
||||
{
|
||||
//Serial.print(".");
|
||||
if (millis() - lastHeaderTime > PACKET_TIMEOUT && rxBufferIndex > 0)
|
||||
{
|
||||
// Timeout occurred, reset buffer and pointer
|
||||
rxBufferIndex = 0;
|
||||
eotPosition = 0;
|
||||
readError = true;
|
||||
}
|
||||
uint8_t incomingByte = serial.read();
|
||||
switch (rxBufferIndex) {
|
||||
case 0: // Looking for the header
|
||||
if (incomingByte == headerChar)
|
||||
{
|
||||
lastHeaderTime = millis();
|
||||
rxBuffer[rxBufferIndex] = incomingByte;
|
||||
rxBufferIndex++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // Looking for the address
|
||||
if (incomingByte == receiveID) {
|
||||
rxBuffer[rxBufferIndex] = incomingByte;
|
||||
rxBufferIndex++;
|
||||
} else {
|
||||
// Address mismatch, reset to look for a new packet
|
||||
rxBufferIndex = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // EOT position
|
||||
eotPosition = incomingByte;
|
||||
rxBuffer[rxBufferIndex] = incomingByte;
|
||||
rxBufferIndex++;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Normal data handling
|
||||
rxBuffer[rxBufferIndex] = incomingByte;
|
||||
rxBufferIndex++;
|
||||
|
||||
if (isCompletePacket())
|
||||
{
|
||||
processPacket();
|
||||
rxBufferIndex = 0; // Reset for the next packet
|
||||
readComplete = true; // Indicate that read operation is complete
|
||||
}
|
||||
|
||||
// Check for buffer overflow
|
||||
if (rxBufferIndex >= rxBufferSize)
|
||||
{
|
||||
rxBufferIndex = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SerialDataLink::isCompletePacket() {
|
||||
if (rxBufferIndex - 3 < eotPosition) return false;
|
||||
// Ensure there are enough bytes for EOT + 2-byte CRC
|
||||
|
||||
// Check if the third-last byte is the EOT character
|
||||
if (rxBuffer[eotPosition] == eotChar)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SerialDataLink::checkCRC()
|
||||
{
|
||||
uint16_t receivedCrc;
|
||||
if (rxBufferIndex < 3)
|
||||
{
|
||||
// Not enough data for CRC check
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
convert.high = rxBuffer[rxBufferIndex - 2];
|
||||
convert.low = rxBuffer[rxBufferIndex - 1];
|
||||
receivedCrc = convert.u16;
|
||||
|
||||
// Calculate CRC for the received data (excluding the CRC bytes themselves)
|
||||
uint16_t calculatedCrc = calculateCRC16(rxBuffer, rxBufferIndex - 2);
|
||||
return receivedCrc == calculatedCrc;
|
||||
}
|
||||
|
||||
|
||||
void SerialDataLink::processPacket()
|
||||
{
|
||||
|
||||
if (!checkCRC()) {
|
||||
// CRC check failed, handle the error
|
||||
readError = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Start from index 3 to skip the SOT and ADDRESS and EOT Position characters
|
||||
uint8_t i = 3;
|
||||
while (i < eotPosition)
|
||||
{
|
||||
uint8_t arrayID = rxBuffer[i++];
|
||||
|
||||
// Make sure there's enough data for a complete int16 (2 bytes)
|
||||
if (i + 1 >= rxBufferIndex) {
|
||||
readError = true;
|
||||
needToNACK = true;
|
||||
return; // Incomplete packet or buffer overflow
|
||||
}
|
||||
|
||||
// Combine the next two bytes into an int16 value
|
||||
int16_t value = (int16_t(rxBuffer[i]) << 8) | int16_t(rxBuffer[i + 1]);
|
||||
i += 2;
|
||||
|
||||
// Handle the array ID and value here
|
||||
if (arrayID < dataArraySizeRX) {
|
||||
dataArrayRX[arrayID] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle invalid array ID
|
||||
readError = true;
|
||||
needToNACK = true;
|
||||
return;
|
||||
}
|
||||
newData = true;
|
||||
needToACK = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SerialDataLink::setUpdateInterval(unsigned long interval) {
|
||||
updateInterval = interval;
|
||||
}
|
||||
|
||||
void SerialDataLink::setAckTimeout(unsigned long timeout) {
|
||||
ACK_TIMEOUT = timeout;
|
||||
}
|
||||
|
||||
void SerialDataLink::setPacketTimeout(unsigned long timeout) {
|
||||
PACKET_TIMEOUT = timeout;
|
||||
}
|
||||
|
||||
void SerialDataLink::setHeaderChar(char header)
|
||||
{
|
||||
headerChar = header;
|
||||
}
|
||||
|
||||
void SerialDataLink::setEOTChar(char eot)
|
||||
{
|
||||
eotChar = eot;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint16_t SerialDataLink::calculateCRC16(const uint8_t* data, size_t length)
|
||||
{
|
||||
uint16_t crc = 0xFFFF; // Start value for CRC
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
uint8_t index = (crc >> 8) ^ data[i];
|
||||
crc = (crc << 8) ^ crcTable[index];
|
||||
}
|
||||
return crc;
|
||||
}
|
|
@ -1,176 +0,0 @@
|
|||
/**
|
||||
* @file SerialDataLink.h
|
||||
* @brief Half-Duplex Serial Data Link for Arduino
|
||||
*
|
||||
* This file contains the definition of the SerialDataLink class, designed to facilitate
|
||||
* half-duplex communication between Arduino controllers. The class employs a non-blocking,
|
||||
* poll-based approach to transmit and receive data, making it suitable for applications
|
||||
* where continuous monitoring and variable transfer between controllers are required.
|
||||
*
|
||||
* The half-duplex nature of this implementation allows for data transfer in both directions,
|
||||
* but not simultaneously, ensuring a controlled communication flow and reducing the likelihood
|
||||
* of data collision.
|
||||
*
|
||||
*
|
||||
* @author MackElec
|
||||
* @web https://github.com/mackelec/SerialDataLink
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
// ... Class definition ...
|
||||
|
||||
/**
|
||||
* @class SerialDataLink
|
||||
* @brief Class for managing half-duplex serial communication.
|
||||
*
|
||||
* Provides functions to send and receive data in a half-duplex manner over a serial link.
|
||||
* It supports non-blocking operation with a polling approach to check for new data and
|
||||
* transmission errors.
|
||||
*
|
||||
* Public Methods:
|
||||
* - SerialDataLink(): Constructor to initialize the communication parameters.
|
||||
* - run(): Main method to be called frequently to handle data transmission and reception.
|
||||
* - updateData(): Method to update data to be transmitted.
|
||||
* - getReceivedData(): Retrieves data received from the serial link.
|
||||
* - checkNewData(): Checks if new data has been received.
|
||||
* - checkTransmissionError(): Checks for transmission errors.
|
||||
* - checkReadError(): Checks for read errors.
|
||||
* - setUpdateInterval(): Sets the interval for data updates.
|
||||
* - setAckTimeout(): Sets the timeout for acknowledgments.
|
||||
* - setPacketTimeout(): Sets the timeout for packet reception.
|
||||
* - setHeaderChar(): Sets the character used to denote the start of a packet.
|
||||
* - setEOTChar(): Sets the character used to denote the end of a packet.
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef SERIALDATALINK_H
|
||||
#define SERIALDATALINK_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class SerialDataLink {
|
||||
public:
|
||||
// Constructor
|
||||
SerialDataLink(Stream &serial, uint8_t transmitID, uint8_t receiveID, uint8_t maxIndexTX, uint8_t maxIndexRX, bool enableRetransmit = false);
|
||||
|
||||
// Method to handle data transmission and reception
|
||||
void run();
|
||||
|
||||
void updateData(uint8_t index, int16_t value);
|
||||
|
||||
// Check if new data has been received
|
||||
bool checkNewData(bool resetFlag);
|
||||
int16_t getReceivedData(uint8_t index);
|
||||
|
||||
// Check for errors
|
||||
bool checkTransmissionError(bool resetFlag);
|
||||
bool checkReadError(bool resetFlag);
|
||||
|
||||
// Setter methods for various parameters and special characters
|
||||
|
||||
void setUpdateInterval(unsigned long interval);
|
||||
void setAckTimeout(unsigned long timeout);
|
||||
void setPacketTimeout(unsigned long timeout);
|
||||
|
||||
void setHeaderChar(char header);
|
||||
void setEOTChar(char eot);
|
||||
void muteACK(bool mute);
|
||||
|
||||
private:
|
||||
enum class DataLinkState
|
||||
{
|
||||
Idle,
|
||||
Transmitting,
|
||||
WaitingForAck,
|
||||
Receiving,
|
||||
Error
|
||||
};
|
||||
|
||||
DataLinkState currentState;
|
||||
Stream &serial;
|
||||
uint8_t transmitID;
|
||||
uint8_t receiveID;
|
||||
|
||||
// Separate max indices for TX and RX
|
||||
const uint8_t maxIndexTX;
|
||||
const uint8_t maxIndexRX;
|
||||
|
||||
|
||||
// Buffer and state management
|
||||
static const uint8_t txBufferSize = 128; // Adjust size as needed
|
||||
static const uint8_t rxBufferSize = 128; // Adjust size as needed
|
||||
|
||||
uint8_t txBuffer[txBufferSize];
|
||||
uint8_t rxBuffer[rxBufferSize];
|
||||
|
||||
uint8_t txBufferIndex;
|
||||
uint8_t rxBufferIndex;
|
||||
uint8_t sendBufferIndex = 0;
|
||||
|
||||
bool isTransmitting;
|
||||
bool transmissionComplete = false;
|
||||
bool isReceiving;
|
||||
bool readComplete = false;
|
||||
bool retransmitEnabled;
|
||||
bool transmissionError = false;
|
||||
bool readError = false;
|
||||
bool muteAcknowledgement = false;
|
||||
|
||||
// Data arrays and update management
|
||||
|
||||
static const uint8_t dataArraySizeTX = 20; // Adjust size as needed for TX
|
||||
static const uint8_t dataArraySizeRX = 20; // Adjust size as needed for RX
|
||||
|
||||
int16_t dataArrayTX[dataArraySizeTX];
|
||||
int16_t dataArrayRX[dataArraySizeRX];
|
||||
bool dataUpdated[dataArraySizeTX];
|
||||
unsigned long lastSent[dataArraySizeTX];
|
||||
|
||||
unsigned long updateInterval = 500;
|
||||
unsigned long ACK_TIMEOUT = 100;
|
||||
unsigned long PACKET_TIMEOUT = 100; // Timeout in milliseconds
|
||||
|
||||
unsigned long lastStateChangeTime = 0;
|
||||
unsigned long stateChangeTimeout = 200;
|
||||
|
||||
// Special characters for packet framing
|
||||
char headerChar = '<';
|
||||
char eotChar = '>';
|
||||
|
||||
static const uint8_t ACK_CODE = 0x06; // Standard acknowledgment
|
||||
static const uint8_t ACK_RTT_CODE = 0x07; // Acknowledgment with request to transmit
|
||||
static const uint8_t NACK_CODE = 0x08; // Negative acknowledgment
|
||||
static const uint8_t NACK_RTT_CODE = 0x09; // Negative acknowledgment with request to transmit
|
||||
|
||||
|
||||
|
||||
// Internal methods for packet construction, transmission, and reception
|
||||
bool shouldTransmit();
|
||||
void constructPacket();
|
||||
void addToTxBuffer(uint8_t byte);
|
||||
bool sendNextByte();
|
||||
bool ackReceived();
|
||||
bool ackTimeout();
|
||||
void updateState(DataLinkState newState);
|
||||
|
||||
// Internal methods for reception
|
||||
void read();
|
||||
void handleResendRequest();
|
||||
bool isCompletePacket();
|
||||
void processPacket();
|
||||
void sendACK();
|
||||
bool checkCRC();
|
||||
uint16_t calculateCRC16(const uint8_t* data, size_t length);
|
||||
|
||||
unsigned long lastTransmissionTime;
|
||||
bool requestToSend = false;
|
||||
unsigned long lastHeaderTime = 0;
|
||||
bool newData = false;
|
||||
bool needToACK = false;
|
||||
bool needToNACK = false;
|
||||
uint8_t eotPosition = 0;
|
||||
};
|
||||
|
||||
#endif // SERIALDATALINK_H
|
Loading…
Add table
Add a link
Reference in a new issue