1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-04-21 12:31:19 +02:00

sorta works

This commit is contained in:
travis-farmer 2024-12-22 16:02:07 -05:00
parent c151b52114
commit 250a34bc09
No known key found for this signature in database
GPG Key ID: 0BC296791D14CB35
2 changed files with 295 additions and 212 deletions

View File

@ -37,7 +37,7 @@ RSproto::RSproto(uint8_t busNo, HardwareSerial &serial, unsigned long baud, int8
_txPin = txPin; _txPin = txPin;
_busNo = busNo; _busNo = busNo;
_cycleTime = cycleTime; _cycleTime = cycleTime * 1000UL;
bufferLength=0; bufferLength=0;
inCommandPayload=PAYLOAD_FALSE; inCommandPayload=PAYLOAD_FALSE;
// Add device to HAL device chain // Add device to HAL device chain
@ -74,199 +74,233 @@ uint16_t RSproto::crc16(uint8_t *data, uint16_t length) {
void RSproto::_loop(unsigned long currentMicros) { void RSproto::_loop(unsigned long currentMicros) {
_currentMicros = currentMicros; _currentMicros = currentMicros;
//if (_busy == true) return; //if (_busy == true) return;
if (_currentMicros - _cycleStartTime < _cycleTime) return;
_cycleStartTime = _currentMicros;
Task currentTask = getNextTask(); if ( hasTasks()){
if (currentTask.completed != true) { // Check if a task was found Task* currentTask = getTaskById(getNextTaskId());
if (currentTask == nullptr) return;
// Calculate CRC for response data if (!currentTask->rxMode) { // Check if a task was found
if (!currentTask.rxMode) { currentTask->crcPassFail = 0;
currentTask.crcPassFail = 0; uint16_t response_crc = crc16((uint8_t*)currentTask->commandArray, currentTask->byteCount-1);
uint16_t response_crc = crc16((uint8_t*)currentTask.commandArray, currentTask.byteCount-1);
if (_txPin != -1) digitalWrite(_txPin,HIGH); if (_txPin != -1) digitalWrite(_txPin,HIGH);
// Send response data with CRC // Send response data with CRC
_serial->write(0xFE); _serial->write(0xFE);
_serial->write(0xFE); _serial->write(0xFE);
_serial->write(response_crc >> 8); _serial->write(response_crc >> 8);
_serial->write(response_crc & 0xFF); _serial->write(response_crc & 0xFF);
_serial->write(currentTask.byteCount); _serial->write(currentTask->byteCount);
for (int i = 0; i < currentTask.byteCount; i++) { for (int i = 0; i < currentTask->byteCount; i++) {
_serial->write(currentTask.commandArray[i]); _serial->write(currentTask->commandArray[i]);
} }
_serial->write(0xFD); _serial->write(0xFD);
_serial->write(0xFD); _serial->write(0xFD);
_serial->flush(); _serial->flush();
if (_txPin != -1) digitalWrite(_txPin,LOW); if (_txPin != -1) digitalWrite(_txPin,LOW);
// delete task command after sending, for now // delete task command after sending, for now
markTaskCompleted(currentTask.taskID); currentTask->rxMode = true;
}
} else if (currentTask->rxMode) {
if (_serial->available() && currentTask->rxMode) {
uint16_t calculated_crc;
int byteCount = 100;
uint8_t byte_array[byteCount];
int curByte = _serial->read();
if (curByte == 0xFE && flagStart == false) flagStart = true;
else if ( curByte == 0xFE && flagStart == true) {
flagProc = false;
byteCounter = 0;
flagStarted = true;
flagStart = false;
flagEnded = false;
rxStart = true;
rxEnd = false;
crcPass = false;
memset(received_data, 0, ARRAY_SIZE);
}else if (flagStarted) {
crc[0] = curByte;
byteCounter++;
flagStarted = false;
} else if (byteCounter == 1) {
crc[1] = curByte;
received_crc = (crc[0] << 8) | crc[1];
byteCounter++;
} else if (byteCounter == 2) {
byteCount = curByte;
byteCounter++;
} else if (flagEnded == false && byteCounter >= 3) {
received_data[byteCounter-3] = curByte;
byteCounter++;
}
if (curByte == 0xFD && flagEnd == false) flagEnd = true;
else if ( curByte == 0xFD && flagEnd == true) {
flagEnded = true;
flagEnd = false;
rxEnd = true;
byteCount = byteCounter;
byteCounter = 0;
}
if (flagEnded) {
calculated_crc = crc16((uint8_t*)received_data, byteCount-6);
if (received_crc == calculated_crc) {
//DIAG(F("Loop CRC PASS"));
crcPass = true;
currentTask->crcPassFail = 1;
}else {
//DIAG(F("Loop CRC Fail %x %x"),received_crc,calculated_crc);
currentTask->processed = true;
if (_serial->available() && currentTask.rxMode) { currentTask->crcPassFail = -1;
}
flagEnded = false;
uint16_t calculated_crc;
int byteCount = 100;
uint8_t byte_array[byteCount];
int curByte = _serial->read();
if (curByte == 0xFE && flagStart == false) flagStart = true;
else if ( curByte == 0xFE && flagStart == true) {
flagProc = false;
byteCounter = 0;
flagStarted = true;
flagStart = false;
flagEnded = false;
rxStart = true;
rxEnd = false;
crcPass = false;
}else if (flagStarted) {
crc[0] = curByte;
byteCounter++;
flagStarted = false;
} else if (byteCounter == 1) {
crc[1] = curByte;
received_crc = (crc[0] << 8) | crc[1];
byteCounter++;
} else if (byteCounter == 2) {
byteCount = curByte;
byteCounter++;
} else if (flagEnded == false && byteCounter >= 3) {
received_data[byteCounter-3] = curByte;
byteCounter++;
}
if (curByte == 0xFD && flagEnd == false) flagEnd = true;
else if ( curByte == 0xFD && flagEnd == true) {
flagEnded = true;
flagEnd = false;
rxEnd = true;
byteCount = byteCounter;
byteCounter = 0;
}
if (flagEnded) {
calculated_crc = crc16((uint8_t*)received_data, byteCount-7);
if (received_crc == calculated_crc) {
DIAG(F("Loop CRC PASS"));
crcPass = true;
currentTask.crcPassFail = 1;
}else {
DIAG(F("Loop CRC Fail %x %x"),received_crc,calculated_crc);
currentTask.crcPassFail = -1;
}
flagEnded = false;
}
// Check CRC validity
if (crcPass) {
// Data received successfully, process it (e.g., print)
int nodeTo = received_data[0];
if (nodeTo == 0) { // for master. master does not retransmit, or a loop will runaway.
flagProc = true;
currentTask->gotCallback = true;
}
} else {
//DIAG(F("IO_RSproto: CRC Error!"));
}
} }
// Check CRC validity
if (crcPass) { // temp debug
// Data received successfully, process it (e.g., print)
if (flagProc) {
int nodeTo = received_data[0]; int nodeTo = received_data[0];
if (nodeTo == 0) { // for master. master does not retransmit, or a loop will runaway. int nodeFr = received_data[1];
flagProc = true; RSprotonode *node = findNode(nodeFr);
currentTask.gotCallback = true; //DIAG(F("Node from %i %i"), nodeFr, node->getNodeID());
int AddrCode = received_data[2];
//DIAG(F("From: %i, To: %i | %i %i %i %i %i"), nodeFr,nodeTo, received_data[3], received_data[4], received_data[5], received_data[6],received_data[7]);
//return;
} switch (AddrCode) {
case EXIOPINS:
} else { {node->setnumDigitalPins(received_data[3]);
//DIAG(F("IO_RSproto: CRC Error!")); node->setnumAnalogPins(received_data[4]);
}
}
// temp debug // See if we already have suitable buffers assigned
if (node->getnumDigialPins()>0) {
//end debug size_t digitalBytesNeeded = (node->getnumDigialPins() + 7) / 8;
if (node->getdigitalPinBytes() < digitalBytesNeeded) {
if (flagProc) { // Not enough space, free any existing buffer and allocate a new one
int nodeTo = received_data[0]; if (node->cleandigitalPinStates(digitalBytesNeeded)) {
int nodeFr = received_data[1]; node->setdigitalPinBytes(digitalBytesNeeded);
int AddrCode = received_data[2]; } else {
//DIAG(F("From: %i, To: %i | %i %i %i %i %i"), nodeFr,nodeTo, received_data[3], received_data[4], received_data[5], received_data[6],received_data[7]); DIAG(F("EX-IOExpander485 node:%d ERROR alloc %d bytes"), nodeFr, digitalBytesNeeded);
//return; //_deviceState = DEVSTATE_FAILED;
RSprotonode *node = findNode(nodeFr); node->setdigitalPinBytes(0);
switch (AddrCode) { }
case EXIOPINS:
{node->setnumDigitalPins(received_data[3]);
node->setnumAnalogPins(received_data[4]);
// See if we already have suitable buffers assigned
if (node->getnumDigialPins()>0) {
size_t digitalBytesNeeded = (node->getnumDigialPins() + 7) / 8;
if (node->getdigitalPinBytes() < digitalBytesNeeded) {
// Not enough space, free any existing buffer and allocate a new one
if (node->cleandigitalPinStates(digitalBytesNeeded)) {
node->setdigitalPinBytes(digitalBytesNeeded);
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc %d bytes"), nodeFr, digitalBytesNeeded);
//_deviceState = DEVSTATE_FAILED;
node->setdigitalPinBytes(0);
return;
} }
} }
}
if (node->getnumAnalogPins()>0) {
if (node->getnumAnalogPins()>0) { size_t analogueBytesNeeded = node->getnumAnalogPins() * 2;
size_t analogueBytesNeeded = node->getnumAnalogPins() * 2; if (node->getanalogPinBytes() < analogueBytesNeeded) {
if (node->getanalogPinBytes() < analogueBytesNeeded) { // Free any existing buffers and allocate new ones.
// Free any existing buffers and allocate new ones.
if (node->cleanAnalogStates(analogueBytesNeeded)) {
if (node->cleanAnalogStates(analogueBytesNeeded)) { node->setanalogPinBytes(analogueBytesNeeded);
node->setanalogPinBytes(analogueBytesNeeded); } else {
} else { DIAG(F("EX-IOExpander485 node:%d ERROR alloc analog pin bytes"), nodeFr);
DIAG(F("EX-IOExpander485 node:%d ERROR alloc analog pin bytes"), nodeFr); //_deviceState = DEVSTATE_FAILED;
//_deviceState = DEVSTATE_FAILED; node->setanalogPinBytes(0);
node->setanalogPinBytes(0); }
return;
} }
} }
currentTask->processed = true;
node->resFlag[currentTask->retFlag] = 1;
break;}
case EXIOINITA: {
for (int i = 0; i < node->getnumAnalogPins(); i++) {
node->setanalogPinMap(received_data[i+3], i);
}
currentTask->processed = true;
node->resFlag[currentTask->retFlag] = 1;
break;
} }
node->resFlag[currentTask.retFlag] = 1; case EXIOVER: {
break;} node->setMajVer(received_data[3]);
case EXIOINITA: { node->setMinVer(received_data[4]);
for (int i = 0; i < node->getnumAnalogPins(); i++) { node->setPatVer(received_data[5]);
node->setanalogPinMap(received_data[i+3], i); DIAG(F("EX-IOExpander485: Found node %i v%i.%i.%i"),nodeFr, node->getMajVer(), node->getMinVer(), node->getPatVer());
//if (!_currentNode->isInitialised()) {
//_currentNode->setInitialised();
//DIAG(F("EX-IOExpander485: Initialized Node:%d "), nodeFr);
//}
currentTask->processed = true;
node->resFlag[currentTask->retFlag] = 1;
break;
} }
node->resFlag[currentTask.retFlag] = 1; case EXIORDY: {
break; currentTask->processed = true;
} node->resFlag[currentTask->retFlag] = 1;
case EXIOVER: { break;
node->setMajVer(received_data[3]);
node->setMinVer(received_data[4]);
node->setPatVer(received_data[5]);
DIAG(F("EX-IOExpander485: Found node %i v%i.%i.%i"),node->getNodeID(), node->getMajVer(), node->getMinVer(), node->getPatVer());
node->resFlag[currentTask.retFlag] = 1;
break;
}
case EXIORDY: {
node->resFlag[currentTask.retFlag] = 1;
break;
}
case EXIOERR: {
node->resFlag[currentTask.retFlag] = -1;
break;
}
case EXIORDD: {
for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) {
node->setanalogInputStates(received_data[i+3], i);
} }
node->resFlag[currentTask.retFlag] = 1; case EXIOERR: {
break; currentTask->processed = true;
} node->resFlag[currentTask->retFlag] = -1;
case EXIORDAN: { DIAG(F("Some sort of error was received... WHAT DID YOU DO!"));
for (int i = 0; i < node->_numAnaloguePins; i++) { break;
node->setanalogInputBuffer(received_data[i+3], i); }
case EXIORDD: {
for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) {
node->setanalogInputStates(received_data[i+3], i);
}
currentTask->processed = true;
node->resFlag[currentTask->retFlag] = 1;
break;
}
case EXIORDAN: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->setanalogInputBuffer(received_data[i+3], i);
}
currentTask->processed = true;
node->resFlag[currentTask->retFlag] = 1;
break;
} }
node->resFlag[currentTask.retFlag] = 1;
break;
} }
} }
flagProc = false;
}
if (currentTask.gotCallback) {
}
}
if (currentTask->processed) {
markTaskCompleted(currentTask->taskID);
}
}
if (_currentMicros - _cycleStartTime >= _cycleTime/* && _currentNode->isInitialised()*/) {
_cycleStartTime = _currentMicros;
if (_currentNode == NULL) _currentNode = _nodeListStart;
RSproto *bus = RSproto::findBus(0);
uint8_t buffB[3];
buffB[0] = (_currentNode->getNodeID());
buffB[1] = (0);
buffB[2] = (EXIORDD);
bus->setBusy();
bus->addTask(buffB, 3, EXIORDD);
buffB[0] = (_currentNode->getNodeID());
buffB[1] = (0);
buffB[2] = (EXIORDD);
bus->setBusy();
bus->addTask(buffB, 3, EXIORDAN);
_currentNode = _currentNode->getNext();
//DIAG(F("Polling"));
} }
} }
@ -287,6 +321,7 @@ RSprotonode::RSprotonode(VPIN firstVpin, int nPins, uint8_t nodeID) {
_nPins = nPins; _nPins = nPins;
_busNo = 0; _busNo = 0;
_nodeID = nodeID; _nodeID = nodeID;
_initialised = false;
memset(resFlag, 0, 255); memset(resFlag, 0, 255);
//bus = bus->findBus(0); //bus = bus->findBus(0);
//_serial = bus->_serialD; //_serial = bus->_serialD;
@ -318,9 +353,8 @@ bool RSprotonode::_configure(VPIN vpin, ConfigTypeEnum configType, int paramCoun
buff[4] = (pullup); buff[4] = (pullup);
unsigned long startMillis = millis(); unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0); RSproto *bus = RSproto::findBus(0);
bus->_busy = true; bus->setBusy();
bus->addTask(bus->taskIDCntr++, buff, 5, EXIODPUP); bus->addTask(buff, 5, EXIODPUP);
bus->_busy = false;
return true; return true;
} }
@ -337,11 +371,10 @@ bool RSprotonode::_configure(VPIN vpin, ConfigTypeEnum configType, int paramCoun
buff[5] = lowByte(_firstVpin); buff[5] = lowByte(_firstVpin);
unsigned long startMillis = millis(); unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0); RSproto *bus = RSproto::findBus(0);
bus->_busy = true; bus->setBusy();
bus->addTask(bus->taskIDCntr++, buff, 6, EXIOENAN); bus->addTask(buff, 6, EXIOENAN);
bus->_busy = false;
return true; return false;
} }
void RSprotonode::_begin() { void RSprotonode::_begin() {
@ -354,28 +387,26 @@ void RSprotonode::_begin() {
buff[5] = ((_firstVpin >> 8)); buff[5] = ((_firstVpin >> 8));
unsigned long startMillis = millis(); unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0); RSproto *bus = RSproto::findBus(0);
bus->_busy = true; bus->initTask();
bus->addTask(bus->taskIDCntr++, buff, 6, EXIOINIT); bus->setBusy();
bus->_busy = false; bus->addTask(buff, 6, EXIOINIT);
buff[0] = (_nodeID); buff[0] = (_nodeID);
buff[1] = (0); buff[1] = (0);
buff[2] = (EXIOINITA); buff[2] = (EXIOINITA);
startMillis = millis(); startMillis = millis();
bus->_busy = true; bus->setBusy();
bus->addTask(bus->taskIDCntr++, buff, 3, EXIOINITA); bus->addTask(buff, 3, EXIOINITA);
bus->_busy = false;
buff[0] = (_nodeID); buff[0] = (_nodeID);
buff[1] = (0); buff[1] = (0);
buff[2] = (EXIOVER); buff[2] = (EXIOVER);
startMillis = millis(); startMillis = millis();
bus->_busy = true; bus->setBusy();
bus->addTask(bus->taskIDCntr++, buff, 3, EXIOVER); bus->addTask(buff, 3, EXIOVER);
bus->_busy = false;
setInitialised();
#ifdef DIAG_IO #ifdef DIAG_IO
_display(); _display();
#endif #endif
@ -399,7 +430,8 @@ void RSprotonode::_write(VPIN vpin, int value) {
buff[4] = (value); buff[4] = (value);
unsigned long startMillis = millis(); unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0); RSproto *bus = RSproto::findBus(0);
bus->addTask(bus->taskIDCntr++, buff, 5, EXIOWRD); bus->setBusy();
bus->addTask(buff, 5, EXIOWRD);
} }
@ -430,6 +462,7 @@ void RSprotonode::_write(VPIN vpin, int value) {
buff[8] = lowByte(duration); buff[8] = lowByte(duration);
unsigned long startMillis = millis(); unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0); RSproto *bus = RSproto::findBus(0);
bus->addTask(bus->taskIDCntr++, buff, 9, EXIOWRAN); bus->setBusy();
bus->addTask(buff, 9, EXIOWRAN);
} }

