diff --git a/IO_RSproto.cpp b/IO_RSproto.cpp index 5483389..2f76559 100644 --- a/IO_RSproto.cpp +++ b/IO_RSproto.cpp @@ -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 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 (_currentNode == NULL) { - // _currentNode = _nodeListStart; + if (_busy == true) return; + if (_currentTask == NULL) { + _currentTask = _taskListStart; - //} + } 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); diff --git a/IO_RSproto.h b/IO_RSproto.h index 52fd39d..de7d020 100644 --- a/IO_RSproto.h +++ b/IO_RSproto.h @@ -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. @@ -283,8 +309,28 @@ private: if (fail) _deviceState = DEVSTATE_FAILED; } - + 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);