diff --git a/README.md b/README.md index 8c1875b..1a36037 100644 --- a/README.md +++ b/README.md @@ -42,4 +42,6 @@ See the [example sketches](https://github.com/PowerBroker2/SerialTransfer/tree/m # ***NOTE:*** -SPITransfer.h and it's associated features are not supported for the Arduino Nano 33 BLE or DUE. +SPITransfer.h and it's associated features are not supported for the ESP8266, Arduino Nano 33 BLE or DUE. + +Should the automatic detection of SPI support fail you can define the macro `SPI_TRANSFER` to `1` to forcefully enable SPI or to `0` to forcefully disable it. diff --git a/examples/i2c_rx_data/i2c_rx_data.ino b/examples/i2c_rx_data/i2c_rx_data.ino index d31536a..c48b12f 100644 --- a/examples/i2c_rx_data/i2c_rx_data.ino +++ b/examples/i2c_rx_data/i2c_rx_data.ino @@ -3,51 +3,41 @@ I2CTransfer myTransfer; -struct STRUCT { - char z; - float y; +struct STRUCT +{ + char z; + float y; } testStruct; char arr[6]; /////////////////////////////////////////////////////////////////// Callbacks -void hi() +void handlePacket(Packet& packet) { - // use this variable to keep track of how many - // bytes we've processed from the receive buffer - uint16_t recSize = 0; - - recSize = myTransfer.rxObj(testStruct, recSize); - Serial.print(testStruct.z); - Serial.print(testStruct.y); - Serial.print(" | "); + packet.rxObj(testStruct); + Serial.print(testStruct.z); + Serial.print(testStruct.y); + Serial.print(" | "); - recSize = myTransfer.rxObj(arr, recSize); - Serial.println(arr); + packet.rxObj(arr); + Serial.println(arr); } /////////////////////////////////////////////////////////////////// void setup() { - Serial.begin(115200); - Wire.begin(0); - - functionPtr callbackArr[] = { hi }; - - ///////////////////////////////////////////////////////////////// Config Parameters - configST myConfig; - myConfig.debug = true; - myConfig.callbacks = callbackArr; - myConfig.callbacksLen = sizeof(callbackArr) / sizeof(functionPtr); - ///////////////////////////////////////////////////////////////// - - myTransfer.begin(Wire, myConfig); + Serial.begin(115200); + Wire.begin(0); + + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(Wire, Serial); + myTransfer.addCallback(handlePacket); } void loop() { - // Do nothing + myTransfer.tick(); } diff --git a/examples/i2c_rx_datum/i2c_rx_datum.ino b/examples/i2c_rx_datum/i2c_rx_datum.ino index e7cd626..e764b95 100644 --- a/examples/i2c_rx_datum/i2c_rx_datum.ino +++ b/examples/i2c_rx_datum/i2c_rx_datum.ino @@ -3,41 +3,37 @@ I2CTransfer myTransfer; -struct STRUCT { - char z; - float y; +struct STRUCT +{ + char z; + float y; } testStruct; /////////////////////////////////////////////////////////////////// Callbacks -void hi() +void handlePacket(Packet& packet) { - myTransfer.rxObj(testStruct); - Serial.print(testStruct.z); - Serial.println(testStruct.y); + packet.rxObj(testStruct); + Serial.print(testStruct.z); + Serial.print(testStruct.y); } /////////////////////////////////////////////////////////////////// void setup() { - Serial.begin(115200); - Wire.begin(0); - - functionPtr callbackArr[] = { hi }; - - ///////////////////////////////////////////////////////////////// Config Parameters - configST myConfig; - myConfig.debug = true; - myConfig.callbacks = callbackArr; - myConfig.callbacksLen = sizeof(callbackArr) / sizeof(functionPtr); - ///////////////////////////////////////////////////////////////// - - myTransfer.begin(Wire, myConfig); + Serial.begin(115200); + Wire.begin(0); + + Wire.begin(0); + + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(Wire, Serial); + myTransfer.addCallback(handlePacket); } void loop() { - // Do nothing + myTransfer.tick(); } diff --git a/examples/i2c_tx_data/i2c_tx_data.ino b/examples/i2c_tx_data/i2c_tx_data.ino index 984c54f..a403599 100644 --- a/examples/i2c_tx_data/i2c_tx_data.ino +++ b/examples/i2c_tx_data/i2c_tx_data.ino @@ -3,9 +3,10 @@ I2CTransfer myTransfer; -struct STRUCT { - char z; - float y; +struct STRUCT +{ + char z; + float y; } testStruct; char arr[] = "hello"; @@ -13,29 +14,26 @@ char arr[] = "hello"; void setup() { - Serial.begin(115200); - Wire.begin(); + Serial.begin(115200); + Wire.begin(); - myTransfer.begin(Wire); + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(Wire, Serial); - testStruct.z = '$'; - testStruct.y = 4.5; + testStruct.z = '$'; + testStruct.y = 4.5; } void loop() { - // use this variable to keep track of how many - // bytes we're stuffing in the transmit buffer - uint16_t sendSize = 0; - - ///////////////////////////////////////// Stuff buffer with struct - sendSize = myTransfer.txObj(testStruct, sendSize); + ///////////////////////////////////////// Stuff buffer with struct + myTransfer.txObj(testStruct); - ///////////////////////////////////////// Stuff buffer with array - sendSize = myTransfer.txObj(arr, sendSize); + ///////////////////////////////////////// Stuff buffer with array + myTransfer.txObj(arr); - ///////////////////////////////////////// Send buffer - myTransfer.sendData(sendSize); - delay(500); + ///////////////////////////////////////// Send buffer + myTransfer.sendPacket(); + delay(500); } diff --git a/examples/i2c_tx_datum/i2c_tx_datum.ino b/examples/i2c_tx_datum/i2c_tx_datum.ino index 96a7c58..cea75ae 100644 --- a/examples/i2c_tx_datum/i2c_tx_datum.ino +++ b/examples/i2c_tx_datum/i2c_tx_datum.ino @@ -3,26 +3,28 @@ I2CTransfer myTransfer; -struct STRUCT { - char z; - float y; +struct STRUCT +{ + char z; + float y; } testStruct; void setup() { - Serial.begin(115200); - Wire.begin(); + Serial.begin(115200); + Wire.begin(); - myTransfer.begin(Wire); + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(Wire, Serial); - testStruct.z = '$'; - testStruct.y = 4.5; + testStruct.z = '$'; + testStruct.y = 4.5; } void loop() { - myTransfer.sendDatum(testStruct); - delay(500); + myTransfer.sendObj(testStruct); + delay(500); } diff --git a/examples/spi_rx_data/spi_rx_data.ino b/examples/spi_rx_data/spi_rx_data.ino index 214bad3..1ae48a8 100644 --- a/examples/spi_rx_data/spi_rx_data.ino +++ b/examples/spi_rx_data/spi_rx_data.ino @@ -3,51 +3,33 @@ SPITransfer myTransfer; -struct STRUCT { - char z; - float y; +struct STRUCT +{ + char z; + float y; } testStruct; char arr[6]; -volatile bool procNewPacket = false; - void setup() { - Serial.begin(115200); - - SPCR |= bit (SPE); - pinMode(MISO, OUTPUT); - SPI.attachInterrupt(); - - myTransfer.begin(SPI); -} + Serial.begin(115200); + pinMode(MISO, OUTPUT); -void loop() -{ - if(procNewPacket) - { - procNewPacket = false; - - // use this variable to keep track of how many - // bytes we've processed from the receive buffer - uint16_t recSize = 0; - - recSize = myTransfer.rxObj(testStruct, recSize); - Serial.print(testStruct.z); - Serial.print(testStruct.y); - Serial.print(" | "); - - recSize = myTransfer.rxObj(arr, recSize); - Serial.println(arr); - } + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(SPI, Serial); } -ISR (SPI_STC_vect) +void loop() { - if(myTransfer.available()) - procNewPacket = true; + myTransfer.rxObj(testStruct); + Serial.print(testStruct.z); + Serial.print(testStruct.y); + Serial.print(" | "); + + myTransfer.rxObj(arr); + Serial.println(arr); } diff --git a/examples/spi_rx_datum/spi_rx_datum.ino b/examples/spi_rx_datum/spi_rx_datum.ino index f63a449..91c8daf 100644 --- a/examples/spi_rx_datum/spi_rx_datum.ino +++ b/examples/spi_rx_datum/spi_rx_datum.ino @@ -3,41 +3,27 @@ SPITransfer myTransfer; -struct STRUCT { - char z; - float y; +struct STRUCT +{ + char z; + float y; } testStruct; -volatile bool procNewPacket = false; - void setup() { - Serial.begin(115200); - - SPCR |= bit (SPE); - pinMode(MISO, OUTPUT); - SPI.attachInterrupt(); - - myTransfer.begin(SPI); -} + Serial.begin(115200); + pinMode(MISO, OUTPUT); -void loop() -{ - if(procNewPacket) - { - procNewPacket = false; - - myTransfer.rxObj(testStruct); - Serial.print(testStruct.z); - Serial.println(testStruct.y); - } + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(SPI, Serial); } -ISR (SPI_STC_vect) +void loop() { - if(myTransfer.available()) - procNewPacket = true; + myTransfer.rxObj(testStruct); + Serial.print(testStruct.z); + Serial.print(testStruct.y); } diff --git a/examples/spi_rx_file/spi_rx_file.ino b/examples/spi_rx_file/spi_rx_file.ino index 5ff26c3..c4af5ce 100644 --- a/examples/spi_rx_file/spi_rx_file.ino +++ b/examples/spi_rx_file/spi_rx_file.ino @@ -4,46 +4,36 @@ SPITransfer myTransfer; const int fileSize = 2000; -char file[fileSize]; -char fileName[10]; - -volatile bool procNewPacket = false; +char file[fileSize]; +char fileName[10]; void setup() { - Serial.begin(115200); - - SPCR |= bit (SPE); - pinMode(MISO, OUTPUT); - SPI.attachInterrupt(); - - myTransfer.begin(SPI); -} + Serial.begin(115200); + pinMode(MISO, OUTPUT); -void loop() -{ - if(procNewPacket) - { - procNewPacket = false; - - if (!myTransfer.currentPacketID()) - { - myTransfer.rxObj(fileName); - Serial.println(); - Serial.println(fileName); - } - else if (myTransfer.currentPacketID() == 1) - for(uint8_t i=2; i fileSize) // Determine data length for the last packet if file length is not an exact multiple of MAX_PACKET_SIZE-2 - dataLen = fileSize - fileIndex; - - uint8_t sendSize = myTransfer.txObj(fileIndex); // Stuff the current file index - sendSize = myTransfer.txObj(file[fileIndex], sendSize, dataLen); // Stuff the current file data - - myTransfer.sendData(sendSize, 1); // Send the current file index and data - delay(100); - } - delay(10000); + constexpr uint8_t maxTransferPacketSize = MAX_PACKET_SIZE - 2; + + myTransfer.sendObj(fileName); // Send filename + + uint16_t numPackets = fileSize / maxTransferPacketSize; // Reserve one byte for current file index + + if (fileSize % maxTransferPacketSize) // Add an extra transmission if needed + numPackets++; + + for (uint16_t i = 0; i < numPackets; i++) // Send all data within the file across multiple packets + { + uint8_t dataLen = maxTransferPacketSize; + uint16_t fileIndex = i * maxTransferPacketSize; // Determine the current file index + + // Determine data length for the last packet if file length is not an exact multiple of MAX_PACKET_SIZE-2 + if ((fileIndex + maxTransferPacketSize) > fileSize) + dataLen = fileSize - fileIndex; + + myTransfer.txObj(fileIndex); // Stuff the current file index + myTransfer.txObj(file[fileIndex], dataLen); // Stuff the current file data + + myTransfer.sendPacket(1); // Send the current file index and data + delay(100); + } + delay(10000); } diff --git a/examples/uart_rx_data/uart_rx_data.ino b/examples/uart_rx_data/uart_rx_data.ino index 2248305..554cb73 100644 --- a/examples/uart_rx_data/uart_rx_data.ino +++ b/examples/uart_rx_data/uart_rx_data.ino @@ -3,9 +3,10 @@ SerialTransfer myTransfer; -struct STRUCT { - char z; - float y; +struct STRUCT +{ + char z; + float y; } testStruct; char arr[6]; @@ -13,26 +14,24 @@ char arr[6]; void setup() { - Serial.begin(115200); - Serial1.begin(115200); - myTransfer.begin(Serial1); + Serial.begin(115200); + Serial1.begin(115200); + + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(Serial1, Serial); } void loop() { - if(myTransfer.available()) - { - // use this variable to keep track of how many - // bytes we've processed from the receive buffer - uint16_t recSize = 0; - - recSize = myTransfer.rxObj(testStruct, recSize); - Serial.print(testStruct.z); - Serial.print(testStruct.y); - Serial.print(" | "); - - recSize = myTransfer.rxObj(arr, recSize); - Serial.println(arr); - } + if (myTransfer.available()) + { + myTransfer.rxObj(testStruct); + Serial.print(testStruct.z); + Serial.print(testStruct.y); + Serial.print(" | "); + + myTransfer.rxObj(arr); + Serial.println(arr); + } } diff --git a/examples/uart_rx_datum/uart_rx_datum.ino b/examples/uart_rx_datum/uart_rx_datum.ino index bb0e4e3..0393175 100644 --- a/examples/uart_rx_datum/uart_rx_datum.ino +++ b/examples/uart_rx_datum/uart_rx_datum.ino @@ -3,26 +3,29 @@ SerialTransfer myTransfer; -struct STRUCT { - char z; - float y; +struct STRUCT +{ + char z; + float y; } testStruct; void setup() { - Serial.begin(115200); - Serial1.begin(115200); - myTransfer.begin(Serial1); + Serial.begin(115200); + Serial1.begin(115200); + + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(Serial1, Serial); } void loop() { - if(myTransfer.available()) - { - myTransfer.rxObj(testStruct); - Serial.print(testStruct.z); - Serial.println(testStruct.y); - } + if (myTransfer.available()) + { + myTransfer.rxObj(testStruct); + Serial.print(testStruct.z); + Serial.println(testStruct.y); + } } diff --git a/examples/uart_rx_file/uart_rx_file.ino b/examples/uart_rx_file/uart_rx_file.ino index 0fec67c..c94ec7e 100644 --- a/examples/uart_rx_file/uart_rx_file.ino +++ b/examples/uart_rx_file/uart_rx_file.ino @@ -4,32 +4,35 @@ SerialTransfer myTransfer; const int fileSize = 2000; -char file[fileSize]; -char fileName[10]; +char file[fileSize]; +char fileName[10]; void setup() { - Serial.begin(115200); - Serial1.begin(115200); - - myTransfer.begin(Serial1); + Serial.begin(115200); + Serial1.begin(115200); + + // Serial is the debug serial port. If you don't want to enable debugging, you can remove it + myTransfer.begin(Serial1, Serial); } void loop() { - if (myTransfer.available()) - { - if (!myTransfer.currentPacketID()) - { - myTransfer.rxObj(fileName); - Serial.println(); - Serial.println(fileName); - } - else if (myTransfer.currentPacketID() == 1) - for(uint8_t i=2; i fileSize) // Determine data length for the last packet if file length is not an exact multiple of MAX_PACKET_SIZE-2 - dataLen = fileSize - fileIndex; - - uint8_t sendSize = myTransfer.txObj(fileIndex); // Stuff the current file index - sendSize = myTransfer.txObj(file[fileIndex], sendSize, dataLen); // Stuff the current file data - - myTransfer.sendData(sendSize, 1); // Send the current file index and data - delay(100); - } - delay(10000); + constexpr uint8_t maxTransferPacketSize = MAX_PACKET_SIZE - 2; + + myTransfer.sendObj(fileName); // Send filename + + uint16_t numPackets = fileSize / maxTransferPacketSize; // Reserve one byte for current file index + + if (fileSize % maxTransferPacketSize) // Add an extra transmission if needed + numPackets++; + + for (uint16_t i = 0; i < numPackets; i++) // Send all data within the file across multiple packets + { + uint8_t dataLen = maxTransferPacketSize; + uint16_t fileIndex = i * maxTransferPacketSize; // Determine the current file index + + // Determine data length for the last packet if file length is not an exact multiple of MAX_PACKET_SIZE-2 + if ((fileIndex + maxTransferPacketSize) > fileSize) + dataLen = fileSize - fileIndex; + + myTransfer.txObj(fileIndex); // Stuff the current file index + myTransfer.txObj(file[fileIndex], dataLen); // Stuff the current file data + + myTransfer.sendPacket(1); // Send the current file index and data + delay(100); + } + delay(10000); } diff --git a/src/I2CTransfer.cpp b/src/I2CTransfer.cpp deleted file mode 100644 index b11630a..0000000 --- a/src/I2CTransfer.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "I2CTransfer.h" - - -/* - void I2CTransfer::begin(TwoWire &_port, configST configs) - Description: - ------------ - * Advanced initializer for the I2CTransfer Class - Inputs: - ------- - * const TwoWire &_port - I2C port to communicate over - * const configST configs - Struct that holds config - values for all possible initialization parameters - Return: - ------- - * void -*/ -void I2CTransfer::begin(TwoWire& _port, const configST configs) -{ - port = &_port; - port->onReceive(processData); - packet.begin(configs); -} - - -/* - void I2CTransfer::begin(TwoWire &_port, const bool _debug, Stream &_debugPort) - Description: - ------------ - * Simple initializer for the SerialTransfer Class - Inputs: - ------- - * const TwoWire &_port - I2C port to communicate over - * const bool _debug - Whether or not to print error messages - * const Stream &_debugPort - Serial port to print error messages - Return: - ------- - * void -*/ -void I2CTransfer::begin(TwoWire& _port, const bool _debug, Stream& _debugPort) -{ - port = &_port; - packet.begin(_debug, _debugPort); -} - - -/* - uint8_t I2CTransfer::sendData(const uint16_t &messageLen, const uint8_t &packetID, const uint8_t &targetAddress=0) - Description: - ------------ - * Send a specified number of bytes in packetized form - Inputs: - ------- - * const uint16_t &messageLen - Number of values in txBuff - to send as the payload in the next packet - * const uint8_t &packetID - The packet 8-bit identifier - * const uint8_t &targetAddress - I2C address to the device the packet - will be transmitted to - Return: - ------- - * uint8_t numBytesIncl - Number of payload bytes included in packet -*/ -uint8_t I2CTransfer::sendData(const uint16_t& messageLen, const uint8_t& packetID, const uint8_t& targetAddress) -{ - uint8_t numBytesIncl; - - numBytesIncl = packet.constructPacket(messageLen, packetID); - - port->beginTransmission(targetAddress); - port->write(packet.preamble, sizeof(packet.preamble)); - port->write(packet.txBuff, numBytesIncl); - port->write(packet.postamble, sizeof(packet.postamble)); - port->endTransmission(); - - return numBytesIncl; -} - - -/* - void I2CTransfer::processData(int numBytes) - Description: - ------------ - * Parses incoming serial data automatically when an - I2C frame is received - Inputs: - ------- - * int numBytes - Number of I2C bytes to read (ignored) - Return: - ------- - * void -*/ -void I2CTransfer::processData(int numBytes) -{ - uint8_t recChar; - classToUse->bytesRead = 0; - - while (classToUse->port->available()) - { - recChar = classToUse->port->read(); - classToUse->bytesRead = classToUse->packet.parse(recChar); - classToUse->status = classToUse->packet.status; - } -} - - -/* - uint8_t I2CTransfer::currentPacketID() - Description: - ------------ - * Returns the ID of the last parsed packet - Inputs: - ------- - * void - Return: - ------- - * uint8_t - ID of the last parsed packet -*/ -uint8_t I2CTransfer::currentPacketID() -{ - return packet.currentPacketID(); -} - - -I2CTransfer* I2CTransfer::classToUse = NULL; diff --git a/src/I2CTransfer.h b/src/I2CTransfer.h index cd79f26..80e6708 100644 --- a/src/I2CTransfer.h +++ b/src/I2CTransfer.h @@ -1,110 +1,7 @@ #pragma once -#include "Arduino.h" -#include "Packet.h" -#include "Wire.h" +#include -class I2CTransfer -{ - public: // <<---------------------------------------//public - Packet packet; - static I2CTransfer* classToUse; - uint8_t bytesRead = 0; - int8_t status = 0; +#include "StreamTransfer.h" - - I2CTransfer() - { - classToUse = this; - }; - void begin(TwoWire& _port, const configST configs); - void begin(TwoWire& _port, const bool _debug = true, Stream& _debugPort = Serial); - uint8_t sendData(const uint16_t& messageLen, const uint8_t& packetID = 0, const uint8_t& targetAddress = 0); - uint8_t currentPacketID(); - - - /* - uint16_t I2CTransfer::txObj(const T &val, const uint16_t &index=0, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Stuffs "len" number of bytes of an arbitrary object (byte, int, - float, double, struct, etc...) into the transmit buffer (txBuff) - starting at the index as specified by the argument "index" - Inputs: - ------- - * const T &val - Pointer to the object to be copied to the - transmit buffer (txBuff) - * const uint16_t &index - Starting index of the object within the - transmit buffer (txBuff) - * const uint16_t &len - Number of bytes of the object "val" to transmit - Return: - ------- - * uint16_t maxIndex - uint16_t maxIndex - Index of the transmit buffer (txBuff) that directly follows the bytes processed - by the calling of this member function - */ - template - uint16_t txObj(const T& val, const uint16_t& index = 0, const uint16_t& len = sizeof(T)) - { - return packet.txObj(val, index, len); - } - - - /* - uint16_t I2CTransfer::rxObj(const T &val, const uint16_t &index=0, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Reads "len" number of bytes from the receive buffer (rxBuff) - starting at the index as specified by the argument "index" - into an arbitrary object (byte, int, float, double, struct, etc...) - Inputs: - ------- - * const T &val - Pointer to the object to be copied into from the - receive buffer (rxBuff) - * const uint16_t &index - Starting index of the object within the - receive buffer (rxBuff) - * const uint16_t &len - Number of bytes in the object "val" received - Return: - ------- - * uint16_t maxIndex - Index of the receive buffer (rxBuff) that directly follows the bytes processed - by the calling of this member function - */ - template - uint16_t rxObj(const T& val, const uint16_t& index = 0, const uint16_t& len = sizeof(T)) - { - return packet.rxObj(val, index, len); - } - - - /* - uint8_t I2CTransfer::sendDatum(const T &val, const uint8_t &packetID=0, const uint8_t &targetAddress=0, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Stuffs "len" number of bytes of an arbitrary object (byte, int, - float, double, struct, etc...) into the transmit buffer (txBuff) - starting at the index as specified by the argument "index" and - automatically transmits the bytes in an individual packet - Inputs: - ------- - * const T &val - Pointer to the object to be copied to the - transmit buffer (txBuff) - * const uint8_t &packetID - The packet 8-bit identifier - * const uint8_t &targetAddress - I2C address to the device the packet - will be transmitted to - * const uint16_t &len - Number of bytes of the object "val" to transmit - Return: - ------- - * uint8_t - Number of payload bytes included in packet - */ - template - uint8_t sendDatum(const T& val, const uint8_t& packetID = 0, const uint8_t& targetAddress = 0, const uint16_t& len = sizeof(T)) - { - return sendData(packet.txObj(val, packetID, len), packetID, targetAddress); - } - - - private: // <<---------------------------------------//private - TwoWire* port; - - - static void processData(int numBytes); -}; +using I2CTransfer = StreamTransfer; diff --git a/src/Packet.cpp b/src/Packet.cpp index 1d5ed12..6d30470 100644 --- a/src/Packet.cpp +++ b/src/Packet.cpp @@ -1,61 +1,39 @@ #include "Packet.h" -PacketCRC crc; +Packet::Packet(bool debug) +{ + begin(debug); +} -/* - void Packet::begin(configST configs) - Description: - ------------ - * Advanced initializer for the Packet Class - Inputs: - ------- - * const configST configs - Struct that holds config - values for all possible initialization parameters - Return: - ------- - * void -*/ -void Packet::begin(const configST configs) +Packet::~Packet() { - debugPort = configs.debugPort; - debug = configs.debug; - callbacks = configs.callbacks; - callbacksLen = configs.callbacksLen; + CallbackNode* cur; + CallbackNode* toDel; + + while (cur != nullptr) + { + toDel = cur; + cur = cur->next; - // need to give the debug port a kick to get things working for some strange reason... - debugPort->println(); + delete toDel; + } } -/* - void Packet::begin(const bool _debug, Stream &_debugPort) - Description: - ------------ - * Simple initializer for the Packet Class - Inputs: - ------- - * const Stream &_port - Serial port to communicate over - * const bool _debug - Whether or not to print error messages - * const Stream &_debugPort - Serial port to print error messages - Return: - ------- - * void -*/ -void Packet::begin(const bool _debug, Stream& _debugPort) +void Packet::begin(bool debug) { - debugPort = &_debugPort; - debug = _debug; + this->debug = debug; } /* - uint8_t Packet::constructPacket(const uint16_t &messageLen, const uint8_t packetID) + uint8_t Packet::sendPacket(uint8_t packetID) Description: ------------ * Calculate, format, and insert the packet protocol metadata into the packet transmit - buffer + buffer, then send the packet. Inputs: ------- * const uint16_t &messageLen - Number of values in txBuff @@ -65,48 +43,40 @@ void Packet::begin(const bool _debug, Stream& _debugPort) ------- * uint8_t - Number of payload bytes included in packet */ -uint8_t Packet::constructPacket(const uint16_t& messageLen, const uint8_t packetID) +uint8_t Packet::sendPacket(uint8_t packetID) { - if (messageLen > MAX_PACKET_SIZE) - { - calcOverhead(txBuff, MAX_PACKET_SIZE); - stuffPacket(txBuff, MAX_PACKET_SIZE); - uint8_t crcVal = crc.calculate(txBuff, MAX_PACKET_SIZE); + // This should not happen but let's have this just to be save + if (bytesToSend > MAX_PACKET_SIZE) + bytesToSend = MAX_PACKET_SIZE; - preamble[1] = packetID; - preamble[2] = overheadByte; - preamble[3] = MAX_PACKET_SIZE; + // Construct the packet + const uint8_t overheadByte = stuffPacket(); + const size_t postambleOffset = bytesToSend + PREAMBLE_SIZE; + const uint8_t crcVal = PacketCRC<>::calculate(txBuff, bytesToSend); - postamble[0] = crcVal; + preamble[1] = packetID; + preamble[2] = overheadByte; + preamble[3] = bytesToSend; - return MAX_PACKET_SIZE; - } - else - { - calcOverhead(txBuff, (uint8_t)messageLen); - stuffPacket(txBuff, (uint8_t)messageLen); - uint8_t crcVal = crc.calculate(txBuff, (uint8_t)messageLen); + txRawBuff[postambleOffset] = crcVal; + txRawBuff[postambleOffset + 1] = STOP_BYTE; - preamble[1] = packetID; - preamble[2] = overheadByte; - preamble[3] = messageLen; + // Send it off + writeBytes(); - postamble[0] = crcVal; + uint8_t bytesSent = bytesToSend; + bytesToSend = 0; - return (uint8_t)messageLen; - } + return bytesSent; } /* - uint8_t Packet::parse(uint8_t recChar, bool valid) + uint8_t Packet::available() Description: ------------ * Parses incoming serial data, analyzes packet contents, - and reports errors/successful packet reception. Executes - callback functions for parsed packets whos ID has a - corresponding callback function set via - "void Packet::begin(const configST configs)" + and reports errors/successful packet reception Inputs: ------- * void @@ -114,149 +84,139 @@ uint8_t Packet::constructPacket(const uint16_t& messageLen, const uint8_t packet ------- * uint8_t - Num bytes in RX buffer */ -uint8_t Packet::parse(uint8_t recChar, bool valid) +uint8_t Packet::available() { - if (valid) + if (bytesAvailable()) { - switch (state) - { - case find_start_byte: ///////////////////////////////////////// - { - if (recChar == START_BYTE) - state = find_id_byte; - break; - } - - case find_id_byte: //////////////////////////////////////////// - { - idByte = recChar; - state = find_overhead_byte; - break; - } - - case find_overhead_byte: ////////////////////////////////////// + while (bytesAvailable()) { - recOverheadByte = recChar; - state = find_payload_len; - break; - } + uint8_t recChar = readByte(); - case find_payload_len: //////////////////////////////////////// - { - if (recChar <= MAX_PACKET_SIZE) + switch (state) { - bytesToRec = recChar; - state = find_payload; - } - else + case fsm::find_start_byte: ///////////////////////////////////////// { - bytesRead = 0; - state = find_start_byte; - status = PAYLOAD_ERROR; - - if (debug) - debugPort->println("ERROR: PAYLOAD_ERROR"); + if (recChar == START_BYTE) + state = fsm::find_id_byte; + break; + } - return bytesRead; + case fsm::find_id_byte: //////////////////////////////////////////// + { + idByte = recChar; + state = fsm::find_overhead_byte; + break; } - break; - } - case find_payload: //////////////////////////////////////////// - { - if (payIndex < bytesToRec) + case fsm::find_overhead_byte: ////////////////////////////////////// { - rxBuff[payIndex] = recChar; - payIndex++; + recOverheadByte = recChar; + state = fsm::find_payload_len; + break; + } - if (payIndex == bytesToRec) + case fsm::find_payload_len: //////////////////////////////////////// + { + if (recChar <= MAX_PACKET_SIZE) { - payIndex = 0; - state = find_crc; + bytesToRec = recChar; + state = fsm::find_payload; } + else + { + bytesRec = 0; + state = fsm::find_start_byte; + status = PAYLOAD_ERROR; + return 0; + } + break; } - break; - } - - case find_crc: /////////////////////////////////////////// - { - uint8_t calcCrc = crc.calculate(rxBuff, bytesToRec); - if (calcCrc == recChar) - state = find_end_byte; - else + case fsm::find_payload: //////////////////////////////////////////// { - bytesRead = 0; - state = find_start_byte; - status = CRC_ERROR; - - if (debug) - debugPort->println("ERROR: CRC_ERROR"); + if (payIndex < bytesToRec) + { + rxBuff[payIndex] = recChar; + payIndex++; - return bytesRead; + if (payIndex == bytesToRec) + { + payIndex = 0; + state = fsm::find_crc; + } + } + break; } - break; - } - - case find_end_byte: /////////////////////////////////////////// - { - state = find_start_byte; - - if (recChar == STOP_BYTE) + case fsm::find_crc: /////////////////////////////////////////// { - unpackPacket(rxBuff, bytesToRec); - bytesRead = bytesToRec; - status = NEW_DATA; + uint8_t calcCrc = PacketCRC<>::calculate(rxBuff, bytesToRec); - if (callbacks) + if (calcCrc == recChar) + state = fsm::find_end_byte; + else { - if (idByte < callbacksLen) - callbacks[idByte](); - else if (debug) - { - debugPort->print(F("ERROR: No callback available for packet ID ")); - debugPort->println(idByte); - } + bytesRec = 0; + state = fsm::find_start_byte; + status = CRC_ERROR; + return 0; } - return bytesToRec; + break; } - bytesRead = 0; - status = STOP_BYTE_ERROR; + case fsm::find_end_byte: /////////////////////////////////////////// + { + state = fsm::find_start_byte; - if (debug) - debugPort->println("ERROR: STOP_BYTE_ERROR"); + if (recChar == STOP_BYTE) + { + unpackPacket(); + bytesRec = bytesToRec; + bytesRead = 0; + status = NEW_DATA; - return bytesRead; - break; - } + callCallbacks(); - default: - { - if (debug) - { - debugPort->print("ERROR: Undefined state "); - debugPort->println(state); + return bytesToRec; + } + + bytesRec = 0; + status = STOP_BYTE_ERROR; + return 0; + break; } - bytesRead = 0; - state = find_start_byte; - break; - } + default: + { + if (debug) + { + printDebug("ERROR: Undefined state "); + } + + bytesRec = 0; + state = fsm::find_start_byte; + break; + } + } } } else { - bytesRead = 0; - status = NO_DATA; - return bytesRead; + bytesRec = 0; + status = NO_DATA; + return 0; } - bytesRead = 0; - status = CONTINUE; - return bytesRead; + bytesRec = 0; + status = CONTINUE; + return 0; +} + + +bool Packet::tick() +{ + return available() > 0; } @@ -272,66 +232,45 @@ uint8_t Packet::parse(uint8_t recChar, bool valid) ------- * uint8_t - ID of the last parsed packet */ -uint8_t Packet::currentPacketID() +uint8_t Packet::getPacketID() const { return idByte; } -/* - void Packet::calcOverhead(uint8_t arr[], const uint8_t &len) - Description: - ------------ - * Calculates the COBS (Consistent Overhead Stuffing) Overhead - byte and stores it in the class's overheadByte variable. This - variable holds the byte position (within the payload) of the - first payload byte equal to that of START_BYTE - Inputs: - ------- - * uint8_t arr[] - Array of values the overhead is to be calculated - over - * const uint8_t &len - Number of elements in arr[] - Return: - ------- - * void -*/ -void Packet::calcOverhead(uint8_t arr[], const uint8_t& len) +uint8_t Packet::getPacketSize() const +{ + return bytesRec; +} + + +ParserState Packet::getStatus() const +{ + return status; +} + + +void Packet::addCallback(CallbackFunc callback) { - overheadByte = 0xFF; + CallbackNode* newNode = new CallbackNode(callback); - for (uint8_t i = 0; i < len; i++) + if (callbacks == nullptr) { - if (arr[i] == START_BYTE) - { - overheadByte = i; - break; - } + callbacks = newNode; + return; } + + CallbackNode* cur = callbacks; + + while (cur->next != nullptr) + cur = cur->next; + + cur->next = newNode; } -/* - int16_t Packet::findLast(uint8_t arr[], const uint8_t &len) - Description: - ------------ - * Finds last instance of the value START_BYTE within the given - packet array - Inputs: - ------- - * uint8_t arr[] - Packet array - * const uint8_t &len - Number of elements in arr[] - Return: - ------- - * int16_t - Index of last instance of the value START_BYTE within the given - packet array -*/ -int16_t Packet::findLast(uint8_t arr[], const uint8_t& len) +void Packet::printDebug(const char* msg) const { - for (uint8_t i = (len - 1); i != 0xFF; i--) - if (arr[i] == START_BYTE) - return i; - - return -1; } @@ -349,21 +288,20 @@ int16_t Packet::findLast(uint8_t arr[], const uint8_t& len) ------- * void */ -void Packet::stuffPacket(uint8_t arr[], const uint8_t& len) +uint8_t Packet::stuffPacket() { - int16_t refByte = findLast(arr, len); + uint8_t lastPos = 0xFF; - if (refByte != -1) + for (uint8_t i = (bytesToSend - 1); i != 0xFF; i--) { - for (uint8_t i = (len - 1); i != 0xFF; i--) + if (txBuff[i] == START_BYTE) { - if (arr[i] == START_BYTE) - { - arr[i] = refByte - i; - refByte = i; - } + txBuff[i] = (lastPos == 0xFF) ? 0 : (lastPos - i); + lastPos = i; } } + + return lastPos; } @@ -380,19 +318,30 @@ void Packet::stuffPacket(uint8_t arr[], const uint8_t& len) ------- * void */ -void Packet::unpackPacket(uint8_t arr[], const uint8_t& len) +void Packet::unpackPacket() { uint8_t testIndex = recOverheadByte; uint8_t delta = 0; if (testIndex <= MAX_PACKET_SIZE) { - while (arr[testIndex]) + while (rxBuff[testIndex]) { - delta = arr[testIndex]; - arr[testIndex] = START_BYTE; + delta = rxBuff[testIndex]; + rxBuff[testIndex] = START_BYTE; testIndex += delta; } - arr[testIndex] = START_BYTE; + rxBuff[testIndex] = START_BYTE; + } +} + +void Packet::callCallbacks() +{ + CallbackNode* cur = callbacks; + + while (cur != nullptr) + { + cur->callback(*this); + cur = cur->next; } } diff --git a/src/Packet.h b/src/Packet.h index 9c6fa45..d7358c3 100644 --- a/src/Packet.h +++ b/src/Packet.h @@ -12,59 +12,50 @@ */ #pragma once -#include "Arduino.h" -#include "PacketCRC.h" - - -typedef void (*functionPtr)(); - -const int8_t CONTINUE = 3; -const int8_t NEW_DATA = 2; -const int8_t NO_DATA = 1; -const int8_t CRC_ERROR = 0; -const int8_t PAYLOAD_ERROR = -1; -const int8_t STOP_BYTE_ERROR = -2; +#include +#include -const uint8_t START_BYTE = 0x7E; -const uint8_t STOP_BYTE = 0x81; - -const uint8_t PREAMBLE_SIZE = 4; -const uint8_t POSTAMBLE_SIZE = 2; -const uint8_t MAX_PACKET_SIZE = 0xFE; // Maximum allowed payload bytes per packet -const uint8_t NUM_OVERHEAD = 6; // Delete +#include "PacketCRC.h" -struct configST +enum ParserState : int8_t { - Stream* debugPort = &Serial; - bool debug = true; - functionPtr* callbacks = NULL; - uint8_t callbacksLen = 0; + CONTINUE = 2, + NEW_DATA = 1, + NO_DATA = 0, + CRC_ERROR = -1, + PAYLOAD_ERROR = -2, + STOP_BYTE_ERROR = -3 }; +constexpr uint8_t START_BYTE = 0x7E; +constexpr uint8_t STOP_BYTE = 0x81; + +constexpr uint8_t PREAMBLE_SIZE = 4; +constexpr uint8_t POSTAMBLE_SIZE = 2; +constexpr uint8_t MAX_PACKET_SIZE = 0xFE; // Maximum allowed payload bytes per packet +constexpr uint8_t AUTO_INDEX = 0xFF; + class Packet { public: // <<---------------------------------------//public - uint8_t txBuff[MAX_PACKET_SIZE]; + typedef void (*CallbackFunc)(Packet&); + + + uint8_t (&txBuff)[MAX_PACKET_SIZE] = _txBuff; uint8_t rxBuff[MAX_PACKET_SIZE]; - uint8_t preamble[PREAMBLE_SIZE] = {START_BYTE, 0, 0, 0}; - uint8_t postamble[POSTAMBLE_SIZE] = {0, STOP_BYTE}; - uint8_t bytesRead = 0; - int8_t status = 0; + uint8_t bytesToSend = 0; + uint8_t bytesRead = 0; - void begin(const configST configs); - void begin(const bool _debug = true, Stream& _debugPort = Serial); - uint8_t constructPacket(const uint16_t& messageLen, const uint8_t packetID = 0); - uint8_t parse(uint8_t recChar, bool valid = true); - uint8_t currentPacketID(); + uint8_t sendPacket(uint8_t packetID = 0); /* - uint16_t Packet::txObj(const T &val, const uint16_t &index=0, const uint16_t &len=sizeof(T)) + uint16_t Packet::txObj(const T& val, size_t len = sizeof(T), uint8_t index = AUTO_INDEX) Description: ------------ * Stuffs "len" number of bytes of an arbitrary object (byte, int, @@ -85,28 +76,66 @@ class Packet by the calling of this member function */ template - uint16_t txObj(const T& val, const uint16_t& index = 0, const uint16_t& len = sizeof(T)) + uint8_t txObj(const T& val, size_t len = sizeof(T), uint8_t index = AUTO_INDEX) { - uint8_t* ptr = (uint8_t*)&val; - uint16_t maxIndex; + const uint8_t* ptr = reinterpret_cast(&val); + const uint8_t indexLimit = MAX_PACKET_SIZE; + uint8_t maxIndex; - if ((len + index) > MAX_PACKET_SIZE) - maxIndex = MAX_PACKET_SIZE; - else - maxIndex = len + index; + if (index == AUTO_INDEX) + index = bytesToSend; - for (uint16_t i = index; i < maxIndex; i++) - { - txBuff[i] = *ptr; - ptr++; - } + // Doing it like this makes sure that the comparison is done with the data type size_t instead of uint8_t, which could overflow! + maxIndex = ((len + index) > indexLimit) ? indexLimit : (len + index); + + for (uint8_t i = index; i < maxIndex; i++) + txBuff[i] = *(ptr++); + + if (bytesToSend < maxIndex) + bytesToSend = maxIndex; return maxIndex; } /* - uint16_t Packet::rxObj(const T &val, const uint16_t &index=0, const uint16_t &len=sizeof(T)) + uint8_t Packet::sendObj(const T& val, uint8_t packetID = 0, size_t len = sizeof(T)) + Description: + ------------ + * Stuffs "len" number of bytes of an arbitrary object (byte, int, + float, double, struct, etc...) into the transmit buffer (txBuff) + starting at the index as specified by the argument "index" and + automatically transmits the bytes in an individual packet + Inputs: + ------- + * const T &val - Pointer to the object to be copied to the + transmit buffer (txBuff) + * const uint16_t &len - Number of bytes of the object "val" to transmit + Return: + ------- + * uint8_t - Number of payload bytes included in packet + */ + template + uint8_t sendObj(const T& val, uint8_t packetID = 0, size_t len = sizeof(T)) + { + if (debug && (bytesToSend != 0)) + printDebug("Discarded existing data during call to Packet::sendObj!"); + + // Discard any other data + bytesToSend = 0; + txObj(val, len); + + return sendPacket(packetID); + } + + uint8_t available(); + bool tick(); + uint8_t getPacketID() const; + uint8_t getPacketSize() const; + + + /* + uint16_t Packet::rxObj(T& val, size_t len = sizeof(T), uint8_t index = AUTO_INDEX) Description: ------------ * Reads "len" number of bytes from the receive buffer (rxBuff) @@ -127,28 +156,50 @@ class Packet by the calling of this member function */ template - uint16_t rxObj(const T& val, const uint16_t& index = 0, const uint16_t& len = sizeof(T)) + uint8_t rxObj(T& val, size_t len = sizeof(T), uint8_t index = AUTO_INDEX) { - uint8_t* ptr = (uint8_t*)&val; - uint16_t maxIndex; + uint8_t* ptr = reinterpret_cast(&val); + const uint8_t indexLimit = bytesRec; + uint8_t maxIndex; - if ((len + index) > MAX_PACKET_SIZE) - maxIndex = MAX_PACKET_SIZE; - else - maxIndex = len + index; + if (index == AUTO_INDEX) + index = bytesRead; - for (uint16_t i = index; i < maxIndex; i++) - { - *ptr = rxBuff[i]; - ptr++; - } + // Doing it like this makes sure that the comparison is done with the data type size_t instead of uint8_t, which could overflow! + maxIndex = ((len + index) > indexLimit) ? indexLimit : (len + index); + + for (uint8_t i = index; i < maxIndex; i++) + *(ptr++) = rxBuff[i]; + + if (bytesRead < maxIndex) + bytesRead = maxIndex; return maxIndex; } + ParserState getStatus() const; - private: // <<---------------------------------------//private - enum fsm + void addCallback(CallbackFunc callback); + + + protected: // <<---------------------------------------//protected + Packet(bool debug = false); + virtual ~Packet(); + + void begin(bool debug = false); + + union + { + uint8_t txRawBuff[PREAMBLE_SIZE + MAX_PACKET_SIZE + POSTAMBLE_SIZE]; + struct + { + uint8_t preamble[PREAMBLE_SIZE] = {START_BYTE, 0, 0, 0}; + uint8_t _txBuff[MAX_PACKET_SIZE]; + // Postamble missing on purpose because it doesn't have a static position + } __attribute__((packed)); + }; + + enum class fsm { find_start_byte, find_id_byte, @@ -158,23 +209,39 @@ class Packet find_crc, find_end_byte }; - fsm state = find_start_byte; - functionPtr* callbacks = NULL; - uint8_t callbacksLen = 0; + ParserState status = NO_DATA; + fsm state = fsm::find_start_byte; + + // Vritual functions to override + virtual bool bytesAvailable() = 0; + virtual uint8_t readByte() = 0; + virtual void writeBytes() = 0; + virtual void printDebug(const char* msg) const; + + + private: // <<---------------------------------------//private + struct CallbackNode + { + CallbackNode* next; + const CallbackFunc callback; + + inline CallbackNode(CallbackFunc callback) : next(nullptr), callback(callback){}; + }; + + bool debug; - Stream* debugPort; - bool debug = false; + CallbackNode* callbacks = nullptr; + // Internal parser state + uint8_t bytesRec = 0; uint8_t bytesToRec = 0; uint8_t payIndex = 0; uint8_t idByte = 0; - uint8_t overheadByte = 0; uint8_t recOverheadByte = 0; - void calcOverhead(uint8_t arr[], const uint8_t& len); - int16_t findLast(uint8_t arr[], const uint8_t& len); - void stuffPacket(uint8_t arr[], const uint8_t& len); - void unpackPacket(uint8_t arr[], const uint8_t& len); + uint8_t stuffPacket(); + void unpackPacket(); + void callCallbacks(); }; diff --git a/src/PacketCRC.h b/src/PacketCRC.h index 43b1996..f04a4f8 100644 --- a/src/PacketCRC.h +++ b/src/PacketCRC.h @@ -1,76 +1,103 @@ #pragma once -#include "Arduino.h" +#include +#include + +template class PacketCRC { public: // <<---------------------------------------//public - uint8_t poly = 0; + static inline constexpr const uint8_t calculate(const uint8_t& val) + { + return (val < tableLen) ? crcTable[val] : 0; + } - PacketCRC(const uint8_t& polynomial = 0x9B, const uint8_t& crcLen = 8) + // This function can be constexpr in C++14 and above! + static inline +#if __cplusplus > 201103L + constexpr +#endif + const uint8_t + calculate(const uint8_t arr[], uint8_t len) { - poly = polynomial; - crcLen_ = crcLen; - tableLen_ = pow(2, crcLen); - csTable = new uint8_t[tableLen_]; + uint8_t crc = 0; + + for (uint8_t i = 0; i < len; i++) + crc = calculate(crc ^ arr[i]); - generateTable(); + return crc; } - void generateTable() + PacketCRC() = delete; + PacketCRC(const PacketCRC&) = delete; + PacketCRC(PacketCRC&&) = delete; + + + private: // <<---------------------------------------//private + // ============================================ + // Taken and adjusted from: https://github.com/BrainStone/CppCompiletimeArrayGenerator + template + struct Generator { - for (int i = 0; i < tableLen_; ++i) + static_assert(N > 0, "N must be greater than 0"); + + private: + template + struct Generator_impl { - int curr = i; - - for (int j = 0; j < 8; ++j) - { - if ((curr & 0x80) != 0) - curr = (curr << 1) ^ (int)poly; - else - curr <<= 1; - } - - csTable[i] = (byte)curr; - } - } + static constexpr const uint8_t (&value)[N] = Generator_impl::value; + }; - void printTable() - { - for (int i = 0; i < tableLen_; i++) + template + struct Generator_impl<0, Rest...> { - Serial.print(csTable[i], HEX); + static constexpr const uint8_t value[N] = {FUNC(0), Rest...}; + }; + + public: + static constexpr const uint8_t (&value)[N] = Generator_impl::value; + + Generator() = delete; + Generator(const Generator&) = delete; + Generator(Generator&&) = delete; + }; - if ((i + 1) % 16) - Serial.print(' '); - else - Serial.println(); - } - } - uint8_t calculate(const uint8_t& val) + // ============================================ + + + static inline constexpr uint8_t step(uint8_t curr) { - if (val < tableLen_) - return csTable[val]; - return 0; + return (curr << 1) ^ (((curr & 0x80) != 0) ? polynomial : 0); } - uint8_t calculate(uint8_t arr[], uint8_t len) + + static inline constexpr uint8_t step(uint8_t curr, size_t depth) { - uint8_t crc = 0; - for (uint16_t i = 0; i < len; i++) - crc = csTable[crc ^ arr[i]]; + return (depth > 1) ? step(step(curr), depth - 1) : step(curr); + } - return crc; + + static inline constexpr uint8_t generateValue(size_t index) + { + // No loops for C++11 constexpr functions + // Essentially we compute + // curr = (curr << 1) ^ (((curr & 0x80) != 0) ? polynomial : 0) + // 8 times + return step(static_cast(index), 8); } - private: // <<---------------------------------------//private - uint16_t tableLen_; - uint8_t crcLen_; - uint8_t* csTable; + static constexpr const uint16_t tableLen = 1 << crcLen; + static constexpr const uint8_t (&crcTable)[tableLen] = Generator::generateValue>::value; }; +template +constexpr const uint8_t (&PacketCRC::crcTable)[PacketCRC::tableLen]; -extern PacketCRC crc; +template +template +template +constexpr const uint8_t PacketCRC::Generator::Generator_impl<0, Rest...>::value[]; diff --git a/src/SPITransfer.cpp b/src/SPITransfer.cpp index 3321018..8e8c8fe 100644 --- a/src/SPITransfer.cpp +++ b/src/SPITransfer.cpp @@ -1,136 +1,62 @@ -#include "Arduino.h" +#include "SPITransfer.h" -#if not(defined(MBED_H) || defined(__SAM3X8E__)) // These boards are/will not be supported by SPITransfer.h +#if SPI_TRANSFER -#include "SPITransfer.h" + +SPITransfer::SPITransfer() +{ +} + + +SPITransfer::SPITransfer(SPIClass& port, uint8_t ssPin, Stream* debugPort) +{ + begin(port, ssPin, debugPort); +} -/* - void SPITransfer::begin(SPIClass &_port, configST configs, const uint8_t &_SS) - Description: - ------------ - * Advanced initializer for the SPITransfer Class - Inputs: - ------- - * const SPIClass &_port - SPI port to communicate over - * const configST configs - Struct that holds config - * const uint8_t &_SS - SPI buslave select pin used - values for all possible initialization parameters - Return: - ------- - * void -*/ -void SPITransfer::begin(SPIClass& _port, const configST configs, const uint8_t& _SS) +SPITransfer::SPITransfer(SPIClass& port, Stream& debugPort, uint8_t ssPin) { - port = &_port; - packet.begin(configs); - ssPin = _SS; + begin(port, debugPort, ssPin); } -/* - void SPITransfer::begin(SPIClass &_port, const uint8_t &_SS, const bool _debug, Stream &_debugPort) - Description: - ------------ - * Simple initializer for the SPITransfer Class - Inputs: - ------- - * const Stream &_port - SPI port to communicate over - * const uint8_t &_SS - SPI buslave select pin used - * const bool _debug - Whether or not to print error messages - * const Stream &_debugPort - Serial port to print error messages - Return: - ------- - * void -*/ -void SPITransfer::begin(SPIClass& _port, const uint8_t& _SS, const bool _debug, Stream& _debugPort) +void SPITransfer::begin(SPIClass& port, uint8_t ssPin, Stream* debugPort) { - port = &_port; - packet.begin(_debug, _debugPort); - ssPin = _SS; + this->port = &port; + this->ssPin = ssPin; + + StreamDebugPacket::begin(debugPort); } -/* - uint8_t SPITransfer::sendData(const uint16_t &messageLen, const uint8_t packetID) - Description: - ------------ - * Send a specified number of bytes in packetized form - Inputs: - ------- - * const uint16_t &messageLen - Number of values in txBuff - to send as the payload in the next packet - * const uint8_t packetID - The packet 8-bit identifier - Return: - ------- - * uint8_t numBytesIncl - Number of payload bytes included in packet -*/ -uint8_t SPITransfer::sendData(const uint16_t& messageLen, const uint8_t packetID) +void SPITransfer::begin(SPIClass& port, Stream& debugPort, uint8_t ssPin) { - uint8_t numBytesIncl = packet.constructPacket(messageLen, packetID); - - digitalWrite(SS, LOW); // Enable SS (active low) - for (uint8_t i = 0; i < sizeof(packet.preamble); i++) - { - delay(1); // This delay is needed - port->transfer(packet.preamble[i]); - } - - for (uint8_t i = 0; i < numBytesIncl; i++) - { - delay(1); // This delay is needed - port->transfer(packet.txBuff[i]); - } - - for (uint8_t i = 0; i < sizeof(packet.postamble); i++) - { - delay(1); // This delay is needed - port->transfer(packet.postamble[i]); - } - digitalWrite(SS, HIGH); // Disable SS (active low) - - return numBytesIncl; + begin(port, ssPin, &debugPort); } -/* - uint8_t SPITransfer::available() - Description: - ------------ - * Parses incoming serial data, analyzes packet contents, - and reports errors/successful packet reception - Inputs: - ------- - * void - Return: - ------- - * uint8_t bytesRead - Num bytes in RX buffer -*/ -uint8_t SPITransfer::available() +bool SPITransfer::bytesAvailable() { - volatile uint8_t recChar = SPDR; - bytesRead = packet.parse(recChar); - status = packet.status; + recByte = port->transfer(0x00); + + return (state != fsm::find_start_byte) || (recByte == START_BYTE); +} - return bytesRead; + +uint8_t SPITransfer::readByte() +{ + return recByte; } -/* - uint8_t SPITransfer::currentPacketID() - Description: - ------------ - * Returns the ID of the last parsed packet - Inputs: - ------- - * void - Return: - ------- - * uint8_t - ID of the last parsed packet -*/ -uint8_t SPITransfer::currentPacketID() +void SPITransfer::writeBytes() { - return packet.currentPacketID(); + digitalWrite(ssPin, LOW); // Enable SS (active low) + delayMicroseconds(1); + + port->transfer(txRawBuff, PREAMBLE_SIZE + bytesToSend + POSTAMBLE_SIZE); + + digitalWrite(ssPin, HIGH); // Disable SS (active low) } -#endif // not (defined(MBED_H) || defined(__SAM3X8E__)) +#endif // SPI_TRANSFER diff --git a/src/SPITransfer.h b/src/SPITransfer.h index 68a991a..63621c2 100644 --- a/src/SPITransfer.h +++ b/src/SPITransfer.h @@ -1,107 +1,44 @@ #pragma once -#include "Arduino.h" +#include -#if not(defined(MBED_H) || defined(__SAM3X8E__)) // These boards are/will not be supported by SPITransfer.h +// You can forcefully enable or disable SPITransfer by defining this to 1 or 0 respectively +#ifndef SPI_TRANSFER +// These boards are/will not be supported by SPITransfer.h +#if defined(MBED_H) || defined(__SAM3X8E__) || defined(ESP8266) +#define SPI_TRANSFER 0 +#else +#define SPI_TRANSFER 1 +#endif +#endif // ndef SPI_TRANSFER -#include "Packet.h" -#include "SPI.h" +#if SPI_TRANSFER +#include -class SPITransfer -{ - public: // <<---------------------------------------//public - Packet packet; - uint8_t bytesRead = 0; - int8_t status = 0; - - - void begin(SPIClass& _port, const configST configs, const uint8_t& _SS = SS); - void begin(SPIClass& _port, const uint8_t& _SS = SS, const bool _debug = true, Stream& _debugPort = Serial); - uint8_t sendData(const uint16_t& messageLen, const uint8_t packetID = 0); - uint8_t available(); - uint8_t currentPacketID(); - +#include "StreamDebugPacket.h" - /* - uint16_t SPITransfer::txObj(const T &val, const uint16_t &index=0, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Stuffs "len" number of bytes of an arbitrary object (byte, int, - float, double, struct, etc...) into the transmit buffer (txBuff) - starting at the index as specified by the argument "index" - Inputs: - ------- - * const T &val - Pointer to the object to be copied to the - transmit buffer (txBuff) - * const uint16_t &index - Starting index of the object within the - transmit buffer (txBuff) - * const uint16_t &len - Number of bytes of the object "val" to transmit - Return: - ------- - * uint16_t maxIndex - uint16_t maxIndex - Index of the transmit buffer (txBuff) that directly follows the bytes processed - by the calling of this member function - */ - template - uint16_t txObj(const T& val, const uint16_t& index = 0, const uint16_t& len = sizeof(T)) - { - return packet.txObj(val, index, len); - } - - - /* - uint16_t SPITransfer::rxObj(const T &val, const uint16_t &index=0, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Reads "len" number of bytes from the receive buffer (rxBuff) - starting at the index as specified by the argument "index" - into an arbitrary object (byte, int, float, double, struct, etc...) - Inputs: - ------- - * const T &val - Pointer to the object to be copied into from the - receive buffer (rxBuff) - * const uint16_t &index - Starting index of the object within the - receive buffer (rxBuff) - * const uint16_t &len - Number of bytes in the object "val" received - Return: - ------- - * uint16_t maxIndex - Index of the receive buffer (rxBuff) that directly follows the bytes processed - by the calling of this member function - */ - template - uint16_t rxObj(const T& val, const uint16_t& index = 0, const uint16_t& len = sizeof(T)) - { - return packet.rxObj(val, index, len); - } +class SPITransfer : public StreamDebugPacket +{ + public: // <<---------------------------------------//public + SPITransfer(); + SPITransfer(SPIClass& port, uint8_t ssPin = SS, Stream* debugPort = nullptr); + SPITransfer(SPIClass& port, Stream& debugPort, uint8_t ssPin = SS); - /* - uint8_t SPITransfer::sendDatum(const T &val, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Stuffs "len" number of bytes of an arbitrary object (byte, int, - float, double, struct, etc...) into the transmit buffer (txBuff) - starting at the index as specified by the argument "index" and - automatically transmits the bytes in an individual packet - Inputs: - ------- - * const T &val - Pointer to the object to be copied to the - transmit buffer (txBuff) - * const uint16_t &len - Number of bytes of the object "val" to transmit - Return: - ------- - * uint8_t - Number of payload bytes included in packet - */ - template - uint8_t sendDatum(const T& val, const uint16_t& len = sizeof(T)) - { - return sendData(packet.txObj(val, 0, len)); - } + void begin(SPIClass& port, uint8_t ssPin = SS, Stream* debugPort = nullptr); + void begin(SPIClass& port, Stream& debugPort, uint8_t ssPin = SS); + protected: // <<---------------------------------------//protected + // Vritual functions to override + virtual bool bytesAvailable(); + virtual uint8_t readByte(); + virtual void writeBytes(); private: // <<---------------------------------------//private SPIClass* port; uint8_t ssPin; + uint8_t recByte; }; -#endif // not (defined(MBED_H) || defined(__SAM3X8E__)) +#endif // SPI_TRANSFER diff --git a/src/SerialTransfer.cpp b/src/SerialTransfer.cpp deleted file mode 100644 index a8879b9..0000000 --- a/src/SerialTransfer.cpp +++ /dev/null @@ -1,151 +0,0 @@ -#include "SerialTransfer.h" - - -/* - void SerialTransfer::begin(Stream &_port, configST configs) - Description: - ------------ - * Advanced initializer for the SerialTransfer Class - Inputs: - ------- - * const Stream &_port - Serial port to communicate over - * const configST configs - Struct that holds config - values for all possible initialization parameters - Return: - ------- - * void -*/ -void SerialTransfer::begin(Stream& _port, const configST configs) -{ - port = &_port; - packet.begin(configs); -} - - -/* - void SerialTransfer::begin(Stream &_port, const bool _debug, Stream &_debugPort) - Description: - ------------ - * Simple initializer for the SerialTransfer Class - Inputs: - ------- - * const Stream &_port - Serial port to communicate over - * const bool _debug - Whether or not to print error messages - * const Stream &_debugPort - Serial port to print error messages - Return: - ------- - * void -*/ -void SerialTransfer::begin(Stream& _port, const bool _debug, Stream& _debugPort) -{ - port = &_port; - packet.begin(_debug, _debugPort); -} - - -/* - uint8_t SerialTransfer::sendData(const uint16_t &messageLen, const uint8_t packetID) - Description: - ------------ - * Send a specified number of bytes in packetized form - Inputs: - ------- - * const uint16_t &messageLen - Number of values in txBuff - to send as the payload in the next packet - * const uint8_t packetID - The packet 8-bit identifier - Return: - ------- - * uint8_t numBytesIncl - Number of payload bytes included in packet -*/ -uint8_t SerialTransfer::sendData(const uint16_t& messageLen, const uint8_t packetID) -{ - uint8_t numBytesIncl; - - numBytesIncl = packet.constructPacket(messageLen, packetID); - port->write(packet.preamble, sizeof(packet.preamble)); - port->write(packet.txBuff, numBytesIncl); - port->write(packet.postamble, sizeof(packet.postamble)); - - return numBytesIncl; -} - - -/* - uint8_t SerialTransfer::available() - Description: - ------------ - * Parses incoming serial data, analyzes packet contents, - and reports errors/successful packet reception - Inputs: - ------- - * void - Return: - ------- - * uint8_t bytesRead - Num bytes in RX buffer -*/ -uint8_t SerialTransfer::available() -{ - bool valid = false; - uint8_t recChar = 0xFF; - - if (port->available()) - { - valid = true; - - while (port->available()) - { - recChar = port->read(); - - bytesRead = packet.parse(recChar, valid); - status = packet.status; - } - } - else - { - bytesRead = packet.parse(recChar, valid); - status = packet.status; - } - - return bytesRead; -} - - -/* - bool SerialTransfer::tick() - Description: - ------------ - * Checks to see if any packets have been fully parsed. This - is basically a wrapper around the method "available()" and - is used primarily in conjunction with callbacks - Inputs: - ------- - * void - Return: - ------- - * bool - Whether or not a full packet has been parsed -*/ -bool SerialTransfer::tick() -{ - if (available()) - return true; - - return false; -} - - -/* - uint8_t SerialTransfer::currentPacketID() - Description: - ------------ - * Returns the ID of the last parsed packet - Inputs: - ------- - * void - Return: - ------- - * uint8_t - ID of the last parsed packet -*/ -uint8_t SerialTransfer::currentPacketID() -{ - return packet.currentPacketID(); -} diff --git a/src/SerialTransfer.h b/src/SerialTransfer.h index 79c6756..6a207a9 100644 --- a/src/SerialTransfer.h +++ b/src/SerialTransfer.h @@ -1,100 +1,9 @@ #pragma once -#include "Arduino.h" -#include "Packet.h" +// Using HardwareSerial.h because it's more portable +// Feel free to include Serial.h in your source files if you need it +#include -class SerialTransfer -{ - public: // <<---------------------------------------//public - Packet packet; - uint8_t bytesRead = 0; - int8_t status = 0; +#include "StreamTransfer.h" - - void begin(Stream& _port, const configST configs); - void begin(Stream& _port, const bool _debug = true, Stream& _debugPort = Serial); - uint8_t sendData(const uint16_t& messageLen, const uint8_t packetID = 0); - uint8_t available(); - bool tick(); - uint8_t currentPacketID(); - - - /* - uint16_t SerialTransfer::txObj(const T &val, const uint16_t &index=0, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Stuffs "len" number of bytes of an arbitrary object (byte, int, - float, double, struct, etc...) into the transmit buffer (txBuff) - starting at the index as specified by the argument "index" - Inputs: - ------- - * const T &val - Pointer to the object to be copied to the - transmit buffer (txBuff) - * const uint16_t &index - Starting index of the object within the - transmit buffer (txBuff) - * const uint16_t &len - Number of bytes of the object "val" to transmit - Return: - ------- - * uint16_t maxIndex - uint16_t maxIndex - Index of the transmit buffer (txBuff) that directly follows the bytes processed - by the calling of this member function - */ - template - uint16_t txObj(const T& val, const uint16_t& index = 0, const uint16_t& len = sizeof(T)) - { - return packet.txObj(val, index, len); - } - - - /* - uint16_t SerialTransfer::rxObj(const T &val, const uint16_t &index=0, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Reads "len" number of bytes from the receive buffer (rxBuff) - starting at the index as specified by the argument "index" - into an arbitrary object (byte, int, float, double, struct, etc...) - Inputs: - ------- - * const T &val - Pointer to the object to be copied into from the - receive buffer (rxBuff) - * const uint16_t &index - Starting index of the object within the - receive buffer (rxBuff) - * const uint16_t &len - Number of bytes in the object "val" received - Return: - ------- - * uint16_t maxIndex - Index of the receive buffer (rxBuff) that directly follows the bytes processed - by the calling of this member function - */ - template - uint16_t rxObj(const T& val, const uint16_t& index = 0, const uint16_t& len = sizeof(T)) - { - return packet.rxObj(val, index, len); - } - - - /* - uint8_t SerialTransfer::sendDatum(const T &val, const uint16_t &len=sizeof(T)) - Description: - ------------ - * Stuffs "len" number of bytes of an arbitrary object (byte, int, - float, double, struct, etc...) into the transmit buffer (txBuff) - starting at the index as specified by the argument "index" and - automatically transmits the bytes in an individual packet - Inputs: - ------- - * const T &val - Pointer to the object to be copied to the - transmit buffer (txBuff) - * const uint16_t &len - Number of bytes of the object "val" to transmit - Return: - ------- - * uint8_t - Number of payload bytes included in packet - */ - template - uint8_t sendDatum(const T& val, const uint16_t& len = sizeof(T)) - { - return sendData(packet.txObj(val, 0, len)); - } - - - private: // <<---------------------------------------//private - Stream* port; -}; +using SerialTransfer = StreamTransfer; diff --git a/src/StreamDebugPacket.cpp b/src/StreamDebugPacket.cpp new file mode 100644 index 0000000..62339c4 --- /dev/null +++ b/src/StreamDebugPacket.cpp @@ -0,0 +1,30 @@ +#include "StreamDebugPacket.h" + +StreamDebugPacket::StreamDebugPacket() +{ +} + + +StreamDebugPacket::StreamDebugPacket(Stream* debugPort) +{ + begin(debugPort); +} + + +void StreamDebugPacket::begin(Stream* debugPort) +{ + this->debugPort = debugPort; + // need to give the debug port a kick to get things working for some strange reason... + debugPort->println(); + + Packet::begin(debugPort != nullptr); +} + + +void StreamDebugPacket::printDebug(const char* msg) const +{ + if (debugPort == nullptr) + return; + + debugPort->println(msg); +} diff --git a/src/StreamDebugPacket.h b/src/StreamDebugPacket.h new file mode 100644 index 0000000..6fc0704 --- /dev/null +++ b/src/StreamDebugPacket.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "Packet.h" + + +class StreamDebugPacket : public Packet +{ + protected: // <<---------------------------------------//protected + StreamDebugPacket(); + StreamDebugPacket(Stream* debugPort); + + void begin(Stream* debugPort = nullptr); + + virtual void printDebug(const char* msg) const; + + private: // <<---------------------------------------//private + Stream* debugPort; +}; diff --git a/src/StreamTransfer.cpp b/src/StreamTransfer.cpp new file mode 100644 index 0000000..668fef7 --- /dev/null +++ b/src/StreamTransfer.cpp @@ -0,0 +1,49 @@ +#include "StreamTransfer.h" + +StreamTransfer::StreamTransfer() +{ +} + + +StreamTransfer::StreamTransfer(Stream& port, Stream* debugPort) +{ + begin(port, debugPort); +} + + +StreamTransfer::StreamTransfer(Stream& port, Stream& debugPort) +{ + begin(port, debugPort); +} + + +void StreamTransfer::begin(Stream& port, Stream* debugPort) +{ + this->port = &port; + + StreamDebugPacket::begin(debugPort); +} + + +void StreamTransfer::begin(Stream& port, Stream& debugPort) +{ + begin(port, &debugPort); +} + + +bool StreamTransfer::bytesAvailable() +{ + return port->available(); +} + + +uint8_t StreamTransfer::readByte() +{ + return port->read(); +} + + +void StreamTransfer::writeBytes() +{ + port->write(txRawBuff, PREAMBLE_SIZE + bytesToSend + POSTAMBLE_SIZE); +} diff --git a/src/StreamTransfer.h b/src/StreamTransfer.h new file mode 100644 index 0000000..fe5a638 --- /dev/null +++ b/src/StreamTransfer.h @@ -0,0 +1,24 @@ +#pragma once + +#include "StreamDebugPacket.h" + + +class StreamTransfer : public StreamDebugPacket +{ + public: // <<---------------------------------------//public + StreamTransfer(); + StreamTransfer(Stream& port, Stream* debugPort = nullptr); + StreamTransfer(Stream& port, Stream& debugPort); + + void begin(Stream& port, Stream* debugPort = nullptr); + void begin(Stream& port, Stream& debugPort); + + protected: // <<---------------------------------------//protected + // Vritual functions to override + virtual bool bytesAvailable(); + virtual uint8_t readByte(); + virtual void writeBytes(); + + private: // <<---------------------------------------//private + Stream* port; +};