1
0
mirror of https://github.com/DCC-EX/CommandStation-EX.git synced 2025-04-21 12:31:19 +02:00
This commit is contained in:
travis-farmer 2024-12-28 02:40:50 -05:00
parent 25c01e0ca4
commit 495c9407a8
No known key found for this signature in database
GPG Key ID: 0BC296791D14CB35
2 changed files with 117 additions and 121 deletions

View File

@ -75,7 +75,6 @@ void EXIO485::_loop(unsigned long currentMicros) {
_currentMicros = currentMicros; _currentMicros = currentMicros;
if (_currentNode == NULL) _currentNode = _nodeListStart; if (_currentNode == NULL) _currentNode = _nodeListStart;
if (!hasTasks() && _currentNode->isInitialised()) { if (!hasTasks() && _currentNode->isInitialised()) {
_cycleStartTime = _currentMicros;
uint8_t buffA[3]; uint8_t buffA[3];
buffA[0] = (_currentNode->getNodeID()); buffA[0] = (_currentNode->getNodeID());
buffA[1] = (0); buffA[1] = (0);
@ -87,38 +86,24 @@ void EXIO485::_loop(unsigned long currentMicros) {
buffB[2] = (EXIORDAN); buffB[2] = (EXIORDAN);
addTask(buffB, 3, EXIORDAN); addTask(buffB, 3, EXIORDAN);
_currentNode = _currentNode->getNext(); _currentNode = _currentNode->getNext();
DIAG(F("Polling")); //DIAG(F("Polling"));
} }
if ( hasTasks()){ if ( hasTasks()){
_cycleStartTimeA = _currentMicros; _cycleStartTimeA = _currentMicros;
if (CurrentTaskID == -1) { if (CurrentTaskID == -1) CurrentTaskID = getNextTaskId();
CurrentTaskID = getNextTaskId();
}
Task* currentTask = getTaskById(CurrentTaskID); Task* currentTask = getTaskById(CurrentTaskID);
if (_currentMicros - _cycleStartTime > 1000000UL) { // timout every 1000ms //if (currentTask == nullptr) return;
_cycleStartTime = _currentMicros;// reset timout
if (taskResendCount >= 2) { // max resends
markTaskCompleted(CurrentTaskID); // kill task and move on
CurrentTaskID = getNextTaskId(); // move on
taskResendCount = 0;
DIAG(F("Move on"));
} else {
currentTask->rxMode = false; // resend
taskResendCount++;
DIAG(F("Resend"));
}
}
if (!currentTask->rxMode) { // Check if a task was found if (!currentTask->rxMode) { // Check if a task was found
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); //delayUntil(_currentMicros+10000UL);
ArduinoPins::fastWriteDigital(_txPin,HIGH);
// Send response data with CRC // Send response data with CRC
_serial->write(0xFE); _serial->write(0xFE);
_serial->write(0xFE); _serial->write(0xFE);
@ -131,18 +116,13 @@ void EXIO485::_loop(unsigned long currentMicros) {
_serial->write(0xFD); _serial->write(0xFD);
_serial->write(0xFD); _serial->write(0xFD);
_serial->flush(); _serial->flush();
if (_txPin != -1) digitalWrite(_txPin,LOW); ArduinoPins::fastWriteDigital(_txPin,LOW);
// delete task command after sending, for now // delete task command after sending, for now
currentTask->rxMode = true; currentTask->rxMode = true;
DIAG(F("Task")); //DIAG(F("Task %d"), currentTask->taskID);
} else { } else {
if ( _serial->available()) { if ( _serial->available()) {
uint16_t calculated_crc;
int byteCount = 100;
int curByte = _serial->read(); int curByte = _serial->read();
if (curByte == 0xFE && flagStart == false) flagStart = true; if (curByte == 0xFE && flagStart == false) flagStart = true;
@ -188,99 +168,110 @@ void EXIO485::_loop(unsigned long currentMicros) {
} }
// Check CRC validity }
if (crcPass) { // Check CRC validity
// Data received successfully, process it (e.g., print) if (crcPass) {
int nodeTo = received_data[0]; // Data received successfully, process it (e.g., print)
if (nodeTo == 0) { // for master. master does not retransmit, or a loop will runaway. int nodeTo = received_data[0];
flagProc = true; if (nodeTo == 0) { // for master. master does not retransmit, or a loop will runaway.
} flagProc = true;
} }
if (flagProc) { }
int nodeFr = received_data[1];
EXIO485node *node = findNode(nodeFr);
int AddrCode = received_data[2];
switch (AddrCode) { if (flagProc) {
case EXIOPINS: crcPass = false;
{node->setnumDigitalPins(received_data[3]); int nodeFr = received_data[1];
node->setnumAnalogPins(received_data[4]); EXIO485node *node = findNode(nodeFr);
int AddrCode = received_data[2];
// See if we already have suitable buffers assigned switch (AddrCode) {
if (node->getnumDigialPins()>0) { case EXIOPINS:
size_t digitalBytesNeeded = (node->getnumDigialPins() + 7) / 8; {node->setnumDigitalPins(received_data[3]);
if (node->getdigitalPinBytes() < digitalBytesNeeded) { node->setnumAnalogPins(received_data[4]);
// Not enough space, free any existing buffer and allocate a new one
if (node->cleandigitalPinStates(digitalBytesNeeded)) { // See if we already have suitable buffers assigned
node->setdigitalPinBytes(digitalBytesNeeded); if (node->getnumDigialPins()>0) {
} else { size_t digitalBytesNeeded = (node->getnumDigialPins() + 7) / 8;
DIAG(F("EX-IOExpander485 node:%d ERROR alloc %d bytes"), nodeFr, digitalBytesNeeded); if (node->getdigitalPinBytes() < digitalBytesNeeded) {
node->setdigitalPinBytes(0); // 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);
node->setdigitalPinBytes(0);
} }
} }
}
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);
node->setanalogPinBytes(0); node->setanalogPinBytes(0);
}
} }
} }
markTaskCompleted(currentTask->taskID);
break;}
case EXIOINITA: {
for (int i = 0; i < node->getnumAnalogPins(); i++) {
node->setanalogPinMap(received_data[i+3], i);
}
markTaskCompleted(currentTask->taskID);
break;
} }
case EXIOVER: { markTaskCompleted(CurrentTaskID);
node->setMajVer(received_data[3]); flagProc = false;
node->setMinVer(received_data[4]); break;}
node->setPatVer(received_data[5]); case EXIOINITA: {
DIAG(F("EX-IOExpander485: Found node %i v%i.%i.%i"),node->getNodeID(), node->getMajVer(), node->getMinVer(), node->getPatVer()); for (int i = 0; i < node->getnumAnalogPins(); i++) {
node->setInitialised(); node->setanalogPinMap(received_data[i+3], i);
markTaskCompleted(currentTask->taskID);
break;
} }
case EXIORDY: {
markTaskCompleted(currentTask->taskID); markTaskCompleted(CurrentTaskID);
break; flagProc = false;
}
case EXIOERR: {
markTaskCompleted(currentTask->taskID);
DIAG(F("EX-IOExplorer485: Some sort of error was received...")); // ;-)
break;
}
case EXIORDAN: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->setanalogInputBuffer(received_data[i+3], i);
}
markTaskCompleted(currentTask->taskID);
break;
}
case EXIORDD: {
for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) {
node->setdigitalInputStates(received_data[i+3], i);
}
markTaskCompleted(currentTask->taskID);
break; break;
} }
case EXIOVER: {
node->setMajVer(received_data[3]);
node->setMinVer(received_data[4]);
node->setPatVer(received_data[5]);
DIAG(F("EX-IOExpander485: Found node %d v%d.%d.%d"),node->getNodeID(), node->getMajVer(), node->getMinVer(), node->getPatVer());
node->setInitialised();
markTaskCompleted(CurrentTaskID);
flagProc = false;
break;
}
case EXIORDY: {
markTaskCompleted(CurrentTaskID);
flagProc = false;
break;
}
case EXIOERR: {
markTaskCompleted(CurrentTaskID);
DIAG(F("EX-IOExplorer485: Some sort of error was received...")); // ;-)
flagProc = false;
break;
}
case EXIORDAN: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->setanalogInputBuffer(received_data[i+3], i);
}
markTaskCompleted(CurrentTaskID);
flagProc = false;
break;
}
case EXIORDD: {
for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) {
node->setdigitalInputStates(received_data[i+3], i);
}
markTaskCompleted(CurrentTaskID);
flagProc = false;
break;
} }
} }
flagProc = false;
} }
} }
} }
} }
@ -362,7 +353,6 @@ void EXIO485node::_begin() {
buff[4] = ((_firstVpin & 0xFF)); buff[4] = ((_firstVpin & 0xFF));
buff[5] = ((_firstVpin >> 8)); buff[5] = ((_firstVpin >> 8));
EXIO485 *bus = EXIO485::findBus(0); EXIO485 *bus = EXIO485::findBus(0);
bus->initTask();
bus->setBusy(); bus->setBusy();
bus->addTask(buff, 6, EXIOINIT); bus->addTask(buff, 6, EXIOINIT);

View File

@ -22,13 +22,13 @@
* EXIO485 * EXIO485
* ======= * =======
* To define a EXIO485, example syntax: * To define a EXIO485, example syntax:
* EXIO485::create(busNo, serial, baud[, pin]); * EXIO485::create(busNo, serial, baud[, TxPin]);
* *
* busNo = the Bus no of the instance. should = 0, unless more than one bus configured for some reason. * busNo = the Bus no of the instance. should = 0, unless more than one bus configured for some reason.
* serial = serial port to be used (e.g. Serial3) * serial = serial port to be used (e.g. Serial3)
* baud = baud rate (9600, 19200, 28800, 57600 or 115200) * baud = baud rate (9600, 19200, 28800, 57600 or 115200)
* cycletime = minimum time between successive updates/reads of a node in millisecs (default 500ms) * cycletime = minimum time between successive updates/reads of a node in millisecs (default 500ms)
* pin = pin number connected to EXIO485 module's DE and !RE terminals for half-duplex operation (default -1) * TxPin = pin number connected to EXIO485 module's DE and !RE terminals for half-duplex operation (default -1)
* if omitted (default), hardware MUST support full-duplex opperation! * if omitted (default), hardware MUST support full-duplex opperation!
* *
* *
@ -416,7 +416,7 @@ private:
public: public:
struct Task { struct Task {
static const int ARRAY_SIZE = 150; static const int ARRAY_SIZE = 150;
int taskID; long taskID;
uint8_t commandArray[ARRAY_SIZE]; uint8_t commandArray[ARRAY_SIZE];
int byteCount; int byteCount;
uint8_t retFlag; uint8_t retFlag;
@ -427,8 +427,8 @@ struct Task {
bool processed; bool processed;
}; };
static const int MAX_TASKS = 50; static const int MAX_TASKS = 50;
int taskIDCntr = 0; long taskIDCntr = 1;
int CurrentTaskID = -1; long CurrentTaskID = -1;
int taskResendCount = 0; int taskResendCount = 0;
Task taskBuffer[MAX_TASKS]; // Buffer to hold up to 100 tasks Task taskBuffer[MAX_TASKS]; // Buffer to hold up to 100 tasks
int currentTaskIndex = 0; int currentTaskIndex = 0;
@ -467,6 +467,9 @@ void addTask(const uint8_t* cmd, int byteCount, uint8_t retFlag) {
taskBuffer[emptySlot].gotCallback = false; taskBuffer[emptySlot].gotCallback = false;
taskBuffer[emptySlot].completed = false; taskBuffer[emptySlot].completed = false;
taskBuffer[emptySlot].processed = false; taskBuffer[emptySlot].processed = false;
taskIDCntr++;
if (taskIDCntr >= 5000000) taskIDCntr = 1;
taskBuffer[emptySlot].taskID = taskIDCntr;
currentTaskIndex = emptySlot; currentTaskIndex = emptySlot;
} }
bool hasTasks() { bool hasTasks() {
@ -487,7 +490,7 @@ Task* getTaskById(int id) {
return nullptr; // Task not found return nullptr; // Task not found
} }
// Function to get the next task (optional) // Function to get the next task (optional)
int getNextTaskId() { long getNextTaskId() {
for (int i = 0; i < MAX_TASKS; i++) { for (int i = 0; i < MAX_TASKS; i++) {
if (!taskBuffer[i].completed) { if (!taskBuffer[i].completed) {
return taskBuffer[i].taskID; return taskBuffer[i].taskID;
@ -499,7 +502,9 @@ int getNextTaskId() {
void markTaskCompleted(int id) { void markTaskCompleted(int id) {
for (int i = 0; i < MAX_TASKS; i++) { for (int i = 0; i < MAX_TASKS; i++) {
if (taskBuffer[i].taskID == id) { if (taskBuffer[i].taskID == id) {
taskBuffer[i].completed = true; taskBuffer[i].completed = true; // completed
taskBuffer[i].taskID = -1; // unassigned
CurrentTaskID = getNextTaskId();
break; break;
} }
} }
@ -512,13 +517,13 @@ bool rxStart = false;
bool rxEnd = false; bool rxEnd = false;
bool crcPass = false; bool crcPass = false;
bool flagProc = false; bool flagProc = false;
uint16_t calculated_crc;
int byteCount = 100;
uint8_t received_data[ARRAY_SIZE]; uint8_t received_data[ARRAY_SIZE];
uint16_t received_crc; uint16_t received_crc;
uint8_t crc[2]; uint8_t crc[2];
uint16_t crc16(uint8_t *data, uint16_t length); uint16_t crc16(uint8_t *data, uint16_t length);
void remove_nulls(char *str, int len);
int getCharsLeft(char *str, char position);
void parseRx(uint8_t * outArray, uint8_t retFlag);
// EX-IOExpander protocol flags // EX-IOExpander protocol flags
enum { enum {
EXIOINIT = 0xE0, // Flag to initialise setup procedure EXIOINIT = 0xE0, // Flag to initialise setup procedure
@ -562,6 +567,7 @@ uint16_t crc16(uint8_t *data, uint16_t length);
unsigned long taskCounter=0ul; unsigned long taskCounter=0ul;
// Device-specific initialisation // Device-specific initialisation
void _begin() override { void _begin() override {
//initTask();
_serial->begin(_baud, SERIAL_8N1); _serial->begin(_baud, SERIAL_8N1);
if (_txPin >0) { if (_txPin >0) {
pinMode(_txPin, OUTPUT); pinMode(_txPin, OUTPUT);