View File

@ -93,7 +93,7 @@ private:
uint8_t _nodeID; uint8_t _nodeID;
char _type; char _type;
RSprotonode *_next = NULL; RSprotonode *_next = NULL;
bool _initialised = false; bool _initialised;
RSproto *bus; RSproto *bus;
HardwareSerial* _serial; HardwareSerial* _serial;
enum { enum {
@ -286,7 +286,7 @@ private:
int _operationCount = 0; int _operationCount = 0;
int _refreshOperation = 0; int _refreshOperation = 0;
byte bufferLength; byte bufferLength;
static const int ARRAY_SIZE = 254; static const int ARRAY_SIZE = 75;
int buffer[ARRAY_SIZE]; int buffer[ARRAY_SIZE];
byte inCommandPayload; byte inCommandPayload;
static RSproto *_busList; // linked list of defined bus instances static RSproto *_busList; // linked list of defined bus instances
@ -329,42 +329,82 @@ struct Task {
bool gotCallback; bool gotCallback;
bool rxMode; bool rxMode;
int crcPassFail; int crcPassFail;
bool completed = false; bool completed;
bool processed;
}; };
static const int MAX_TASKS = 100;
int taskIDCntr = 0; int taskIDCntr = 0;
Task taskBuffer[100]; // Buffer to hold up to 100 tasks Task taskBuffer[MAX_TASKS]; // Buffer to hold up to 100 tasks
int taskCount = 0; int currentTaskIndex = 0;
void addTask(int id, const uint8_t* cmd, int byteCount, uint8_t retFlag, bool gotCallBack=false, bool rxMode=false, int crcPassFail=0) { void initTask() {
if (taskCount < 100) { // Check if buffer is not full for (int i = 0; i <MAX_TASKS; i++) {
taskBuffer[taskCount].taskID = id; taskBuffer[i].completed = true;
memcpy(taskBuffer[taskCount].commandArray, cmd, ARRAY_SIZE); taskBuffer[i].processed = false;
taskBuffer[taskCount].commandArray[ARRAY_SIZE] = 0; // Ensure null-termination taskBuffer[i].byteCount = 0;
taskBuffer[taskCount].byteCount = byteCount; taskBuffer[i].crcPassFail = 0;
taskBuffer[taskCount].retFlag = retFlag; taskBuffer[i].gotCallback = false;
taskBuffer[taskCount].gotCallback = false; taskBuffer[i].retFlag = 0;
taskBuffer[taskCount].rxMode = false; taskBuffer[i].rxMode = false;
taskBuffer[taskCount].crcPassFail = 0; taskBuffer[i].taskID = i;
taskBuffer[taskCount].completed = false; memset(taskBuffer[i].commandArray,0,ARRAY_SIZE);
taskCount++;
} else {
Serial.println("Task buffer overflow!");
} }
} }
Task getNextTask() { void addTask(const uint8_t* cmd, int byteCount, uint8_t retFlag) {
for (int i = 0; i < taskCount; i++) { // Find an empty slot in the buffer
if (!taskBuffer[i].completed) { int emptySlot = -1;
return taskBuffer[i]; for (int i = 0; i < MAX_TASKS; i++) {
if (taskBuffer[i].completed) {
emptySlot = i;
break;
} }
} }
// Return a default task if no uncompleted tasks found // If no empty slot found, return (buffer full)
Task emptyTask; if (emptySlot == -1) {
return emptyTask; DIAG(F("Task Buffer Full!"));
return;
}
for (int i = 0; i < ARRAY_SIZE; i++) taskBuffer[emptySlot].commandArray[i] = cmd[i];
taskBuffer[emptySlot].byteCount = byteCount;
taskBuffer[emptySlot].retFlag = retFlag;
taskBuffer[emptySlot].rxMode = false;
taskBuffer[emptySlot].crcPassFail = 0;
taskBuffer[emptySlot].gotCallback = false;
taskBuffer[emptySlot].completed = false;
taskBuffer[emptySlot].processed = false;
currentTaskIndex = emptySlot;
} }
void markTaskCompleted(int taskID) { bool hasTasks() {
for (int i = 0; i < taskCount; i++) { for (int i = 0; i < MAX_TASKS; i++) {
if (taskBuffer[i].taskID == taskID) { if (!taskBuffer[i].completed) {
return true; // At least one task is not completed
}
}
return false; // All tasks are completed
}
// Function to get a specific task by ID
Task* getTaskById(int id) {
for (int i = 0; i < MAX_TASKS; i++) {
if (taskBuffer[i].taskID == id) {
return &taskBuffer[i]; // Return a pointer to the task
}
}
return nullptr; // Task not found
}
// Function to get the next task (optional)
int getNextTaskId() {
for (int i = 0; i < MAX_TASKS; i++) {
if (!taskBuffer[i].completed) {
return taskBuffer[i].taskID;
}
}
return -1; // No tasks available
}
// Function to mark a task as completed
void markTaskCompleted(int id) {
for (int i = 0; i < MAX_TASKS; i++) {
if (taskBuffer[i].taskID == id) {
taskBuffer[i].completed = true; taskBuffer[i].completed = true;
break; break;
} }
} }
} }
@ -408,6 +448,15 @@ uint16_t crc16(uint8_t *data, uint16_t length);
uint16_t _pin; uint16_t _pin;
int8_t _txPin; int8_t _txPin;
bool _busy = false; bool _busy = false;
void setBusy() {
_busy = true;
}
void clearBusy() {
_busy = false;
}
bool getBusy() {
return _busy;
}
unsigned long _baud; unsigned long _baud;
int taskCnt = 0; int taskCnt = 0;
uint8_t initBuffer[1] = {0xFE}; uint8_t initBuffer[1] = {0xFE};
@ -418,6 +467,7 @@ uint16_t crc16(uint8_t *data, uint16_t length);
if (_txPin >0) { if (_txPin >0) {
pinMode(_txPin, OUTPUT); pinMode(_txPin, OUTPUT);
digitalWrite(_txPin, LOW); digitalWrite(_txPin, LOW);
} }
#if defined(RSproto_STM_OK) #if defined(RSproto_STM_OK)
pinMode(RSproto_STM_OK, OUTPUT); pinMode(RSproto_STM_OK, OUTPUT);