diff --git a/IO_EXIO485.cpp b/IO_EXIO485.cpp index ec4a96e..0c0b4ac 100644 --- a/IO_EXIO485.cpp +++ b/IO_EXIO485.cpp @@ -1,6 +1,5 @@ /* * © 2024, Travis Farmer. All rights reserved. - * © 2021 Chris Harlow * * This file is part of DCC++EX API * @@ -48,14 +47,7 @@ EXIO485::EXIO485(uint8_t busNo, HardwareSerial &serial, unsigned long baud, int8 _busList = this; } -/* -= _loop =- -// -// Main loop function for EXIO485. -// Work through list of nodes. For each node, in separate loop entries -// When the slot time has finished, move on to the next device. -*/ - -// CRC-16 implementation (replace with your preferred CRC library if needed) +// CRC-16 implementation uint16_t EXIO485::crc16(uint8_t *data, uint16_t length) { uint16_t crc = 0xFFFF; for (uint16_t i = 0; i < length; i++) { @@ -71,10 +63,18 @@ uint16_t EXIO485::crc16(uint8_t *data, uint16_t length) { return crc; } + +/* -= _loop =- +// +// Main loop function for EXIO485. +// Work through list of nodes. For each node, in separate loop entries +// When the slot time has finished, move on to the next device. +*/ + void EXIO485::_loop(unsigned long currentMicros) { _currentMicros = currentMicros; if (_currentNode == NULL) _currentNode = _nodeListStart; - if (!hasTasks() && _currentNode->isInitialised()) { + if (!hasTasks() && _currentNode->isInitialised()) { // no tasks? lets poll for data uint8_t buffA[3]; buffA[0] = (_currentNode->getNodeID()); buffA[1] = (0); @@ -86,24 +86,19 @@ void EXIO485::_loop(unsigned long currentMicros) { buffB[2] = (EXIORDAN); addTask(buffB, 3, EXIORDAN); _currentNode = _currentNode->getNext(); - //DIAG(F("Polling")); } - if ( hasTasks()){ + if ( hasTasks()){ // do we have any tasks on the docket _cycleStartTimeA = _currentMicros; if (CurrentTaskID == -1) CurrentTaskID = getNextTaskId(); Task* currentTask = getTaskById(CurrentTaskID); - //if (currentTask == nullptr) return; - - - if (!currentTask->rxMode) { // Check if a task was found + if (!currentTask->rxMode) { currentTask->crcPassFail = 0; uint16_t response_crc = crc16((uint8_t*)currentTask->commandArray, currentTask->byteCount-1); - //delayUntil(_currentMicros+10000UL); - ArduinoPins::fastWriteDigital(_txPin,HIGH); + if (_txPin != -1) ArduinoPins::fastWriteDigital(_txPin,HIGH); // Send response data with CRC _serial->write(0xFE); _serial->write(0xFE); @@ -116,10 +111,9 @@ void EXIO485::_loop(unsigned long currentMicros) { _serial->write(0xFD); _serial->write(0xFD); _serial->flush(); - ArduinoPins::fastWriteDigital(_txPin,LOW); + if (_txPin != -1) ArduinoPins::fastWriteDigital(_txPin,LOW); // delete task command after sending, for now currentTask->rxMode = true; - //DIAG(F("Task %d"), currentTask->taskID); } else { if ( _serial->available()) { @@ -165,18 +159,15 @@ void EXIO485::_loop(unsigned long currentMicros) { crcPass = true; } 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. + if (nodeTo == 0) { // for master. flagProc = true; } - } if (flagProc) { @@ -259,19 +250,15 @@ void EXIO485::_loop(unsigned long currentMicros) { break; } case EXIORDD: { - for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) { - node->setdigitalInputStates(received_data[i+3], i); - } - markTaskCompleted(CurrentTaskID); - flagProc = false; + for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) { + node->setdigitalInputStates(received_data[i+3], i); + } + markTaskCompleted(CurrentTaskID); + flagProc = false; break; } } - - } - - } } } diff --git a/IO_EXIO485.h b/IO_EXIO485.h index 6c3c958..8d52e28 100644 --- a/IO_EXIO485.h +++ b/IO_EXIO485.h @@ -1,6 +1,5 @@ /* * © 2024, Travis Farmer. All rights reserved. -* © 2021 Chris Harlow * * This file is part of DCC++EX API * @@ -39,7 +38,7 @@ * * firstVPIN = first vpin in block allocated to this device * numVPINs = number of vpins - * nodeID = 1-251 + * nodeID = 1-252 */ #ifndef IO_EXIO485_H @@ -382,7 +381,7 @@ private: byte bufferLength; static const int ARRAY_SIZE = 150; int buffer[ARRAY_SIZE]; - byte inCommandPayload; + byte inCommandPayload; static EXIO485 *_busList; // linked list of defined bus instances bool waitReceive = false; int _waitCounter = 0; @@ -406,12 +405,6 @@ private: uint16_t _receiveDataIndex = 0; // Index of next data byte to be received. EXIO485 *_nextBus = NULL; // Pointer to next bus instance in list. -// Helper function for error handling - void reportError(uint8_t status, bool fail=true) { - DIAG(F("EX-IOExpander485 Node:%d Error"), _currentNode->getNodeID()); - if (fail) - _deviceState = DEVSTATE_FAILED; - } int byteCounter = 0; public: struct Task { @@ -426,103 +419,91 @@ struct Task { bool completed; bool processed; }; -static const int MAX_TASKS = 50; + static const int MAX_TASKS = 50; long taskIDCntr = 1; long CurrentTaskID = -1; int taskResendCount = 0; -Task taskBuffer[MAX_TASKS]; // Buffer to hold up to 100 tasks -int currentTaskIndex = 0; -void initTask() { - for (int i = 0; i = 5000000) taskIDCntr = 1; + taskBuffer[emptySlot].taskID = taskIDCntr; + currentTaskIndex = emptySlot; } -} -void addTask(const uint8_t* cmd, int byteCount, uint8_t retFlag) { - // Find an empty slot in the buffer - int emptySlot = -1; - for (int i = 0; i < MAX_TASKS; i++) { - if (taskBuffer[i].completed) { - emptySlot = i; - break; + bool hasTasks() { + for (int i = 0; i < MAX_TASKS; i++) { + 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) + long 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; // completed + taskBuffer[i].taskID = -1; // unassigned + CurrentTaskID = getNextTaskId(); + break; + } } } - // If no empty slot found, return (buffer full) - if (emptySlot == -1) { - DIAG(F("Task Buffer Full!")); - return; - } - for (int i = 0; i < byteCount; 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; - taskIDCntr++; - if (taskIDCntr >= 5000000) taskIDCntr = 1; - taskBuffer[emptySlot].taskID = taskIDCntr; - currentTaskIndex = emptySlot; -} -bool hasTasks() { - for (int i = 0; i < MAX_TASKS; i++) { - 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) -long 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; // completed - taskBuffer[i].taskID = -1; // unassigned - CurrentTaskID = getNextTaskId(); - break; - } - } -} -bool flagEnd = false; -bool flagEnded = false; -bool flagStart = false; -bool flagStarted = false; -bool rxStart = false; -bool rxEnd = false; -bool crcPass = false; -bool flagProc = false; -uint16_t calculated_crc; - int byteCount = 100; -uint8_t received_data[ARRAY_SIZE]; -uint16_t received_crc; -uint8_t crc[2]; -uint16_t crc16(uint8_t *data, uint16_t length); + bool flagEnd = false; + bool flagEnded = false; + bool flagStart = false; + bool flagStarted = false; + bool rxStart = false; + bool rxEnd = false; + bool crcPass = false; + bool flagProc = false; + uint16_t calculated_crc; + int byteCount = 100; + uint8_t received_data[ARRAY_SIZE]; + uint16_t received_crc; + uint8_t crc[2]; + uint16_t crc16(uint8_t *data, uint16_t length); // EX-IOExpander protocol flags enum { @@ -567,25 +548,12 @@ uint16_t crc16(uint8_t *data, uint16_t length); unsigned long taskCounter=0ul; // Device-specific initialisation void _begin() override { - //initTask(); _serial->begin(_baud, SERIAL_8N1); if (_txPin >0) { pinMode(_txPin, OUTPUT); digitalWrite(_txPin, LOW); } - #if defined(EXIO485_STM_OK) - pinMode(EXIO485_STM_OK, OUTPUT); - ArduinoPins::fastWriteDigital(EXIO485_STM_OK,LOW); - #endif - #if defined(EXIO485_STM_FAIL) - pinMode(EXIO485_STM_FAIL, OUTPUT); - ArduinoPins::fastWriteDigital(EXIO485_STM_FAIL,LOW); - #endif - #if defined(EXIO485_STM_COMM) - pinMode(EXIO485_STM_COMM, OUTPUT); - ArduinoPins::fastWriteDigital(EXIO485_STM_COMM,LOW); - #endif #if defined(DIAG_IO) _display();