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-19 17:28:54 -05:00
parent 8414ff737c
commit 415dc2674a
No known key found for this signature in database
GPG Key ID: 0BC296791D14CB35
2 changed files with 342 additions and 203 deletions

View File

@ -27,13 +27,20 @@ static const byte PAYLOAD_STRING = 2;
taskBuffer * taskBuffer::first=NULL;
taskBuffer::taskBuffer(Stream * myserial)
taskBuffer::taskBuffer(unsigned long taskID, int *commandBuffer)
{
serial = myserial;
_taskID = taskID;
memset(commandArray, 0, ARRAY_SIZE);
memcpy(commandArray, commandBuffer, ARRAY_SIZE);
next=first;
first=this;
bufferLength=0;
inCommandPayload=PAYLOAD_FALSE;
RSproto *bus = RSproto::findBus(0);
if (bus != NULL) {
bus->addTask(this);
return;
}
}
taskBuffer::~taskBuffer()
@ -41,27 +48,20 @@ taskBuffer::~taskBuffer()
// destructor
}
int taskBuffer::getCharsRightOfPosition(char* str, char position, char* outStr, int size) {
//if (position >= 0 && position < strlen(str)) {
int pos;
char retStr[size];
for (int i = 0; str[i] != '\0'; i++) {
if (str[i] == position) {
pos = i;
break; // Exit the loop once the character is found
}
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];
}
}
int i;
for (i = 0; i < size; i++) {
retStr[i] = str[i+pos+1];
}
memcpy(outStr, retStr, i+pos+1);
return i+pos+2;
//}
str[j] = '\0'; // Ensure the string is null-terminated
}
void taskBuffer::getCharsLeft(char *str, char position, char *result) {
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;
@ -73,124 +73,25 @@ void taskBuffer::getCharsLeft(char *str, char position, char *result) {
if (i < pos) result[i] = str[i];
}
}
if (result != NULL) return atoi(result);
else return 0;
}
int taskBuffer::getValues(char *buf, int lenBuf, int fieldCnt, int *outArray) {
char curBuff[400];
memset(curBuff, '\0', 25);
int byteCntr = 0;
int counter = 0;
for (int i = 0; i< lenBuf; i++) {
if (buf[i] == ' ' || buf[i] == '\0'){
//outArray[counter] = 0x00;
outArray[byteCntr] = atoi(curBuff);
//DIAG(F("byte: %i"),outArray[byteCntr]);
byteCntr++;
memset(curBuff, '\0', sizeof(curBuff));
counter = 0;
} else {
curBuff[counter] = buf[i];
counter++;
}
if (byteCntr > fieldCnt || buf[i] == '\0') {
break;
}
}
return byteCntr;
}
void taskBuffer::doCommand(char *commandBuffer, int commandSize) {
for (taskBuffer * t=first;t;t=t->next) t->doCommand2(commandBuffer,commandSize);
}
void taskBuffer::doCommand2(char *commandBuffer, int commandSize) {
// process commands here to be sent
//_serial->begin(115200);
//ArduinoPins::fastWriteDigital(bus->_txPin, HIGH);
//int counter = 0;
//RSproto *bus = RSproto::findBus(0);
//RSprotonode *node = bus->findNode(commandSize);
//while (node->resFlag == 0 && counter < 5) {
if (_txPin != -1) digitalWrite(_txPin,HIGH);
serial->print(commandBuffer);
if (_txPin != -1) digitalWrite(_txPin,LOW);
//counter++;
//}
void taskBuffer::doCommand(unsigned long taskID, int *commandBuffer) {
// add commands here to be sent
new taskBuffer(taskID, commandBuffer);
}
void taskBuffer::init(HardwareSerial &hwSerial, unsigned long baud, int8_t txPin) {
hwSerial.begin(baud, SERIAL_8N1);
new taskBuffer(&hwSerial);
for (taskBuffer * t=first;t;t=t->next) t->_txPin = txPin;
if (txPin != -1) pinMode(txPin, OUTPUT);
if (txPin != -1) digitalWrite(txPin, LOW);
}
void taskBuffer::loop() {
for (taskBuffer * t=first;t;t=t->next) t->loop2();
}
void taskBuffer::loop2() {
// process received commands here
char ch;
while (serial->available()) {
ch = serial->read();
//RS485_SERIAL.write(ch,1); // send round the ring in case not ours
if (!inCommandPayload) {
if (ch == '<') {
inCommandPayload = PAYLOAD_NORMAL;
bufferLength = 0;
//tmpBuffer[0] = '\0';
}
} else { // if (inCommandPayload)
if (inCommandPayload == PAYLOAD_NORMAL) {
if (ch == '>') {
//tmpBuffer[bufferLength] = '\0';
char chrSize[3];
getCharsLeft(buffer,'|', chrSize);
char chrSend[400];
int remainder = getCharsRightOfPosition(buffer,'|',chrSend, sizeof(buffer));
DIAG(F("%s:%i:%i"),chrSend, remainder,atoi(chrSize));
parseRx(chrSend, remainder, atoi(chrSize));
memset(buffer, '\0', sizeof(buffer));
bufferLength = 0;
inCommandPayload = PAYLOAD_FALSE;
}
}
if (bufferLength < (COMMAND_BUFFER_SIZE-1) && inCommandPayload == PAYLOAD_NORMAL) {
buffer[bufferLength] = ch;
bufferLength++;
}
}
}
}
void taskBuffer::parseRx(char * rxbuffer, int rxBufLen, int fieldCnt) {
// pass on what we got
int outValues[fieldCnt];
memset(outValues, 0, sizeof(outValues));
int realCnt = getValues(rxbuffer, rxBufLen, fieldCnt, outValues);
parseOne(outValues);
}
void taskBuffer::parseOne(int *buf) {
// finaly, process the darn data
uint8_t toNode = buf[0];
if (toNode != 0) return; // not for master
uint8_t fromNode = buf[1];
if (fromNode == 0) return; // why did out own data come round the ring back to us?
uint8_t opcode = buf[2];
RSproto *bus = RSproto::findBus(0);
RSprotonode *node = bus->findNode(fromNode);
switch (opcode) {
void RSproto::parseRx(int * outArray) {
int nodeFr = (outArray[3] << 8) | outArray[2];
int AddrCode = (outArray[5] << 8) | outArray[4];
DIAG(F("From: %i, To: %i"), nodeFr,(outArray[1] << 8) | outArray[0]);
RSprotonode *node = findNode(nodeFr);
switch (AddrCode) {
case EXIOPINS:
{node->_numDigitalPins = buf[3];
node->_numAnaloguePins = buf[4];
{node->_numDigitalPins = (outArray[7] << 8) | outArray[6];
node->_numAnaloguePins = (outArray[9] << 8) | outArray[8];
// See if we already have suitable buffers assigned
if (node->_numDigitalPins>0) {
@ -201,7 +102,7 @@ void taskBuffer::parseOne(int *buf) {
if ((node->_digitalInputStates = (byte*) calloc(digitalBytesNeeded, 1)) != NULL) {
node->_digitalPinBytes = digitalBytesNeeded;
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc %d bytes"), fromNode, digitalBytesNeeded);
DIAG(F("EX-IOExpander485 node:%d ERROR alloc %d bytes"), nodeFr, digitalBytesNeeded);
//_deviceState = DEVSTATE_FAILED;
node->_digitalPinBytes = 0;
return;
@ -226,7 +127,7 @@ void taskBuffer::parseOne(int *buf) {
node->_analoguePinMap != NULL) {
node->_analoguePinBytes = analogueBytesNeeded;
} else {
DIAG(F("EX-IOExpander485 node:%d ERROR alloc analog pin bytes"), fromNode);
DIAG(F("EX-IOExpander485 node:%d ERROR alloc analog pin bytes"), nodeFr);
//_deviceState = DEVSTATE_FAILED;
node->_analoguePinBytes = 0;
return;
@ -237,15 +138,15 @@ void taskBuffer::parseOne(int *buf) {
break;}
case EXIOINITA: {
for (int i = 3; i < node->_numAnaloguePins; i++) {
node->_analoguePinMap[i] = buf[i];
node->_analoguePinMap[i] = (outArray[7] << 8) | outArray[6];
}
node->resFlag = 1;
break;
}
case EXIOVER: {
node->_majorVer = buf[3];
node->_minorVer = buf[4];
node->_patchVer = buf[5];
node->_majorVer = (outArray[7] << 8) | outArray[6];
node->_minorVer = (outArray[9] << 8) | outArray[8];
node->_patchVer = (outArray[11] << 8) | outArray[10];
node->resFlag = 1;
break;
}
@ -258,15 +159,15 @@ void taskBuffer::parseOne(int *buf) {
break;
}
case EXIORDD: {
for (int i = 3; i < (node->_numDigitalPins+7)/8; i++) {
node->_digitalInputStates[i-3] = buf[i];
for (int i = 0; i < (node->_numDigitalPins+7)/8; i=i+2) {
node->_digitalInputStates[i-3] = (outArray[i+1] << 8) | outArray[i];
}
node->resFlag = 1;
break;
}
case EXIORDAN: {
for (int i = 3; i < node->_numAnaloguePins*2; i++) {
node->_analogueInputBuffer[i-3] = buf[i];
node->_analogueInputBuffer[i-3] = (outArray[i+1] << 8) | outArray[i];
}
node->resFlag = 1;
break;
@ -282,11 +183,12 @@ void taskBuffer::parseOne(int *buf) {
RSproto::RSproto(uint8_t busNo, HardwareSerial &serial, unsigned long baud, int8_t txPin, int cycleTime) {
_serial = &serial;
_baud = baud;
_txPin = txPin;
_busNo = busNo;
_cycleTime = cycleTime;
task->init(serial, baud, txPin);
if (_waitA < 3) _waitA = 3;
bufferLength=0;
inCommandPayload=PAYLOAD_FALSE;
// Add device to HAL device chain
IODevice::addDevice(this);
@ -301,19 +203,117 @@ RSproto::RSproto(uint8_t busNo, HardwareSerial &serial, unsigned long baud, int8
// 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)
uint16_t RSproto::crc16(uint8_t *data, uint16_t length) {
uint16_t crc = 0xFFFF;
for (uint16_t i = 0; i < length; i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++) {
bool bit = ((crc & 0x0001) != 0);
crc >>= 1;
if (bit) {
crc ^= 0xA001;
}
}
}
return crc;
}
void RSproto::sendInstantCommand(int *buf) {
// Calculate CRC for response data
uint16_t response_crc = crc16((uint8_t*)buf, ARRAY_SIZE);
if (_txPin != -1) digitalWrite(_txPin,HIGH);
// Send response data with CRC
for (int i = 0; i < ARRAY_SIZE; i++) {
_serial->write(buf[i]);
}
_serial->write(response_crc >> 8);
_serial->write(response_crc & 0xFF);
_serial->flush();
if (_txPin != -1) digitalWrite(_txPin,LOW);
// delete task command after sending, for now
DIAG(F("SA: %I"),_serial->available());
if (_serial->available() >= ARRAY_SIZE) {
int received_data[ARRAY_SIZE];
// Read data and CRC
for (int i = 0; i < ARRAY_SIZE; i++) {
received_data[i] = _serial->read();
}
uint16_t received_crc = (_serial->read() << 8) | _serial->read();
// Calculate CRC for received data
uint16_t calculated_crc = crc16((uint8_t*)received_data, ARRAY_SIZE);
// Check CRC validity
if (calculated_crc == received_crc) {
// Data received successfully, process it (e.g., print)
int nodeTo = (received_data[1] << 8) | received_data[0];
if (nodeTo == 0) { // for master. master does not retransmit, or a loop will runaway.
parseRx(received_data);
}
} else {
DIAG(F("IO_RSproto: CRC Error!"));
}
}
}
void RSproto::_loop(unsigned long currentMicros) {
_currentMicros = currentMicros;
if (_busy == true) return;
if (_currentTask == NULL) {
_currentTask = _taskListStart;
//if (_currentNode == NULL) {
// _currentNode = _nodeListStart;
//}
}
if (_currentMicros - _cycleStartTime < _cycleTime) return;
_cycleStartTime = _currentMicros;
//if (_currentNode == NULL) return;
task->loop();
if (_currentTask != NULL && _currentTask->commandArray[0] != 0) {
// Calculate CRC for response data
uint16_t response_crc = crc16((uint8_t*)_currentTask->commandArray, ARRAY_SIZE);
if (_txPin != -1) digitalWrite(_txPin,HIGH);
// Send response data with CRC
for (int i = 0; i < ARRAY_SIZE; i++) {
_serial->write(_currentTask->commandArray[i]);
}
_serial->write(response_crc >> 8);
_serial->write(response_crc & 0xFF);
_serial->flush();
if (_txPin != -1) digitalWrite(_txPin,LOW);
// delete task command after sending, for now
memset(_currentTask->commandArray, 0, ARRAY_SIZE);
_currentTask->_commandSize = 0;
}
if (_serial->available() >= ARRAY_SIZE) {
int received_data[ARRAY_SIZE];
// Read data and CRC
for (int i = 0; i < ARRAY_SIZE; i++) {
received_data[i / sizeof(int)] = _serial->read();
}
uint16_t received_crc = (_serial->read() << 8) | _serial->read();
// Calculate CRC for received data
uint16_t calculated_crc = crc16((uint8_t*)received_data, ARRAY_SIZE);
// Check CRC validity
if (calculated_crc == received_crc) {
// Data received successfully, process it (e.g., print)
int nodeTo = (received_data[1] << 8) | received_data[0];
if (nodeTo == 0) { // for master. master does not retransmit, or a loop will runaway.
parseRx(received_data);
}
} else {
DIAG(F("IO_RSproto: CRC Error!"));
}
}
task->getNext();
}
// Link to chain of RSproto instances, left over from RSproto template.
@ -355,26 +355,50 @@ bool RSprotonode::_configure(VPIN vpin, ConfigTypeEnum configType, int paramCoun
int pin = vpin - _firstVpin;
uint8_t pullup = (uint8_t)params[0];
char buff[25];
sprintf(buff, "<5|%i %i %i %i %i>", _nodeID, 0, EXIODPUP, pin, pullup);
unsigned long startMillis = millis();
task->doCommand(buff,_nodeID);
while (resFlag == 0 && millis() - startMillis < 500); // blocking for now
if (resFlag != 1) {
DIAG(F("EX-IOExpander485 Vpin %u cannot be used as a digital input pin"), pin);
return false;
}
resFlag = 0;
return true;
int buff[ARRAY_SIZE];
buff[0] = highByte(_nodeID);
buff[1] = lowByte(_nodeID);
buff[2] = highByte(0);
buff[3] = lowByte(0);
buff[4] = highByte(EXIODPUP);
buff[5] = lowByte(EXIODPUP);
buff[6] = highByte(pin);
buff[7] = lowByte(pin);
buff[8] = highByte(pullup);
buff[9] = lowByte(pullup);
unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0);
bus->_busy = true;
bus->sendInstantCommand(buff);
bus->_busy = false;
while (resFlag == 0 && millis() - startMillis < 500); // blocking for now
if (resFlag != 1) {
DIAG(F("EX-IOExpander485 Vpin %u cannot be used as a digital input pin"), pin);
return false;
}
resFlag = 0;
return true;
}
int RSprotonode::_configureAnalogIn(VPIN vpin) {
int pin = vpin - _firstVpin;
//RSproto *mainrs = RSproto::findBus(_busNo);
char buff[25];
sprintf(buff, "<6|%i %i %i %i %i %i>", _nodeID, 0, EXIOENAN, pin, _firstVpin);
int buff[ARRAY_SIZE];
buff[0] = highByte(_nodeID);
buff[1] = lowByte(_nodeID);
buff[2] = highByte(0);
buff[3] = lowByte(0);
buff[4] = highByte(EXIOENAN);
buff[5] = lowByte(EXIOENAN);
buff[6] = highByte(pin);
buff[7] = lowByte(pin);
buff[8] = highByte(_firstVpin);
buff[9] = lowByte(_firstVpin);
unsigned long startMillis = millis();
task->doCommand(buff, _nodeID);
RSproto *bus = RSproto::findBus(0);
bus->_busy = true;
bus->sendInstantCommand(buff);
bus->_busy = false;
while (resFlag == 0 && millis() - startMillis < 500); // blocking for now
if (resFlag != 1) {
DIAG(F("EX-IOExpander485 Vpin %u cannot be used as a digital input pin"), pin);
@ -385,26 +409,52 @@ bool RSprotonode::_configure(VPIN vpin, ConfigTypeEnum configType, int paramCoun
}
void RSprotonode::_begin() {
char buff[25];
sprintf(buff, "<6|%i %i %i %i %i %i>", _nodeID, 0, EXIOINIT, _nPins, (_firstVpin & 0xFF), (_firstVpin >> 8));
unsigned long startMillis = millis();
task->doCommand(buff,_nodeID);
int buff[ARRAY_SIZE];
buff[0] = highByte(_nodeID);
buff[1] = lowByte(_nodeID);
buff[2] = highByte(0);
buff[3] = lowByte(0);
buff[4] = highByte(EXIOINIT);
buff[5] = lowByte(EXIOINIT);
buff[6] = highByte(_nPins);
buff[7] = lowByte(_nPins);
buff[8] = highByte((_firstVpin & 0xFF));
buff[9] = lowByte((_firstVpin >> 8));
unsigned long startMillis = millis();
RSproto *bus = RSproto::findBus(0);
bus->_busy = true;
bus->sendInstantCommand(buff);
bus->_busy = false;
while (resFlag == 0 && millis() - startMillis < 1000); // blocking for now
if (resFlag != 1) {
DIAG(F("EX-IOExpander485 Node:%d ERROR EXIOINIT"), _nodeID);
}
resFlag = 0;
sprintf(buff, "<3|%i %i %i>", _nodeID, 0, EXIOINITA);
buff[0] = highByte(_nodeID);
buff[1] = lowByte(_nodeID);
buff[2] = highByte(0);
buff[3] = lowByte(0);
buff[4] = highByte(EXIOINITA);
buff[5] = lowByte(EXIOINITA);
startMillis = millis();
task->doCommand(buff,_nodeID);
bus->_busy = true;
bus->sendInstantCommand(buff);
bus->_busy = false;
while (resFlag == 0 && millis() - startMillis < 1000); // blocking for now
if (resFlag != 1) {
DIAG(F("EX-IOExpander485 Node:%d ERROR EXIOINITA"), _nodeID);
}
resFlag = 0;
sprintf(buff, "<3|%i %i %i>", _nodeID, 0, EXIOVER);
buff[0] = highByte(_nodeID);
buff[1] = lowByte(_nodeID);
buff[2] = highByte(0);
buff[3] = lowByte(0);
buff[4] = highByte(EXIOVER);
buff[5] = lowByte(EXIOVER);
startMillis = millis();
task->doCommand(buff,_nodeID);
bus->_busy = true;
bus->sendInstantCommand(buff);
bus->_busy = false; task->doCommand(bus->taskCounter++, buff);
while (resFlag == 0 && millis() - startMillis < 1000); // blocking for now
if (resFlag != 1) {
DIAG(F("EX-IOExpander485 Node:%d ERROR EXIOVER"), _nodeID);
@ -427,10 +477,20 @@ int RSprotonode::_read(VPIN vpin) {
void RSprotonode::_write(VPIN vpin, int value) {
if (_deviceState == DEVSTATE_FAILED) return;
int pin = vpin - _firstVpin;
char buff[25];
sprintf(buff, "<5|%i %i %i %i %i>", _nodeID, 0, EXIOWRD, pin, value);
int buff[ARRAY_SIZE];
buff[0] = highByte(_nodeID);
buff[1] = lowByte(_nodeID);
buff[2] = highByte(0);
buff[3] = lowByte(0);
buff[4] = highByte(EXIOWRD);
buff[5] = lowByte(EXIOWRD);
buff[6] = highByte(pin);
buff[7] = lowByte(pin);
buff[8] = highByte(value);
buff[9] = lowByte(value);
unsigned long startMillis = millis();
task->doCommand(buff,_nodeID);
RSproto *bus = RSproto::findBus(0);
task->doCommand(bus->taskCounter++, buff);
while (resFlag == 0 && millis() - startMillis < 500); // blocking for now
if (resFlag != 1) {
DIAG(F("EX-IOExpander485 Node:%d ERROR EXIOVER"), _nodeID);
@ -453,10 +513,24 @@ void RSprotonode::_write(VPIN vpin, int value) {
void RSprotonode::_writeAnalogue(VPIN vpin, int value, uint8_t profile, uint16_t duration) {
int pin = vpin - _firstVpin;
char buff[25];
sprintf(buff, "<7|%i %i %i %i %i %i %i>", _nodeID, 0, EXIOWRAN, pin, value, profile, duration);
int buff[ARRAY_SIZE];
buff[0] = highByte(_nodeID);
buff[1] = lowByte(_nodeID);
buff[2] = highByte(0);
buff[3] = lowByte(0);
buff[4] = highByte(EXIOWRAN);
buff[5] = lowByte(EXIOWRAN);
buff[6] = highByte(pin);
buff[7] = lowByte(pin);
buff[8] = highByte(value);
buff[9] = lowByte(value);
buff[8] = highByte(profile);
buff[9] = lowByte(profile);
buff[8] = highByte(duration);
buff[9] = lowByte(duration);
unsigned long startMillis = millis();
task->doCommand(buff,_nodeID);
RSproto *bus = RSproto::findBus(0);
task->doCommand(bus->taskCounter++, buff);
while (resFlag == 0 && millis() - startMillis < 500); // blocking for now
if (resFlag != 1) {
DIAG(F("EX-IOExpander485 Node:%d ERROR EXIOVER"), _nodeID);

View File

@ -53,7 +53,7 @@ class RSprotonode;
#ifndef COMMAND_BUFFER_SIZE
#define COMMAND_BUFFER_SIZE 400
#define COMMAND_BUFFER_SIZE 900
#endif
/**********************************************************************
@ -79,18 +79,26 @@ class RSprotonode;
class taskBuffer
{
private:
static taskBuffer *first;
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;
byte bufferLength;
char buffer[COMMAND_BUFFER_SIZE];
unsigned long _cycleTimer = 0ul;
taskBuffer *next;
uint8_t startChar[1] = {0xFD};
uint8_t endChar[1] = {0xFE};
byte inCommandPayload;
int commandArray[ARRAY_SIZE];
int _commandSize = 0;
// EX-IOExpander protocol flags
enum {
EXIOINIT = 0xE0, // Flag to initialise setup procedure
@ -111,19 +119,34 @@ static taskBuffer *first;
STARTBYTE = 0xFD,
ENDBYTE = 0xFE,
};
int getCharsRightOfPosition(char* str, char position, char* outStr, int size);
void getCharsLeft(char *str, char position, char *result);
int getValues(char *buf, int lenBuf, int fieldCnt, int *outArray);
void doCommand2(char *commandBuffer, int commandSize=0);
void loop2();
void parseRx(char * rxbuffer, int rxBufLen, int fieldCnt);
void parseOne(int *buf);
public:
taskBuffer(Stream * myserial);
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, int *commandBuffer);
~taskBuffer();
static void doCommand(char *commandBuffer, int commandSize=0);
static void init(HardwareSerial &hwSerial, unsigned long baud, int8_t txPin=-1);
static void loop();
void doCommand(unsigned long taskID, int *commandBuffer);
};
@ -148,7 +171,6 @@ private:
RSproto *bus;
taskBuffer *task;
HardwareSerial* _serial;
// 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
@ -163,7 +185,7 @@ private:
EXIOWRAN = 0xEA, // Flag we're sending an analogue write (PWM)
EXIOERR = 0xEF, // Flag we've received an error
};
static const int ARRAY_SIZE = 254;
public:
static RSprotonode *_nodeList;
enum ProfileType : int {
@ -253,7 +275,10 @@ private:
unsigned long _byteTransmitTime; // time in us for transmission of one byte
int _operationCount = 0;
int _refreshOperation = 0;
byte bufferLength;
static const int ARRAY_SIZE = 254;
int buffer[ARRAY_SIZE];
byte inCommandPayload;
static RSproto *_busList; // linked list of defined bus instances
bool waitReceive = false;
int _waitCounter = 0;
@ -274,6 +299,7 @@ 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.
@ -285,6 +311,26 @@ private:
}
public:
uint16_t crc16(uint8_t *data, uint16_t length);
void remove_nulls(char *str, int len);
int getCharsLeft(char *str, char position);
void parseRx(int * outArray);
void sendInstantCommand(int *buf);
// 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
};
static void create(uint8_t busNo, HardwareSerial &serial, unsigned long baud, int8_t txPin=-1, int cycleTime=500) {
new RSproto(busNo, serial, baud, txPin, cycleTime);
}
@ -298,10 +344,14 @@ public:
unsigned long _baud;
int taskCnt = 0;
uint8_t initBuffer[1] = {0xFE};
unsigned long taskCounter=0;
// Device-specific initialisation
void _begin() override {
_serial->begin(_baud, SERIAL_8N1);
if (_txPin >0) {
pinMode(_txPin, OUTPUT);
digitalWrite(_txPin, LOW);
}
#if defined(RSproto_STM_OK)
pinMode(RSproto_STM_OK, OUTPUT);
ArduinoPins::fastWriteDigital(RSproto_STM_OK,LOW);
@ -338,6 +388,13 @@ public:
}
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;
@ -357,7 +414,15 @@ public:
_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);