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:
parent
d892c27f3f
commit
c151b52114
474
IO_RSproto.cpp
474
IO_RSproto.cpp
@ -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);
|
||||
|
||||
}
|
234
IO_RSproto.h
234
IO_RSproto.h
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user