207 Zeilen
6.0 KiB
C
207 Zeilen
6.0 KiB
C
//--------------------------------------------------------------
|
|
/*
|
|
|
|
LocoNet Hardware Serial connector
|
|
only for ESP8266 and ESP32
|
|
|
|
Use a share
|
|
|
|
Copyright (c) by Philipp Gahtow, year 2022
|
|
|
|
*/
|
|
|
|
#if defined(LOCONET) && (defined(ESP8266_MCU) || defined(ESP32_MCU))
|
|
|
|
#include <LocoNet.h> //include LocoNet OP Codes
|
|
|
|
#include <SoftwareSerial.h>
|
|
SoftwareSerial LocoNetTX; //Software Serial for TX Signal
|
|
#define LocoNetRX Serial //Hardware Serial for RX Signal
|
|
|
|
#define LnBufferMaxData 21 //length of LocoNet data packet
|
|
#define LnBufferSize 5 //size of the RX and TX buffer
|
|
#define LnMsgTimeout 1000 //timeout to revert a msg in µs
|
|
|
|
typedef struct //Msg Buffer
|
|
{
|
|
uint8_t read = 0; //zähler lesen
|
|
uint8_t write = 0; //zähler schreiben
|
|
uint8_t data[LnBufferSize][LnBufferMaxData]; //zu sendende Daten
|
|
} LnBuffer;
|
|
|
|
uint8_t writeRXpos = 0;
|
|
LnBuffer LnRX;
|
|
LnBuffer LnTX;
|
|
|
|
unsigned long previousData = 0; // will store last time data war received
|
|
|
|
//--------------------------------------------------------------
|
|
void LocoNetHw_init() {
|
|
//ESP8266 and ESP32:
|
|
LocoNetRX.end(); //stop running configuration
|
|
LocoNetRX.begin(16660); //set speed to Hw Serial
|
|
|
|
//UCRXI = Invert RX
|
|
//UCTXI = Invert TX
|
|
//UCBN = DataBits Count (2bin) 0:5bit, 1:6bit, 2:7bit, 3:8bit
|
|
//UCSBN = StopBits Count (2bit) 0:disable, 1:1bit, 2:1.5bit, 3:2bit
|
|
//U0C0 = BIT(UCRXI) | BIT(UCBN) | BIT(UCBN+1) | BIT(UCSBN);
|
|
// Inverse RX, 11 = 8bit Data, 01 = 1bit Stop
|
|
|
|
LocoNetTX.begin(16660, SWSERIAL_8N1, LNTxPin, LNTxPin, true); //Set Up SoftwareSerial asyncron
|
|
LocoNetTX.enableTx(true); //enable TX Mode!
|
|
|
|
//clear the RX and TX Buffer:
|
|
for (uint8_t i; i < LnBufferSize; i++) {
|
|
for (uint8_t m; m < LnBufferMaxData; m++) {
|
|
LnRX.data[i][m] = 0xFF;
|
|
LnTX.data[i][m] = 0xFF;
|
|
}
|
|
}
|
|
LnRX.read = 0;
|
|
LnRX.write = 0;
|
|
LnTX.read = 0;
|
|
LnRX.write = 0;
|
|
}
|
|
|
|
|
|
//--------------------------------------------------------------
|
|
bool LocoNet_available() {
|
|
return LnRX.read != LnRX.write;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
uint8_t LocoNet_readLength() {
|
|
if (LocoNet_available()) {
|
|
uint8_t len = LnRX.data[LnRX.read][0] >> 5; //1. Byte = length
|
|
if (len == B100)
|
|
return 2;
|
|
else if (len == B101)
|
|
return 4;
|
|
else if (len == B110)
|
|
return 6;
|
|
else return LnRX.data[LnRX.read][1] & 0x7F; //Länge in 2. Byte codiert.
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
void LocoNet_readData(uint8_t *data) {
|
|
if (LocoNet_available()) {
|
|
uint8_t len = LocoNet_readLength();
|
|
for (uint8_t s = 0; s < len; s++) {
|
|
data[s] = LnRX.data[LnRX.read][s];
|
|
}
|
|
LnRX.data[LnRX.read][0] = 0xFF; //clear
|
|
LnRX.read++;
|
|
if (LnRX.read == LnBufferSize)
|
|
LnRX.read = 0;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
void LocoNet_sendData(uint8_t *data) {
|
|
uint8_t len = data[0] >> 5; //read 1. Byte
|
|
//calculate the length:
|
|
if (len == B100)
|
|
len = 2;
|
|
else if (len == B101)
|
|
len = 4;
|
|
else if (len == B110)
|
|
len = 6;
|
|
else len = (data[1] & 0x7F); //2. Byte in der Nachricht ein 7-Bit-Zählwert ist (BYTE COUNT)
|
|
uint8_t XOR = 0xFF;
|
|
//copy Data to TX Buffer:
|
|
for(uint8_t s = 0; s < (len-1); s++) { //without XOR
|
|
LnTX.data[LnTX.write][s] = data[s];
|
|
XOR ^= data[s];
|
|
}
|
|
LnTX.data[LnTX.write][len-1] = XOR; //last byte
|
|
data[len-1] = XOR; //add XOR to requested data
|
|
LnTX.write++;
|
|
if (LnTX.write == LnBufferSize)
|
|
LnTX.write = 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
void LocoNet_updateRX() {
|
|
if (LocoNetRX.available()) {
|
|
previousData = micros(); //save in time
|
|
uint8_t d = LocoNetRX.read();
|
|
LnRX.data[LnRX.write][writeRXpos] = d; //save data
|
|
uint8_t len = LnRX.data[LnRX.write][0] >> 5; //read 1. Byte
|
|
//calculate the length:
|
|
if (len == B100)
|
|
len = 2;
|
|
else if (len == B101)
|
|
len = 4;
|
|
else if (len == B110)
|
|
len = 6;
|
|
else if (writeRXpos >= 1) {
|
|
len = (LnRX.data[LnRX.write][1] & 0x7F); //2. Byte in der Nachricht ein 7-Bit-Zählwert ist (BYTE COUNT)
|
|
if (len >= LnBufferMaxData) { //ERROR LENGTH
|
|
LnRX.data[LnRX.write][0] = 0xFF; //reset
|
|
writeRXpos = 0;
|
|
}
|
|
}
|
|
|
|
writeRXpos++;
|
|
if ((writeRXpos == len) && (len > 1)) { //accept only data with min. length of 2
|
|
writeRXpos = 0;
|
|
uint8_t cksum = 0; //Prüfsumme
|
|
for (uint8_t i = 0; i < len; i++) {
|
|
cksum ^= LnRX.data[LnRX.write][i];
|
|
}
|
|
if (cksum == 0xFF) {
|
|
LnRX.write++;
|
|
if (LnRX.write == LnBufferSize)
|
|
LnRX.write = 0;
|
|
}
|
|
#if defined(LnDEB)
|
|
else Debug.println(F("LN XOR Fail!"));
|
|
#endif
|
|
}
|
|
}
|
|
else {
|
|
if ((writeRXpos != 0) && (micros() - previousData >= LnMsgTimeout)) { //Timeout!
|
|
LnRX.data[LnRX.write][0] = 0xFF; //reset
|
|
writeRXpos = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------
|
|
void LocoNetRXTXupdate() {
|
|
//check if we have received data?
|
|
LocoNet_updateRX();
|
|
|
|
//check if we have to send data?
|
|
if (LnTX.read != LnTX.write) {
|
|
uint8_t writepos = 0;
|
|
uint8_t len = LnTX.data[LnTX.read][writepos] >> 5;
|
|
if (len == B100)
|
|
len = 2;
|
|
else if (len == B101)
|
|
len = 4;
|
|
else if (len == B110)
|
|
len = 6;
|
|
else len = (LnTX.data[LnTX.read][writepos + 1] & 0x7F); // 2. Byte = length!
|
|
do {
|
|
LocoNetTX.write(LnTX.data[LnTX.read][writepos]);
|
|
LocoNet_updateRX();
|
|
if (writeRXpos == writepos && LnRX.data[LnRX.write][writeRXpos] != LnTX.data[LnTX.read][writepos]) {
|
|
return; //stop here!!!!!!!!!!!!!!!!!!
|
|
//we will not go further!!!!!!!!!
|
|
}
|
|
writepos++;
|
|
} while (writepos < len);
|
|
//next data:
|
|
LnTX.read++;
|
|
if (LnTX.read == LnBufferSize)
|
|
LnTX.read = 0;
|
|
}
|
|
}
|
|
|
|
|
|
#endif
|