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

save current

This commit is contained in:
travis-farmer 2024-12-22 05:20:25 -05:00
parent d892c27f3f
commit c151b52114
No known key found for this signature in database
GPG Key ID: 0BC296791D14CB35
2 changed files with 328 additions and 622 deletions

View File

@ -25,159 +25,6 @@ static const byte PAYLOAD_FALSE = 0;
static const byte PAYLOAD_NORMAL = 1;
static const byte PAYLOAD_STRING = 2;
taskBuffer * taskBuffer::first=NULL;
taskBuffer::taskBuffer(unsigned long taskID, uint8_t *commandBuffer, int byteCount, uint8_t retFlag)
{
_taskID = taskID;
_byteCount = byteCount;
_retFlag = retFlag;
memset(commandArray, 0, byteCount);
memcpy(commandArray, commandBuffer, byteCount);
next=first;
first=this;
RSproto *bus = RSproto::findBus(0);
if (bus != NULL) {
bus->addTask(this);
return;
}
}
taskBuffer::~taskBuffer()
{
// destructor
}
void RSproto::remove_nulls(char *str, int len) {
int i, j = 0;
for (i = 0; i<len; i++) {
if (str[i] != '\0') {
str[j++] = str[i];
}
}
str[j] = '\0'; // Ensure the string is null-terminated
}
int RSproto::getCharsLeft(char *str, char position) {
int pos;
char result[25];
memset(result, '\0', 25);
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == position) {
pos = i;
break; // Exit the loop once the character is found
}
}
if (pos >= 0 && pos < strlen(str)) {
for (int i = 0; i < strlen(str); i++) {
if (i < pos) result[i] = str[i];
}
}
if (result != NULL) return atoi(result);
else return 0;
}
void taskBuffer::doCommand(unsigned long taskID, uint8_t *commandBuffer, int byteCount, uint8_t retFlag) {
// add commands here to be sent
new taskBuffer(taskID, commandBuffer, byteCount, retFlag);
}
void RSproto::parseRx(uint8_t * outArray, uint8_t retFlag) {
int nodeTo = outArray[0];
int nodeFr = outArray[1];
int AddrCode = outArray[2];
DIAG(F("From: %i, To: %i | %i %i %i %i %i"), nodeFr,nodeTo, outArray[3], outArray[4], outArray[5], outArray[6],outArray[7]);
return;
RSprotonode *node = findNode(nodeFr);
switch (AddrCode) {
case EXIOPINS:
{node->_numDigitalPins = outArray[3];
node->_numAnaloguePins = outArray[4];
// See if we already have suitable buffers assigned
if (node->_numDigitalPins>0) {
size_t digitalBytesNeeded = (node->_numDigitalPins + 7) / 8;
if (node->_digitalPinBytes < digitalBytesNeeded) {
// Not enough space, free any existing buffer and allocate a new one
if (node->_digitalPinBytes > 0) free(node->_digitalInputStates);
if ((node->_digitalInputStates = (byte*) calloc(digitalBytesNeeded, 1)) != NULL) {
node->_digitalPinBytes = digitalBytesNeeded;
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc %d bytes"), nodeFr, digitalBytesNeeded);
//_deviceState = DEVSTATE_FAILED;
node->_digitalPinBytes = 0;
return;
}
}
}
if (node->_numAnaloguePins>0) {
size_t analogueBytesNeeded = node->_numAnaloguePins * 2;
if (node->_analoguePinBytes < analogueBytesNeeded) {
// Free any existing buffers and allocate new ones.
if (node->_analoguePinBytes > 0) {
free(node->_analogueInputBuffer);
free(node->_analogueInputStates);
free(node->_analoguePinMap);
}
node->_analogueInputStates = (uint8_t*) calloc(analogueBytesNeeded, 1);
node->_analogueInputBuffer = (uint8_t*) calloc(analogueBytesNeeded, 1);
node->_analoguePinMap = (uint8_t*) calloc(node->_numAnaloguePins, 1);
if (node->_analogueInputStates != NULL &&
node->_analogueInputBuffer != NULL &&
node->_analoguePinMap != NULL) {
node->_analoguePinBytes = analogueBytesNeeded;
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc analog pin bytes"), nodeFr);
//_deviceState = DEVSTATE_FAILED;
node->_analoguePinBytes = 0;
return;
}
}
}
node->resFlag[retFlag] = 1;
break;}
case EXIOINITA: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->_analoguePinMap[i] = outArray[i+3];
}
node->resFlag[retFlag] = 1;
break;
}
case EXIOVER: {
node->_majorVer = outArray[3];
node->_minorVer = outArray[4];
node->_patchVer = outArray[5];
node->resFlag[retFlag] = 1;
break;
}
case EXIORDY: {
node->resFlag[retFlag] = 1;
break;
}
case EXIOERR: {
node->resFlag[retFlag] = -1;
break;
}
case EXIORDD: {
for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) {
node->_digitalInputStates[i] = outArray[i+3];
}
node->resFlag[retFlag] = 1;
break;
}
case EXIORDAN: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->_analogueInputBuffer[i] = outArray[i+3];
}
node->resFlag[retFlag] = 1;
break;
}
}
}
/************************************************************
* RSproto implementation
@ -224,225 +71,38 @@ uint16_t RSproto::crc16(uint8_t *data, uint16_t length) {
return crc;
}
void RSproto::sendInstantCommand(uint8_t *buf, int byteCount, uint8_t retFlag) {
// Calculate CRC for response data
uint16_t response_crc = crc16((uint8_t*)buf, byteCount-1);
if (_txPin != -1) digitalWrite(_txPin,HIGH);
// Send response data with CRC
_serial->write(0xFE);
_serial->write(0xFE);
_serial->write(response_crc >> 8);
_serial->write(response_crc & 0xFF);
_serial->write(byteCount);
for (int i = 0; i < byteCount; i++) {
_serial->write(buf[i]);
}
_serial->write(0xFD);
_serial->write(0xFD);
_serial->flush();
if (_txPin != -1) digitalWrite(_txPin,LOW);
bool flagProc = false;
uint8_t Ireceived_data[ARRAY_SIZE];
//int received_data[ARRAY_SIZE];
uint16_t received_crc;
int byteCounted = 0;
unsigned long startMillis = millis();
while (!flagEnded) {
if (millis() - startMillis > 500) return; // safeguard timeout
while(_serial->available()) {
if (_serial->available()) {
uint16_t calculated_crc;
int byteCountRx = 100;
int curByte = _serial->read();
if (curByte == 0xFE && flagStart == false) flagStart = true;
else if ( curByte == 0xFE && flagStart == true) {
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) {
byteCountRx = curByte;
byteCounter++;
} else if (flagEnded == false && byteCounter >= 3) {
Ireceived_data[byteCounter-3] = curByte;
byteCounter++;
}
if (curByte == 0xFD && flagEnd == false) flagEnd = true;
else if ( curByte == 0xFD && flagEnd == true) {
flagEnded = true;
flagEnd = false;
rxEnd = true;
byteCounted = byteCounter;
byteCounter = 0;
calculated_crc = crc16((uint8_t*)Ireceived_data, byteCounted-6);
if (received_crc == calculated_crc) {
crcPass = true;
DIAG(F("CRC PASS %x %x BC: %i"), received_crc, calculated_crc, byteCounted);
} else {
DIAG(F("CRC FAIL %x %x BC: %i"), received_crc, calculated_crc, byteCounted);
}
return;
}
// Check CRC validity
if (crcPass) {
// Data received successfully, process it (e.g., print)
/*if (received_data[0] == 0) */flagProc = true;
//else DIAG(F("To Node: %i"), received_data[0]);
} else {
//DIAG(F("IO_RSproto: CRC Error!"));
}
}
}
}
if (flagProc) {
flagProc = false;
int nodeTo = Ireceived_data[0];
int nodeFr = Ireceived_data[1];
int AddrCode = Ireceived_data[2];
DIAG(F("From: %i, To: %i | %i %i %i %i %i"), nodeFr,nodeTo, Ireceived_data[3], Ireceived_data[4], Ireceived_data[5], Ireceived_data[6],Ireceived_data[7]);
return;
RSprotonode *node = findNode(nodeFr);
switch (AddrCode) {
case EXIOPINS:
{node->_numDigitalPins = Ireceived_data[3];
node->_numAnaloguePins = Ireceived_data[4];
// See if we already have suitable buffers assigned
if (node->_numDigitalPins>0) {
size_t digitalBytesNeeded = (node->_numDigitalPins + 7) / 8;
if (node->_digitalPinBytes < digitalBytesNeeded) {
// Not enough space, free any existing buffer and allocate a new one
if (node->_digitalPinBytes > 0) free(node->_digitalInputStates);
if ((node->_digitalInputStates = (byte*) calloc(digitalBytesNeeded, 1)) != NULL) {
node->_digitalPinBytes = digitalBytesNeeded;
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc %d bytes"), nodeFr, digitalBytesNeeded);
//_deviceState = DEVSTATE_FAILED;
node->_digitalPinBytes = 0;
return;
}
}
}
if (node->_numAnaloguePins>0) {
size_t analogueBytesNeeded = node->_numAnaloguePins * 2;
if (node->_analoguePinBytes < analogueBytesNeeded) {
// Free any existing buffers and allocate new ones.
if (node->_analoguePinBytes > 0) {
free(node->_analogueInputBuffer);
free(node->_analogueInputStates);
free(node->_analoguePinMap);
}
node->_analogueInputStates = (uint8_t*) calloc(analogueBytesNeeded, 1);
node->_analogueInputBuffer = (uint8_t*) calloc(analogueBytesNeeded, 1);
node->_analoguePinMap = (uint8_t*) calloc(node->_numAnaloguePins, 1);
if (node->_analogueInputStates != NULL &&
node->_analogueInputBuffer != NULL &&
node->_analoguePinMap != NULL) {
node->_analoguePinBytes = analogueBytesNeeded;
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc analog pin bytes"), nodeFr);
//_deviceState = DEVSTATE_FAILED;
node->_analoguePinBytes = 0;
return;
}
}
}
node->resFlag[retFlag] = 1;
break;}
case EXIOINITA: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->_analoguePinMap[i] = Ireceived_data[i+3];
}
node->resFlag[retFlag] = 1;
break;
}
case EXIOVER: {
node->_majorVer = Ireceived_data[3];
node->_minorVer = Ireceived_data[4];
node->_patchVer = Ireceived_data[5];
DIAG(F("EX-IOExpander device found, Node:%d, Version v%d.%d.%d"), node->getNodeID(), node->_majorVer, node->_minorVer, node->_patchVer);
break;
}
case EXIORDY: {
node->resFlag[retFlag] = 1;
break;
}
case EXIOERR: {
node->resFlag[retFlag] = -1;
break;
}
case EXIORDD: {
for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) {
node->_digitalInputStates[i] = Ireceived_data[i+3];
}
node->resFlag[retFlag] = 1;
break;
}
case EXIORDAN: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->_analogueInputBuffer[i] = Ireceived_data[i+3];
}
node->resFlag[retFlag] = 1;
break;
}
}
}
}
void RSproto::_loop(unsigned long currentMicros) {
_currentMicros = currentMicros;
if (_busy == true) return;
if (_currentTask == NULL) {
_currentTask = _taskListStart;
}
//if (_busy == true) return;
if (_currentMicros - _cycleStartTime < _cycleTime) return;
_cycleStartTime = _currentMicros;
if (_currentTask != NULL && _currentTask->_byteCount > 0) {
Task currentTask = getNextTask();
if (currentTask.completed != true) { // Check if a task was found
// Calculate CRC for response data
uint16_t response_crc = crc16((uint8_t*)_currentTask->commandArray, _currentTask->_byteCount-6);
if (!currentTask.rxMode) {
currentTask.crcPassFail = 0;
uint16_t response_crc = crc16((uint8_t*)currentTask.commandArray, currentTask.byteCount-1);
if (_txPin != -1) digitalWrite(_txPin,HIGH);
// Send response data with CRC
_serial->write(0xFE);
_serial->write(0xFE);
_serial->write(response_crc >> 8);
_serial->write(response_crc & 0xFF);
_serial->write(_currentTask->_byteCount);
for (int i = 0; i < _currentTask->_byteCount; i++) {
_serial->write(_currentTask->commandArray[i]);
_serial->write(currentTask.byteCount);
for (int i = 0; i < currentTask.byteCount; i++) {
_serial->write(currentTask.commandArray[i]);
}
_serial->write(0xFD);
_serial->write(0xFD);
_serial->flush();
if (_txPin != -1) digitalWrite(_txPin,LOW);
// delete task command after sending, for now
memset(_currentTask->commandArray, 0, _currentTask->_byteCount);
_currentTask->_byteCount = 0;
markTaskCompleted(currentTask.taskID);
}
if (_serial->available()) {
if (_serial->available() && currentTask.rxMode) {
uint16_t calculated_crc;
@ -485,12 +145,18 @@ void RSproto::_loop(unsigned long currentMicros) {
byteCounter = 0;
}
if (flagEnded) {
calculated_crc = crc16((uint8_t*)received_data, byteCount-6);
calculated_crc = crc16((uint8_t*)received_data, byteCount-7);
if (received_crc == calculated_crc) {
DIAG(F("Loop CRC PASS"));
crcPass = true;
}else DIAG(F("Loop CRC Fail %x %x"),received_crc,calculated_crc);
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) {
@ -498,110 +164,110 @@ void RSproto::_loop(unsigned long currentMicros) {
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!"));
}
task->getNext();
}
// temp debug
//end debug
if (flagProc) {
flagProc = false;
int nodeTo = received_data[0];
int nodeFr = received_data[1];
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;
//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;
RSprotonode *node = findNode(nodeFr);
switch (AddrCode) {
case EXIOPINS:
{node->_numDigitalPins = received_data[3];
node->_numAnaloguePins = received_data[4];
{node->setnumDigitalPins(received_data[3]);
node->setnumAnalogPins(received_data[4]);
// See if we already have suitable buffers assigned
if (node->_numDigitalPins>0) {
size_t digitalBytesNeeded = (node->_numDigitalPins + 7) / 8;
if (node->_digitalPinBytes < digitalBytesNeeded) {
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->_digitalPinBytes > 0) free(node->_digitalInputStates);
if ((node->_digitalInputStates = (byte*) calloc(digitalBytesNeeded, 1)) != NULL) {
node->_digitalPinBytes = digitalBytesNeeded;
if (node->cleandigitalPinStates(digitalBytesNeeded)) {
node->setdigitalPinBytes(digitalBytesNeeded);
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc %d bytes"), nodeFr, digitalBytesNeeded);
//_deviceState = DEVSTATE_FAILED;
node->_digitalPinBytes = 0;
node->setdigitalPinBytes(0);
return;
}
}
}
if (node->_numAnaloguePins>0) {
size_t analogueBytesNeeded = node->_numAnaloguePins * 2;
if (node->_analoguePinBytes < analogueBytesNeeded) {
if (node->getnumAnalogPins()>0) {
size_t analogueBytesNeeded = node->getnumAnalogPins() * 2;
if (node->getanalogPinBytes() < analogueBytesNeeded) {
// Free any existing buffers and allocate new ones.
if (node->_analoguePinBytes > 0) {
free(node->_analogueInputBuffer);
free(node->_analogueInputStates);
free(node->_analoguePinMap);
}
node->_analogueInputStates = (uint8_t*) calloc(analogueBytesNeeded, 1);
node->_analogueInputBuffer = (uint8_t*) calloc(analogueBytesNeeded, 1);
node->_analoguePinMap = (uint8_t*) calloc(node->_numAnaloguePins, 1);
if (node->_analogueInputStates != NULL &&
node->_analogueInputBuffer != NULL &&
node->_analoguePinMap != NULL) {
node->_analoguePinBytes = analogueBytesNeeded;
if (node->cleanAnalogStates(analogueBytesNeeded)) {
node->setanalogPinBytes(analogueBytesNeeded);
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc analog pin bytes"), nodeFr);
//_deviceState = DEVSTATE_FAILED;
node->_analoguePinBytes = 0;
node->setanalogPinBytes(0);
return;
}
}
}
node->resFlag[_currentTask->_retFlag] = 1;
node->resFlag[currentTask.retFlag] = 1;
break;}
case EXIOINITA: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->_analoguePinMap[i] = received_data[i+3];
for (int i = 0; i < node->getnumAnalogPins(); i++) {
node->setanalogPinMap(received_data[i+3], i);
}
node->resFlag[_currentTask->_retFlag] = 1;
node->resFlag[currentTask.retFlag] = 1;
break;
}
case EXIOVER: {
node->_majorVer = received_data[3];
node->_minorVer = received_data[4];
node->_patchVer = received_data[5];
node->resFlag[_currentTask->_retFlag] = 1;
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;
node->resFlag[currentTask.retFlag] = 1;
break;
}
case EXIOERR: {
node->resFlag[_currentTask->_retFlag] = -1;
node->resFlag[currentTask.retFlag] = -1;
break;
}
case EXIORDD: {
for (int i = 0; i < (node->_numDigitalPins+7)/8; i++) {
node->_digitalInputStates[i] = received_data[i+3];
node->setanalogInputStates(received_data[i+3], i);
}
node->resFlag[_currentTask->_retFlag] = 1;
node->resFlag[currentTask.retFlag] = 1;
break;
}
case EXIORDAN: {
for (int i = 0; i < node->_numAnaloguePins; i++) {
node->_analogueInputBuffer[i] = received_data[i+3];
node->setanalogInputBuffer(received_data[i+3], i);
}
node->resFlag[_currentTask->_retFlag] = 1;
node->resFlag[currentTask.retFlag] = 1;
break;
}
}
}
if (currentTask.gotCallback) {
}
}
}
// Link to chain of RSproto instances, left over from RSproto template.
@ -653,7 +319,7 @@ bool RSprotonode::_configure(VPIN vpin, ConfigTypeEnum configType, int paramCoun
unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0);
bus->_busy = true;
bus->sendInstantCommand(buff, 5, EXIODPUP);
bus->addTask(bus->taskIDCntr++, buff, 5, EXIODPUP);
bus->_busy = false;
return true;
@ -672,7 +338,7 @@ bool RSprotonode::_configure(VPIN vpin, ConfigTypeEnum configType, int paramCoun
unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0);
bus->_busy = true;
bus->sendInstantCommand(buff, 6, EXIOENAN);
bus->addTask(bus->taskIDCntr++, buff, 6, EXIOENAN);
bus->_busy = false;
return true;
@ -689,7 +355,7 @@ void RSprotonode::_begin() {
unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0);
bus->_busy = true;
bus->sendInstantCommand(buff, 6, EXIOINIT);
bus->addTask(bus->taskIDCntr++, buff, 6, EXIOINIT);
bus->_busy = false;
buff[0] = (_nodeID);
@ -697,7 +363,7 @@ void RSprotonode::_begin() {
buff[2] = (EXIOINITA);
startMillis = millis();
bus->_busy = true;
bus->sendInstantCommand(buff,3, EXIOINITA);
bus->addTask(bus->taskIDCntr++, buff, 3, EXIOINITA);
bus->_busy = false;
buff[0] = (_nodeID);
@ -705,7 +371,7 @@ void RSprotonode::_begin() {
buff[2] = (EXIOVER);
startMillis = millis();
bus->_busy = true;
bus->sendInstantCommand(buff,3, EXIOVER);
bus->addTask(bus->taskIDCntr++, buff, 3, EXIOVER);
bus->_busy = false;
@ -733,7 +399,7 @@ void RSprotonode::_write(VPIN vpin, int value) {
buff[4] = (value);
unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0);
task->doCommand(bus->taskCounter++, buff, 5, EXIOWRD);
bus->addTask(bus->taskIDCntr++, buff, 5, EXIOWRD);
}
@ -764,6 +430,6 @@ void RSprotonode::_write(VPIN vpin, int value) {
buff[8] = lowByte(duration);
unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0);
task->doCommand(bus->taskCounter++, buff, 9, EXIOWRAN);
bus->addTask(bus->taskIDCntr++, buff, 9, EXIOWRAN);
}

View File

@ -76,81 +76,6 @@ class RSprotonode;
* Data Packet must always precede the parameters with the Command byte.
* this way the data is processed by the correct routine.
**********************************************************************/
class taskBuffer
{
private:
HardwareSerial * hwSerial;
unsigned long _baud;
static const int ARRAY_SIZE = 254;
public:
static taskBuffer *first;
static taskBuffer *end;
RSprotonode *node;
unsigned long _taskID;
Stream * serial;
uint8_t _txPin;
uint8_t _nodeID;
uint8_t _commandType;
unsigned long _cycleTimer = 0ul;
taskBuffer *next;
uint8_t startChar[1] = {0xFD};
uint8_t endChar[1] = {0xFE};
int commandArray[ARRAY_SIZE];
int _byteCount = 0;
uint8_t _retFlag = 0;
// EX-IOExpander protocol flags
enum {
EXIOINIT = 0xE0, // Flag to initialise setup procedure
EXIORDY = 0xE1, // Flag we have completed setup procedure, also for EX-IO to ACK setup
EXIODPUP = 0xE2, // Flag we're sending digital pin pullup configuration
EXIOVER = 0xE3, // Flag to get version
EXIORDAN = 0xE4, // Flag to read an analogue input
EXIOWRD = 0xE5, // Flag for digital write
EXIORDD = 0xE6, // Flag to read digital input
EXIOENAN = 0xE7, // Flag to enable an analogue pin
EXIOINITA = 0xE8, // Flag we're receiving analogue pin mappings
EXIOPINS = 0xE9, // Flag we're receiving pin counts for buffers
EXIOWRAN = 0xEA, // Flag we're sending an analogue write (PWM)
EXIOERR = 0xEF, // Flag we've received an error
};
// RSproto protocol frame bytes
enum {
STARTBYTE = 0xFD,
ENDBYTE = 0xFE,
};
unsigned long getTaskID() {
return _taskID;
}
void setTaskID(unsigned long taskID) {
_taskID = taskID;
}
taskBuffer *getNext() {
return next;
}
void setNext(taskBuffer *task) {
next = task;
}
void addTask(taskBuffer *newTask) {
if (!first)
first = newTask;
if (!end)
end = newTask;
else
end->setNext(newTask);
//DIAG(F("RSproto: 260h nodeID:%d _nodeListStart:%d _nodeListEnd:%d"), newNode, _nodeListStart, _nodeListEnd);
}
taskBuffer(unsigned long taskID, uint8_t *commandBuffer, int byteCount, uint8_t retFlag);
~taskBuffer();
void doCommand(unsigned long taskID, uint8_t *commandBuffer, int byteCount, uint8_t retFlag);
};
@ -170,7 +95,6 @@ private:
RSprotonode *_next = NULL;
bool _initialised = false;
RSproto *bus;
taskBuffer *task;
HardwareSerial* _serial;
enum {
EXIOINIT = 0xE0, // Flag to initialise setup procedure
@ -200,17 +124,103 @@ public:
};
uint8_t _numDigitalPins = 0;
uint8_t getnumDigialPins() {
return _numDigitalPins;
}
void setnumDigitalPins(uint8_t value) {
_numDigitalPins = value;
}
uint8_t _numAnaloguePins = 0;
uint8_t getnumAnalogPins() {
return _numAnaloguePins;
}
void setnumAnalogPins(uint8_t value) {
_numAnaloguePins = value;
}
uint8_t _majorVer = 0;
uint8_t getMajVer() {
return _majorVer;
}
void setMajVer(uint8_t value) {
_majorVer = value;
}
uint8_t _minorVer = 0;
uint8_t getMinVer() {
return _minorVer;
}
void setMinVer(uint8_t value) {
_minorVer = value;
}
uint8_t _patchVer = 0;
uint8_t getPatVer() {
return _patchVer;
}
void setPatVer(uint8_t value) {
_patchVer = value;
}
uint8_t* _digitalInputStates = NULL;
uint8_t getdigitalInputStates(int index) {
return _digitalInputStates[index];
}
void setdigitalInputStates(uint8_t value, int index) {
_digitalInputStates[index] = value;
}
bool cleandigitalPinStates(int size) {
if (_digitalPinBytes > 0) free(_digitalInputStates);
if ((_digitalInputStates = (byte*) calloc(size, 1)) != NULL) {
return true;
} else return false;
}
uint8_t* _analogueInputStates = NULL;
uint8_t getanalogInputStates(int index) {
return _analogueInputStates[index];
}
void setanalogInputStates(uint8_t value, int index) {
_analogueInputStates[index] = value;
}
uint8_t* _analogueInputBuffer = NULL; // buffer for I2C input transfers
uint8_t _readCommandBuffer[4];
uint8_t getanalogInpuBuffer(int index) {
return _analogueInputBuffer[index];
}
void setanalogInputBuffer(uint8_t value, int index) {
_analogueInputBuffer[index] = value;
memcpy(_analogueInputStates, _analogueInputBuffer, _analoguePinBytes);
}
uint8_t _readCommandBuffer[4]; // unused?
uint8_t _digitalPinBytes = 0; // Size of allocated memory buffer (may be longer than needed)
uint8_t getdigitalPinBytes() {
return _digitalPinBytes;
}
void setdigitalPinBytes(uint8_t value) {
_digitalPinBytes = value;
}
uint8_t _analoguePinBytes = 0; // Size of allocated memory buffer (may be longer than needed)
uint8_t getanalogPinBytes() {
return _analoguePinBytes;
}
void setanalogPinBytes(uint8_t value) {
_analoguePinBytes = value;
}
uint8_t* _analoguePinMap = NULL;
uint8_t getanalogPinMap(int index) {
return _analoguePinMap[index];
}
void setanalogPinMap(uint8_t value, int index) {
_analoguePinMap[index] = value;
}
bool cleanAnalogStates(int size) {
if (_analoguePinBytes > 0) {
free(_analogueInputBuffer);
free(_analogueInputStates);
free(_analoguePinMap);
}
_analogueInputStates = (uint8_t*) calloc(size, 1);
_analogueInputBuffer = (uint8_t*) calloc(size, 1);
_analoguePinMap = (uint8_t*) calloc(_numAnaloguePins, 1);
if (_analogueInputStates != NULL && _analogueInputBuffer != NULL && _analoguePinMap != NULL) return true;
else return false;
}
int resFlag[255];
bool _initalized;
static void create(VPIN firstVpin, int nPins, uint8_t nodeID) {
@ -266,7 +276,6 @@ class RSproto : public IODevice {
private:
// Here we define the device-specific variables.
uint8_t _busNo;
taskBuffer *task;
unsigned long _cycleStartTime = 0;
unsigned long _timeoutStart = 0;
unsigned long _cycleTime; // target time between successive read/write cycles, microseconds
@ -300,7 +309,6 @@ private:
RSprotonode *_nodeListStart = NULL, *_nodeListEnd = NULL;
RSprotonode *_currentNode = NULL;
taskBuffer *_taskListStart = NULL, *_taskListEnd = NULL, *_currentTask=NULL;
uint16_t _receiveDataIndex = 0; // Index of next data byte to be received.
RSproto *_nextBus = NULL; // Pointer to next bus instance in list.
@ -312,6 +320,54 @@ private:
}
int byteCounter = 0;
public:
struct Task {
static const int ARRAY_SIZE = 254;
int taskID;
uint8_t commandArray[ARRAY_SIZE];
int byteCount;
uint8_t retFlag;
bool gotCallback;
bool rxMode;
int crcPassFail;
bool completed = false;
};
int taskIDCntr = 0;
Task taskBuffer[100]; // Buffer to hold up to 100 tasks
int taskCount = 0;
void addTask(int id, const uint8_t* cmd, int byteCount, uint8_t retFlag, bool gotCallBack=false, bool rxMode=false, int crcPassFail=0) {
if (taskCount < 100) { // Check if buffer is not full
taskBuffer[taskCount].taskID = id;
memcpy(taskBuffer[taskCount].commandArray, cmd, ARRAY_SIZE);
taskBuffer[taskCount].commandArray[ARRAY_SIZE] = 0; // Ensure null-termination
taskBuffer[taskCount].byteCount = byteCount;
taskBuffer[taskCount].retFlag = retFlag;
taskBuffer[taskCount].gotCallback = false;
taskBuffer[taskCount].rxMode = false;
taskBuffer[taskCount].crcPassFail = 0;
taskBuffer[taskCount].completed = false;
taskCount++;
} else {
Serial.println("Task buffer overflow!");
}
}
Task getNextTask() {
for (int i = 0; i < taskCount; i++) {
if (!taskBuffer[i].completed) {
return taskBuffer[i];
}
}
// Return a default task if no uncompleted tasks found
Task emptyTask;
return emptyTask;
}
void markTaskCompleted(int taskID) {
for (int i = 0; i < taskCount; i++) {
if (taskBuffer[i].taskID == taskID) {
taskBuffer[i].completed = true;
break;
}
}
}
bool flagEnd = false;
bool flagEnded = false;
bool flagStart = false;
@ -327,7 +383,6 @@ 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);
void sendInstantCommand(uint8_t *buf, int byteCount, uint8_t retFlag);
// EX-IOExpander protocol flags
enum {
EXIOINIT = 0xE0, // Flag to initialise setup procedure
@ -356,7 +411,7 @@ uint16_t crc16(uint8_t *data, uint16_t length);
unsigned long _baud;
int taskCnt = 0;
uint8_t initBuffer[1] = {0xFE};
unsigned long taskCounter=0;
unsigned long taskCounter=0ul;
// Device-specific initialisation
void _begin() override {
_serial->begin(_baud, SERIAL_8N1);
@ -400,13 +455,6 @@ uint16_t crc16(uint8_t *data, uint16_t length);
}
return NULL;
}
taskBuffer *findTask(uint8_t taskID) {
for (taskBuffer *task = _taskListStart; task != NULL; task = task->getNext()) {
if (task->getTaskID() == taskID)
return task;
}
return NULL;
}
bool nodesInitialized() {
bool retval = true;
@ -426,15 +474,7 @@ uint16_t crc16(uint8_t *data, uint16_t length);
_nodeListEnd->setNext(newNode);
//DIAG(F("RSproto: 260h nodeID:%d _nodeListStart:%d _nodeListEnd:%d"), newNode, _nodeListStart, _nodeListEnd);
}
void addTask(taskBuffer *newTask) {
if (!_taskListStart)
_taskListStart = newTask;
if (!_nodeListEnd)
_taskListEnd = newTask;
else
_taskListEnd->setNext(newTask);
//DIAG(F("RSproto: 260h nodeID:%d _nodeListStart:%d _nodeListEnd:%d"), newNode, _nodeListStart, _nodeListEnd);
}
protected:
RSproto(uint8_t busNo, HardwareSerial &serial, unsigned long baud, int8_t txPin, int cycleTime);