From 6f375eafb69cc5577b6290eebe759cd907315b99 Mon Sep 17 00:00:00 2001 From: "Pawel Spychalski (DzikuVx)" Date: Sat, 23 Sep 2017 20:44:27 +0200 Subject: [PATCH] QSP protocol implementation --- .vscode/arduino.json | 6 ++ .vscode/c_cpp_properties.json | 21 +++++ common.h | 18 ++++ crossbow.ino | 191 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 236 insertions(+) create mode 100644 .vscode/arduino.json create mode 100644 .vscode/c_cpp_properties.json create mode 100644 common.h create mode 100644 crossbow.ino diff --git a/.vscode/arduino.json b/.vscode/arduino.json new file mode 100644 index 0000000..b4fef73 --- /dev/null +++ b/.vscode/arduino.json @@ -0,0 +1,6 @@ +{ + "board": "arduino:avr:pro", + "configuration": "cpu=16MHzatmega328", + "sketch": "crossbow.ino", + "port": "COM5" +} \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..84e0a78 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,21 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "C:\\Users\\pspyc\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.6.19\\cores\\arduino", + "C:\\Users\\pspyc\\Documents\\Arduino\\libraries\\PPMReader" + ], + "browse": { + "limitSymbolsToIncludedHeaders": false, + "path": [ + "C:\\Users\\pspyc\\AppData\\Local\\Arduino15\\packages\\arduino\\hardware\\avr\\1.6.19\\cores\\arduino", + "${workspaceRoot}", + "C:\\Users\\pspyc\\Documents\\Arduino\\libraries\\PPMReader" + ] + }, + "intelliSenseMode": "msvc-x64" + } + ], + "version": 3 +} \ No newline at end of file diff --git a/common.h b/common.h new file mode 100644 index 0000000..bea1695 --- /dev/null +++ b/common.h @@ -0,0 +1,18 @@ +//Only for UART connected radio modules +#define UART_SPEED 57600 + +#define CHANNEL_ID 0x01 +#define QSP_PREAMBLE 0x51 +#define QSP_PAYLOAD_LENGTH 32 + +#define PIN_LED 13 + +enum dataStates { + IDLE, + PREAMBLE_RECEIVED, + CHANNEL_RECEIVED, + FRAME_TYPE_RECEIVED, + PACKET_ID_RECEIVED, + PAYLOAD_RECEIVED, + CRC_RECEIVED +}; \ No newline at end of file diff --git a/crossbow.ino b/crossbow.ino new file mode 100644 index 0000000..3c68fee --- /dev/null +++ b/crossbow.ino @@ -0,0 +1,191 @@ +// #define DEVICE_MODE_TX +#define DEVICE_MODE_RX + +#ifdef DEVICE_MODE_TX + +/* + * Main defines for device working in TX mode + */ + +#include + +#define PPM_INPUT_PIN 2 +#define PPM_INPUT_INTERRUPT 0 + +PPMReader ppmReader(PPM_INPUT_PIN, PPM_INPUT_INTERRUPT); + +#endif + +#ifdef DEVICE_MODE_RX + +#include + +#define OLED_RESET 4 +Adafruit_SSD1306 display(OLED_RESET); + +#endif + +static uint8_t protocolState = IDLE; +static uint8_t packetId = 0; +static uint8_t qspCrc = 0; +static uint8_t qspPayload[QSP_PAYLOAD_LENGTH] = {0}; + +void writeToRadio(uint8_t dataByte) { + //Compute CRC + qspCrc ^= dataByte; + + //Write to radio + Serial.write(dataByte); +} + +void decodeIncomingQspFrame(uint8_t incomingByte) { + + static uint8_t frameId; + static uint8_t payloadLength; + static uint8_t receivedPayload; + static uint8_t packetId; //TODO move this to global scope maybe? + + if (protocolState == IDLE && incomingByte == QSP_PREAMBLE) { + //If in IDLE and correct preamble comes, start to decode frame + protocolState = PREAMBLE_RECEIVED; + qspCrc = 0 ^ incomingByte; + } else if (protocolState == PREAMBLE_RECEIVED) { + // Check if incomming channel ID is the same as receiver + if (incomingByte == CHANNEL_ID) { + protocolState = CHANNEL_RECEIVED; + qspCrc ^= incomingByte; + + for (uint8_t i = 0; i < QSP_PAYLOAD_LENGTH; i++) { + qspPayload[i] = 0x00; + } + + receivedPayload = 0; + packetId = 0; + } else { + protocolState = IDLE; + } + } else if (protocolState == CHANNEL_RECEIVED) { + //Frame ID and payload length + qspCrc ^= incomingByte; + + frameId = (incomingByte >> 4) & 0x0f; + payloadLength = incomingByte & 0x0f; + + protocolState = FRAME_TYPE_RECEIVED; + + } else if (protocolState == FRAME_TYPE_RECEIVED) { + qspCrc ^= incomingByte; + packetId = incomingByte; + protocolState = PACKET_ID_RECEIVED; + } else if (protocolState == PACKET_ID_RECEIVED) { + + //Now it's time for payload + qspCrc ^= incomingByte; + qspPayload[receivedPayload] = incomingByte; + + receivedPayload++; + + if (receivedPayload == payloadLength) { + protocolState = PAYLOAD_RECEIVED; + } + + } else if (protocolState == PAYLOAD_RECEIVED) { + + if (qspCrc == incomingByte) { + display.clearDisplay(); + display.setCursor(0, 0); + display.print(qspPayload[0]); + + display.setCursor(0, 10); + display.print(qspPayload[1]); + + display.setCursor(0, 20); + display.print(qspPayload[2]); + + display.setCursor(0, 30); + display.print(qspPayload[3]); + + display.display(); + } else { + + display.clearDisplay(); + display.setCursor(0, 0); + display.print("CRC failed"); + display.display(); + + } + + protocolState = IDLE; + } + +} + +uint8_t getPacketId() { + return packetId++; +} + +void encodeQspFrame(uint8_t frameId, uint8_t length, uint8_t *payload) { + //Zero CRC + qspCrc = 0; + + //Write preamble + writeToRadio(QSP_PREAMBLE); + //Write CHANNEL_ID + writeToRadio(CHANNEL_ID); + + //Write frame type and length + uint8_t data = length & 0x0f; + data |= (frameId << 4) & 0xf0; + writeToRadio(data); + + //Write packet ID + writeToRadio(getPacketId()); + + //Write payload + for (uint8_t i = 0; i < length; i++) { + writeToRadio(payload[i]); + } + + //Finally write CRC + writeToRadio(qspCrc); +} + +void setup(void) { + Serial.begin(UART_SPEED); + +#ifdef DEVICE_MODE_RX + pinMode(PIN_LED, OUTPUT); + + /* + * Initialize OLED display + */ + display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x32) + display.setTextSize(1); + display.setTextColor(WHITE); + display.clearDisplay(); + display.display(); + +#endif +} + +void loop(void) { + +#ifdef DEVICE_MODE_TX + uint8_t pp[4] = {0x41, 0x42, 0x43, 0x44}; + + encodeQspFrame(0x01, 0x04, pp); + + Serial.end(); + delay(30); + Serial.begin(UART_SPEED); + delay(1000); +#endif + +#ifdef DEVICE_MODE_RX + + if (Serial.available()) { + decodeIncomingQspFrame(Serial.read()); + } + +#endif +} \ No newline at end of file