From a48497365de2069f8af5a971f6db8d377fb08b39 Mon Sep 17 00:00:00 2001 From: Pawel Spychalski Date: Wed, 16 May 2018 11:01:00 +0200 Subject: [PATCH 1/8] part 1 --- crossbow/crossbow.ino | 62 +++++++++++-------------------------------------- crossbow/qsp.cpp | 4 ++-- crossbow/qsp.h | 2 +- crossbow/radio_node.cpp | 53 ++++++++++++++++++++++++++++++++++++++++++ crossbow/radio_node.h | 55 +++++++++++++++++++++++++++++++++++++++++++ crossbow/variables.h | 34 +-------------------------- 6 files changed, 125 insertions(+), 85 deletions(-) create mode 100644 crossbow/radio_node.cpp create mode 100644 crossbow/radio_node.h diff --git a/crossbow/crossbow.ino b/crossbow/crossbow.ino index 643e353..6e17397 100644 --- a/crossbow/crossbow.ino +++ b/crossbow/crossbow.ino @@ -13,6 +13,7 @@ Copyright (c) 20xx, MPL Contributor1 contrib1@example.net #include "main_variables.h" #include "qsp.h" #include "sbus.h" +#include "radio_node.h" #ifdef ARDUINO_AVR_FEATHER32U4 #define LORA_SS_PIN 8 @@ -32,6 +33,8 @@ Copyright (c) 20xx, MPL Contributor1 contrib1@example.net #error please select hardware #endif +volatile RadioNode radioNode; + /* * Main defines for device working in TX mode */ @@ -87,57 +90,18 @@ volatile RadioState_t radioState = {}; uint8_t tmpBuffer[MAX_PACKET_SIZE]; -uint8_t getRadioRssi(void) -{ - return 164 - constrain(LoRa.packetRssi() * -1, 0, 164); -} - -uint8_t getRadioSnr(void) -{ - return (uint8_t) constrain(LoRa.packetSnr(), 0, 255); -} - -uint32_t getFrequencyForChannel(uint8_t channel) { - return RADIO_FREQUENCY_MIN + (RADIO_CHANNEL_WIDTH * channel); -} - -uint8_t getNextChannel(uint8_t channel) { - return (channel + RADIO_HOP_OFFSET) % RADIO_CHANNEL_COUNT; -} - -uint8_t getPrevChannel(uint8_t channel) { - return (RADIO_CHANNEL_COUNT + channel - RADIO_HOP_OFFSET) % RADIO_CHANNEL_COUNT; -} - -void hopFrequency(volatile RadioState_t *radioState, bool forward, uint8_t fromChannel, uint32_t timestamp) { - radioState->channelEntryMillis = timestamp; - - if (forward) { - radioState->channel = getNextChannel(fromChannel); - } else { - radioState->channel = getPrevChannel(fromChannel); - } - - // And set hardware - LoRa.sleep(); - LoRa.setFrequency( - getFrequencyForChannel(radioState->channel) - ); - LoRa.idle(); -} - void onQspSuccess(QspConfiguration_t *qsp, TxDeviceState_t *txDeviceState, RxDeviceState_t *rxDeviceState, volatile RadioState_t *radioState) { //If recide received a valid frame, that means it can start to talk qsp->canTransmit = true; - radioState->rssi = getRadioRssi(); - radioState->snr = getRadioSnr(); + radioState->rssi = radioNode.getRadioRssi(); + radioState->snr = radioNode.getRadioSnr(); /* * RX module hops to next channel after frame has been received */ #ifdef DEVICE_MODE_RX - hopFrequency(radioState, true, radioState->lastReceivedChannel, millis()); + radioNode.hopFrequency(true, radioState->lastReceivedChannel, millis()); radioState->failedDwellsCount = 0; // We received a frame, so we can just reset this counter LoRa.receive(); //Put radio back into receive mode #endif @@ -206,7 +170,7 @@ void setup(void) LORA_DI0_PIN ); - if (!LoRa.begin(getFrequencyForChannel(radioState.channel))) { + if (!LoRa.begin(radioNode.getFrequencyForChannel(radioNode.getChannel()))) { while (true); } @@ -384,15 +348,15 @@ void loop(void) #ifdef DEVICE_MODE_RX //In the beginning just keep jumping forward and try to resync over lost single frames - if (radioState.failedDwellsCount < 6 && radioState.channelEntryMillis + RX_CHANNEL_DWELL_TIME < currentMillis) { + if (radioState.failedDwellsCount < 6 && radioNode.getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME < currentMillis) { radioState.failedDwellsCount++; - hopFrequency(&radioState, true, radioState.channel, radioState.channelEntryMillis + RX_CHANNEL_DWELL_TIME); + radioNode.hopFrequency(true, radioNode.getChannel(), radioNode.getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME); LoRa.receive(); } // If we are loosing more frames, start jumping in the opposite direction since probably we are completely out of sync now - if (radioState.failedDwellsCount >= 6 && radioState.channelEntryMillis + (RX_CHANNEL_DWELL_TIME * 5) < currentMillis) { - hopFrequency(&radioState, false, radioState.channel, radioState.channelEntryMillis + RX_CHANNEL_DWELL_TIME); //Start jumping in opposite direction to resync + if (radioState.failedDwellsCount >= 6 && radioNode.getChannelEntryMillis() + (RX_CHANNEL_DWELL_TIME * 5) < currentMillis) { + radioNode.hopFrequency(false, radioNode.getChannel(), radioNode.getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME); //Start jumping in opposite direction to resync LoRa.receive(); } @@ -412,7 +376,7 @@ void loop(void) * In case of TX module, hop right now */ #ifdef DEVICE_MODE_TX - hopFrequency(&radioState, true, radioState.channel, millis()); + radioNode.hopFrequency(true, radioNode.getChannel(), millis()); #endif LoRa.receive(); @@ -566,7 +530,7 @@ void loop(void) uint8_t size; LoRa.beginPacket(); //Prepare packet - qspEncodeFrame(&qsp, &radioState, tmpBuffer, &size); + qspEncodeFrame(&qsp, &radioState, tmpBuffer, &size, radioNode.getChannel()); //Sent it to radio in one SPI transaction LoRa.write(tmpBuffer, size); LoRa.endPacketAsync(); diff --git a/crossbow/qsp.cpp b/crossbow/qsp.cpp index 90a8186..90982be 100644 --- a/crossbow/qsp.cpp +++ b/crossbow/qsp.cpp @@ -224,14 +224,14 @@ void qspDecodeIncomingFrame( /** * Encode frame is corrent format and write to hardware */ -void qspEncodeFrame(QspConfiguration_t *qsp, volatile RadioState_t *radioState, uint8_t buffer[], uint8_t *size) { +void qspEncodeFrame(QspConfiguration_t *qsp, volatile RadioState_t *radioState, uint8_t buffer[], uint8_t *size, uint8_t radioChannel) { //Salt CRC with bind key qspInitCrc(qsp); //Write frame type and length // We are no longer sending payload length, so 4 bits are now free for other usages // uint8_t data = qsp->payloadLength & 0x0f; - uint8_t data = radioState->channel; + uint8_t data = radioChannel; data |= (qsp->frameToSend << 4) & 0xf0; qspComputeCrc(qsp, data); buffer[0] = data; diff --git a/crossbow/qsp.h b/crossbow/qsp.h index 60eff2a..74e28d3 100644 --- a/crossbow/qsp.h +++ b/crossbow/qsp.h @@ -16,6 +16,6 @@ void qspDecodeIncomingFrame( volatile RadioState_t *radioState ); void qspClearPayload(QspConfiguration_t *qsp); -void qspEncodeFrame(QspConfiguration_t *qsp, volatile RadioState_t *radioState, uint8_t buffer[], uint8_t *size); +void qspEncodeFrame(QspConfiguration_t *qsp, volatile RadioState_t *radioState, uint8_t buffer[], uint8_t *size, uint8_t radioChannel); void encodePingPayload(QspConfiguration_t *qsp, uint32_t currentMicros); \ No newline at end of file diff --git a/crossbow/radio_node.cpp b/crossbow/radio_node.cpp new file mode 100644 index 0000000..5da105f --- /dev/null +++ b/crossbow/radio_node.cpp @@ -0,0 +1,53 @@ +#include "radio_node.h" +#include "lora.h" + +RadioNode::RadioNode(void) { + +} + +static uint8_t RadioNode::getRadioRssi(void) +{ + return 164 - constrain(LoRa.packetRssi() * -1, 0, 164); +} + +static uint8_t RadioNode::getRadioSnr(void) +{ + return (uint8_t) constrain(LoRa.packetSnr(), 0, 255); +} + +uint8_t RadioNode::getChannel(void) { + return _channel; +} + +uint32_t RadioNode::getChannelEntryMillis(void) { + return _channelEntryMillis; +} + +static uint32_t RadioNode::getFrequencyForChannel(uint8_t channel) { + return RADIO_FREQUENCY_MIN + (RADIO_CHANNEL_WIDTH * channel); +} + +static uint8_t RadioNode::getNextChannel(uint8_t channel) { + return (channel + RADIO_HOP_OFFSET) % RADIO_CHANNEL_COUNT; +} + +static uint8_t RadioNode::getPrevChannel(uint8_t channel) { + return (RADIO_CHANNEL_COUNT + channel - RADIO_HOP_OFFSET) % RADIO_CHANNEL_COUNT; +} + +void RadioNode::hopFrequency(bool forward, uint8_t fromChannel, uint32_t timestamp) { + _channelEntryMillis = timestamp; + + if (forward) { + _channel = RadioNode::getNextChannel(fromChannel); + } else { + _channel = RadioNode::getPrevChannel(fromChannel); + } + + // And set hardware + LoRa.sleep(); + LoRa.setFrequency( + RadioNode::getFrequencyForChannel(_channel) + ); + LoRa.idle(); +} \ No newline at end of file diff --git a/crossbow/radio_node.h b/crossbow/radio_node.h new file mode 100644 index 0000000..9789813 --- /dev/null +++ b/crossbow/radio_node.h @@ -0,0 +1,55 @@ +#pragma once + +#include "Arduino.h" + +#ifndef RADIO_NODE_H +#define RADIO_NODE_H + +#define RADIO_STATE_TX 1 +#define RADIO_STATE_RX 2 + +#define TX_TRANSMIT_SLOT_RATE 67 //ms +#define RX_CHANNEL_DWELL_TIME (TX_TRANSMIT_SLOT_RATE + 10) //Dwell on a channel slightly longer +#define RX_FAILSAFE_DELAY (TX_TRANSMIT_SLOT_RATE * 8) +#define TX_FAILSAFE_DELAY (RX_FAILSAFE_DELAY * 4) + +#define RADIO_FREQUENCY_MIN 868000000 +#define RADIO_FREQUENCY_MAX 870000000 +#define RADIO_FREQUENCY_RANGE (RADIO_FREQUENCY_MAX-RADIO_FREQUENCY_MIN) +#define RADIO_CHANNEL_WIDTH 250000 +#define RADIO_CHANNEL_COUNT 9 // 9 channels in 2MHz range (RADIO_FREQUENCY_RANGE/RADIO_CHANNEL_WIDTH) + 1 +#define RADIO_HOP_OFFSET 5 + +struct RadioState_t { + uint32_t loraBandwidth = 250000; + uint8_t loraSpreadingFactor = 7; + uint8_t loraCodingRate = 6; + uint8_t loraTxPower = 17; // Defines output power of TX, defined in dBm range from 2-17 + int8_t bytesToRead = -1; + uint8_t rssi = 0; + uint8_t snr = 0; + uint8_t deviceState = RADIO_STATE_RX; + uint32_t nextTxCheckMillis = 0; + + const uint32_t dwellTime = TX_TRANSMIT_SLOT_RATE * 2; + uint8_t lastReceivedChannel = 0; + uint8_t failedDwellsCount = 0; +}; + +class RadioNode { + public: + RadioNode(void); + static uint8_t getRadioRssi(void); + static uint8_t getRadioSnr(void); + static uint32_t getFrequencyForChannel(uint8_t channel); + static uint8_t getNextChannel(uint8_t channel); + static uint8_t getPrevChannel(uint8_t channel); + void hopFrequency(bool forward, uint8_t fromChannel, uint32_t timestamp); + uint8_t getChannel(void); + uint32_t getChannelEntryMillis(void); + private: + uint8_t _channel = 0; + uint32_t _channelEntryMillis = 0; +}; + +#endif \ No newline at end of file diff --git a/crossbow/variables.h b/crossbow/variables.h index fd75559..55e1f92 100644 --- a/crossbow/variables.h +++ b/crossbow/variables.h @@ -1,4 +1,5 @@ #include "Arduino.h" +#include "radio_node.h" #pragma once @@ -13,11 +14,6 @@ #define RX_TASK_HEALTH 200 //5Hz should be enough #define RSSI_CHANNEL 11 -#define TX_TRANSMIT_SLOT_RATE 67 //ms -#define RX_CHANNEL_DWELL_TIME (TX_TRANSMIT_SLOT_RATE + 10) //Dwell on a channel slightly longer -#define RX_FAILSAFE_DELAY (TX_TRANSMIT_SLOT_RATE * 8) -#define TX_FAILSAFE_DELAY (RX_FAILSAFE_DELAY * 4) - #define CHANNEL_ID 0x01 #define QSP_PAYLOAD_LENGTH 32 @@ -83,34 +79,6 @@ enum debugConfigFlags { #define NO_DATA_TO_READ -1 -#define RADIO_STATE_TX 1 -#define RADIO_STATE_RX 2 - -#define RADIO_FREQUENCY_MIN 868000000 -#define RADIO_FREQUENCY_MAX 870000000 -#define RADIO_FREQUENCY_RANGE (RADIO_FREQUENCY_MAX-RADIO_FREQUENCY_MIN) -#define RADIO_CHANNEL_WIDTH 250000 -#define RADIO_CHANNEL_COUNT 9 // 9 channels in 2MHz range (RADIO_FREQUENCY_RANGE/RADIO_CHANNEL_WIDTH) + 1 -#define RADIO_HOP_OFFSET 5 - -struct RadioState_t { - uint32_t loraBandwidth = 250000; - uint8_t loraSpreadingFactor = 7; - uint8_t loraCodingRate = 6; - uint8_t loraTxPower = 17; // Defines output power of TX, defined in dBm range from 2-17 - int8_t bytesToRead = -1; - uint8_t rssi = 0; - uint8_t snr = 0; - uint8_t deviceState = RADIO_STATE_RX; - uint32_t nextTxCheckMillis = 0; - - const uint32_t dwellTime = TX_TRANSMIT_SLOT_RATE * 2; - uint8_t channel = 0; - uint8_t lastReceivedChannel = 0; - uint32_t channelEntryMillis = 0; - uint8_t failedDwellsCount = 0; -}; - struct TxDeviceState_t { uint8_t flags = 0; uint32_t roundtrip = 0; From 376694832915e53d8b504102e6d147ca50f3cc13 Mon Sep 17 00:00:00 2001 From: Pawel Spychalski Date: Wed, 16 May 2018 11:41:06 +0200 Subject: [PATCH 2/8] step 2 --- .vscode/settings.json | 4 +++- crossbow/crossbow.ino | 41 +++++++++++++++-------------------------- crossbow/qsp.h | 1 + crossbow/radio_node.cpp | 26 ++++++++++++++++++++++++++ crossbow/radio_node.h | 37 ++++++++++++------------------------- crossbow/variables.h | 27 +++++++++++++++++++++++++++ 6 files changed, 84 insertions(+), 52 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 77f0cd2..d00452d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,9 @@ { "files.associations": { "variables.h": "c", - "arduino.h": "c" + "arduino.h": "c", + "algorithm": "cpp", + "random": "cpp" }, "files.exclude": { "**/build": true diff --git a/crossbow/crossbow.ino b/crossbow/crossbow.ino index 6e17397..1d42577 100644 --- a/crossbow/crossbow.ino +++ b/crossbow/crossbow.ino @@ -9,11 +9,11 @@ Copyright (c) 20xx, MPL Contributor1 contrib1@example.net #include "config.h" #include "lora.h" +#include "radio_node.h" #include "variables.h" #include "main_variables.h" #include "qsp.h" #include "sbus.h" -#include "radio_node.h" #ifdef ARDUINO_AVR_FEATHER32U4 #define LORA_SS_PIN 8 @@ -184,7 +184,7 @@ void setup(void) //Setup ISR callback and start receiving LoRa.onReceive(onReceive); LoRa.receive(); - radioState.deviceState = RADIO_STATE_RX; + radioNode.deviceState = RADIO_STATE_RX; #ifdef DEVICE_MODE_RX //initiallize default ppm values @@ -368,7 +368,7 @@ void loop(void) */ if ( currentMillis > radioState.nextTxCheckMillis && - radioState.deviceState == RADIO_STATE_TX && + radioNode.deviceState == RADIO_STATE_TX && !LoRa.isTransmitting() ) { @@ -380,27 +380,16 @@ void loop(void) #endif LoRa.receive(); - radioState.deviceState = RADIO_STATE_RX; + radioNode.deviceState = RADIO_STATE_RX; radioState.nextTxCheckMillis = currentMillis + 1; //We check of TX done every 1ms } - /* - * There is data to be read from radio! - */ - if (radioState.bytesToRead != NO_DATA_TO_READ) { - LoRa.read(tmpBuffer, radioState.bytesToRead); - - for (int i = 0; i < radioState.bytesToRead; i++) { - qspDecodeIncomingFrame(&qsp, tmpBuffer[i], &rxDeviceState, &txDeviceState, &radioState); - } - - //After reading, flush radio buffer, we have no need for whatever might be over there - LoRa.sleep(); - LoRa.receive(); - radioState.deviceState = RADIO_STATE_RX; - - radioState.bytesToRead = NO_DATA_TO_READ; - } + radioNode.readAndDecode( + &radioState, + &qsp, + &rxDeviceState, + &txDeviceState + ); bool transmitPayload = false; @@ -419,7 +408,7 @@ void loop(void) txInput.loop(); if ( - radioState.deviceState == RADIO_STATE_RX && + radioNode.deviceState == RADIO_STATE_RX && qsp.protocolState == QSP_STATE_IDLE && qsp.lastTxSlotTimestamp + TX_TRANSMIT_SLOT_RATE < currentMillis ) { @@ -536,7 +525,7 @@ void loop(void) LoRa.endPacketAsync(); //Set state to be able to detect the moment when TX is done - radioState.deviceState = RADIO_STATE_TX; + radioNode.deviceState = RADIO_STATE_TX; transmitPayload = false; } @@ -615,18 +604,18 @@ void onReceive(int packetSize) * We can start reading only when radio is not reading. * If not reading, then we might start */ - if (radioState.bytesToRead == NO_DATA_TO_READ) { + if (radioNode.bytesToRead == NO_DATA_TO_READ) { if (packetSize >= MIN_PACKET_SIZE && packetSize <= MAX_PACKET_SIZE) { //We have a packet candidate that might contain a valid QSP packet - radioState.bytesToRead = packetSize; + radioNode.bytesToRead = packetSize; } else { /* That packet was not very interesting, just flush it, we have no use */ LoRa.sleep(); LoRa.receive(); - radioState.deviceState = RADIO_STATE_RX; + radioNode.deviceState = RADIO_STATE_RX; } } } \ No newline at end of file diff --git a/crossbow/qsp.h b/crossbow/qsp.h index 74e28d3..c2b1a7a 100644 --- a/crossbow/qsp.h +++ b/crossbow/qsp.h @@ -1,4 +1,5 @@ #include "Arduino.h" +#include "variables.h" void qspDecodeRcDataFrame(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceSate); void decodeRxHealthPayload(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceState); diff --git a/crossbow/radio_node.cpp b/crossbow/radio_node.cpp index 5da105f..9a7865c 100644 --- a/crossbow/radio_node.cpp +++ b/crossbow/radio_node.cpp @@ -35,6 +35,32 @@ static uint8_t RadioNode::getPrevChannel(uint8_t channel) { return (RADIO_CHANNEL_COUNT + channel - RADIO_HOP_OFFSET) % RADIO_CHANNEL_COUNT; } +void RadioNode::readAndDecode( + volatile RadioState_t *radioState, + QspConfiguration_t *qsp, + RxDeviceState_t *rxDeviceState, + TxDeviceState_t *txDeviceState +) { + uint8_t tmpBuffer[MAX_PACKET_SIZE]; + /* + * There is data to be read from radio! + */ + if (bytesToRead != NO_DATA_TO_READ) { + LoRa.read(tmpBuffer, bytesToRead); + + for (int i = 0; i < bytesToRead; i++) { + qspDecodeIncomingFrame(qsp, tmpBuffer[i], rxDeviceState, txDeviceState, radioState); + } + + //After reading, flush radio buffer, we have no need for whatever might be over there + LoRa.sleep(); + LoRa.receive(); + + deviceState = RADIO_STATE_RX; + bytesToRead = NO_DATA_TO_READ; + } +} + void RadioNode::hopFrequency(bool forward, uint8_t fromChannel, uint32_t timestamp) { _channelEntryMillis = timestamp; diff --git a/crossbow/radio_node.h b/crossbow/radio_node.h index 9789813..02bcd4a 100644 --- a/crossbow/radio_node.h +++ b/crossbow/radio_node.h @@ -1,17 +1,7 @@ #pragma once #include "Arduino.h" - -#ifndef RADIO_NODE_H -#define RADIO_NODE_H - -#define RADIO_STATE_TX 1 -#define RADIO_STATE_RX 2 - -#define TX_TRANSMIT_SLOT_RATE 67 //ms -#define RX_CHANNEL_DWELL_TIME (TX_TRANSMIT_SLOT_RATE + 10) //Dwell on a channel slightly longer -#define RX_FAILSAFE_DELAY (TX_TRANSMIT_SLOT_RATE * 8) -#define TX_FAILSAFE_DELAY (RX_FAILSAFE_DELAY * 4) +#include "qsp.h" #define RADIO_FREQUENCY_MIN 868000000 #define RADIO_FREQUENCY_MAX 870000000 @@ -20,21 +10,10 @@ #define RADIO_CHANNEL_COUNT 9 // 9 channels in 2MHz range (RADIO_FREQUENCY_RANGE/RADIO_CHANNEL_WIDTH) + 1 #define RADIO_HOP_OFFSET 5 -struct RadioState_t { - uint32_t loraBandwidth = 250000; - uint8_t loraSpreadingFactor = 7; - uint8_t loraCodingRate = 6; - uint8_t loraTxPower = 17; // Defines output power of TX, defined in dBm range from 2-17 - int8_t bytesToRead = -1; - uint8_t rssi = 0; - uint8_t snr = 0; - uint8_t deviceState = RADIO_STATE_RX; - uint32_t nextTxCheckMillis = 0; +#ifndef RADIO_NODE_H +#define RADIO_NODE_H - const uint32_t dwellTime = TX_TRANSMIT_SLOT_RATE * 2; - uint8_t lastReceivedChannel = 0; - uint8_t failedDwellsCount = 0; -}; +#include "variables.h" class RadioNode { public: @@ -45,8 +24,16 @@ class RadioNode { static uint8_t getNextChannel(uint8_t channel); static uint8_t getPrevChannel(uint8_t channel); void hopFrequency(bool forward, uint8_t fromChannel, uint32_t timestamp); + void readAndDecode( + volatile RadioState_t *radioState, + QspConfiguration_t *qsp, + RxDeviceState_t *rxDeviceState, + TxDeviceState_t *txDeviceState + ); uint8_t getChannel(void); uint32_t getChannelEntryMillis(void); + int8_t bytesToRead = -1; + uint8_t deviceState = RADIO_STATE_RX; private: uint8_t _channel = 0; uint32_t _channelEntryMillis = 0; diff --git a/crossbow/variables.h b/crossbow/variables.h index 55e1f92..3cb5bb4 100644 --- a/crossbow/variables.h +++ b/crossbow/variables.h @@ -3,6 +3,17 @@ #pragma once +#ifndef VARIABLES_H +#define VARIABLES_H + +#define RADIO_STATE_TX 1 +#define RADIO_STATE_RX 2 + +#define TX_TRANSMIT_SLOT_RATE 67 //ms +#define RX_CHANNEL_DWELL_TIME (TX_TRANSMIT_SLOT_RATE + 10) //Dwell on a channel slightly longer +#define RX_FAILSAFE_DELAY (TX_TRANSMIT_SLOT_RATE * 8) +#define TX_FAILSAFE_DELAY (RX_FAILSAFE_DELAY * 4) + #define OLED_UPDATE_RATE 750 #define SBUS_UPDATE_RATE 15 //ms @@ -79,6 +90,20 @@ enum debugConfigFlags { #define NO_DATA_TO_READ -1 +struct RadioState_t { + uint32_t loraBandwidth = 250000; + uint8_t loraSpreadingFactor = 7; + uint8_t loraCodingRate = 6; + uint8_t loraTxPower = 17; // Defines output power of TX, defined in dBm range from 2-17 + uint8_t rssi = 0; + uint8_t snr = 0; + uint32_t nextTxCheckMillis = 0; + + const uint32_t dwellTime = TX_TRANSMIT_SLOT_RATE * 2; + uint8_t lastReceivedChannel = 0; + uint8_t failedDwellsCount = 0; +}; + struct TxDeviceState_t { uint8_t flags = 0; uint32_t roundtrip = 0; @@ -117,3 +142,5 @@ struct QspConfiguration_t { uint32_t lastTxSlotTimestamp = 0; bool transmitWindowOpen = false; }; + +#endif \ No newline at end of file From 007926412841b13428022fd9769665f3f5abb94b Mon Sep 17 00:00:00 2001 From: Pawel Spychalski Date: Wed, 16 May 2018 13:07:12 +0200 Subject: [PATCH 3/8] step 3 --- .vscode/settings.json | 4 +++- crossbow/config.h | 4 ++-- crossbow/crossbow.ino | 39 ++++++++++++++------------------------- crossbow/qsp.cpp | 14 ++++++-------- crossbow/qsp.h | 6 +++--- crossbow/radio_node.cpp | 27 +++++++++++++++++++++------ crossbow/radio_node.h | 9 +++++++-- crossbow/tx_oled.cpp | 4 ++-- crossbow/tx_oled.h | 3 +++ crossbow/variables.h | 10 ++-------- 10 files changed, 63 insertions(+), 57 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index d00452d..3f3fc72 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,7 +3,9 @@ "variables.h": "c", "arduino.h": "c", "algorithm": "cpp", - "random": "cpp" + "random": "cpp", + "type_traits": "cpp", + "iterator": "cpp" }, "files.exclude": { "**/build": true diff --git a/crossbow/config.h b/crossbow/config.h index 9dc179b..ebd82da 100644 --- a/crossbow/config.h +++ b/crossbow/config.h @@ -15,8 +15,8 @@ * DEVICE_MODE_TX * DEVICE_MODE_RX */ -#define DEVICE_MODE_TX -// #define DEVICE_MODE_RX +// #define DEVICE_MODE_TX +#define DEVICE_MODE_RX #define FEATURE_TX_OLED // #define FORCE_TX_WITHOUT_INPUT diff --git a/crossbow/crossbow.ino b/crossbow/crossbow.ino index 1d42577..b5467da 100644 --- a/crossbow/crossbow.ino +++ b/crossbow/crossbow.ino @@ -90,19 +90,21 @@ volatile RadioState_t radioState = {}; uint8_t tmpBuffer[MAX_PACKET_SIZE]; -void onQspSuccess(QspConfiguration_t *qsp, TxDeviceState_t *txDeviceState, RxDeviceState_t *rxDeviceState, volatile RadioState_t *radioState) { +void onQspSuccess(QspConfiguration_t *qsp, TxDeviceState_t *txDeviceState, RxDeviceState_t *rxDeviceState, uint8_t receivedChannel) { //If recide received a valid frame, that means it can start to talk + radioNode.lastReceivedChannel = receivedChannel; + qsp->canTransmit = true; - radioState->rssi = radioNode.getRadioRssi(); - radioState->snr = radioNode.getRadioSnr(); + radioNode.readRssi(); + radioNode.readSnr(); /* * RX module hops to next channel after frame has been received */ #ifdef DEVICE_MODE_RX - radioNode.hopFrequency(true, radioState->lastReceivedChannel, millis()); - radioState->failedDwellsCount = 0; // We received a frame, so we can just reset this counter + radioNode.hopFrequency(true, radioNode.lastReceivedChannel, millis()); + radioNode.failedDwellsCount = 0; // We received a frame, so we can just reset this counter LoRa.receive(); //Put radio back into receive mode #endif @@ -142,7 +144,7 @@ void onQspSuccess(QspConfiguration_t *qsp, TxDeviceState_t *txDeviceState, RxDev qsp->transmitWindowOpen = true; } -void onQspFailure(QspConfiguration_t *qsp, TxDeviceState_t *txDeviceState, RxDeviceState_t *rxDeviceState, volatile RadioState_t *radioState) { +void onQspFailure(QspConfiguration_t *qsp, TxDeviceState_t *txDeviceState, RxDeviceState_t *rxDeviceState) { } @@ -346,20 +348,7 @@ void loop(void) * This routine handles resync of TX/RX while hoppping frequencies */ #ifdef DEVICE_MODE_RX - - //In the beginning just keep jumping forward and try to resync over lost single frames - if (radioState.failedDwellsCount < 6 && radioNode.getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME < currentMillis) { - radioState.failedDwellsCount++; - radioNode.hopFrequency(true, radioNode.getChannel(), radioNode.getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME); - LoRa.receive(); - } - - // If we are loosing more frames, start jumping in the opposite direction since probably we are completely out of sync now - if (radioState.failedDwellsCount >= 6 && radioNode.getChannelEntryMillis() + (RX_CHANNEL_DWELL_TIME * 5) < currentMillis) { - radioNode.hopFrequency(false, radioNode.getChannel(), radioNode.getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME); //Start jumping in opposite direction to resync - LoRa.receive(); - } - + radioNode.handleChannelDwell(); #endif /* @@ -456,7 +445,7 @@ void loop(void) lastRxStateTaskTime = currentMillis; updateRxDeviceState(&rxDeviceState); - uint8_t output = constrain(radioState.rssi - 40, 0, 100); + uint8_t output = constrain(radioNode.rssi - 40, 0, 100); rxDeviceState.indicatedRssi = (output * 10) + 1000; if (qsp.deviceState == DEVICE_STATE_FAILSAFE) { @@ -487,7 +476,7 @@ void loop(void) break; case QSP_FRAME_RX_HEALTH: - encodeRxHealthPayload(&qsp, &rxDeviceState, &radioState); + encodeRxHealthPayload(&qsp, &rxDeviceState, radioNode.rssi, radioNode.snr); break; } @@ -507,7 +496,7 @@ void loop(void) if (qsp.lastFrameReceivedAt[QSP_FRAME_RC_DATA] + RX_FAILSAFE_DELAY < currentMillis) { qsp.deviceState = DEVICE_STATE_FAILSAFE; rxDeviceState.indicatedRssi = 0; - radioState.rssi = 0; + radioNode.rssi = 0; } else { qsp.deviceState = DEVICE_STATE_OK; } @@ -569,9 +558,9 @@ void loop(void) } else if (txDeviceState.isReceiving && (rxDeviceState.flags & 0x1) == 1) { //Failsafe reported by RX module buzzerContinousMode(BUZZER_MODE_SLOW_BEEP, &buzzer); - } else if (txDeviceState.isReceiving && radioState.rssi < 45) { + } else if (txDeviceState.isReceiving && radioNode.rssi < 45) { buzzerContinousMode(BUZZER_MODE_DOUBLE_CHIRP, &buzzer); // RSSI below 45dB // Critical state - } else if (txDeviceState.isReceiving && radioState.rssi < 55) { + } else if (txDeviceState.isReceiving && radioNode.rssi < 55) { buzzerContinousMode(BUZZER_MODE_CHIRP, &buzzer); // RSSI below 55dB // Warning state } else { buzzerContinousMode(BUZZER_MODE_OFF, &buzzer); diff --git a/crossbow/qsp.cpp b/crossbow/qsp.cpp index 90982be..6a12363 100644 --- a/crossbow/qsp.cpp +++ b/crossbow/qsp.cpp @@ -62,9 +62,9 @@ void qspComputeCrc(QspConfiguration_t *qsp, uint8_t dataByte) qsp->crc = crc8_dvb_s2(qsp->crc, dataByte); } -void encodeRxHealthPayload(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceState, volatile RadioState_t *radioState) { - qsp->payload[0] = radioState->rssi; - qsp->payload[1] = radioState->snr; +void encodeRxHealthPayload(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceState, uint8_t rssi, uint8_t snr) { + qsp->payload[0] = rssi; + qsp->payload[1] = snr; qsp->payload[2] = rxDeviceState->rxVoltage; qsp->payload[3] = rxDeviceState->a1Voltage; qsp->payload[4] = rxDeviceState->a2Voltage; @@ -165,8 +165,7 @@ void qspDecodeIncomingFrame( QspConfiguration_t *qsp, uint8_t incomingByte, RxDeviceState_t *rxDeviceState, - TxDeviceState_t *txDeviceState, - volatile RadioState_t *radioState + TxDeviceState_t *txDeviceState ) { static uint8_t frameId; static uint8_t payloadLength; @@ -210,10 +209,9 @@ void qspDecodeIncomingFrame( { if (qsp->crc == incomingByte) { //CRC is correct - radioState->lastReceivedChannel = receivedChannel; - qsp->onSuccessCallback(qsp, txDeviceState, rxDeviceState, radioState); + qsp->onSuccessCallback(qsp, txDeviceState, rxDeviceState, receivedChannel); } else { - qsp->onFailureCallback(qsp, txDeviceState, rxDeviceState, radioState); + qsp->onFailureCallback(qsp, txDeviceState, rxDeviceState); } // In both cases switch to listening for next preamble diff --git a/crossbow/qsp.h b/crossbow/qsp.h index c2b1a7a..834368c 100644 --- a/crossbow/qsp.h +++ b/crossbow/qsp.h @@ -1,5 +1,6 @@ #include "Arduino.h" #include "variables.h" +#include "radio_node.h" void qspDecodeRcDataFrame(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceSate); void decodeRxHealthPayload(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceState); @@ -7,14 +8,13 @@ void decodeRxHealthPayload(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceSta uint8_t get10bitHighShift(uint8_t channel); uint8_t get10bitLowShift(uint8_t channel); void qspComputeCrc(QspConfiguration_t *qsp, uint8_t dataByte); -void encodeRxHealthPayload(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceState, volatile RadioState_t *radioState); +void encodeRxHealthPayload(QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceState, uint8_t rssi, uint8_t snr); void encodeRcDataPayload(QspConfiguration_t *qsp, volatile int16_t channels[], uint8_t noOfChannels); void qspDecodeIncomingFrame( QspConfiguration_t *qsp, uint8_t incomingByte, RxDeviceState_t *rxDeviceState, - TxDeviceState_t *txDeviceState, - volatile RadioState_t *radioState + TxDeviceState_t *txDeviceState ); void qspClearPayload(QspConfiguration_t *qsp); void qspEncodeFrame(QspConfiguration_t *qsp, volatile RadioState_t *radioState, uint8_t buffer[], uint8_t *size, uint8_t radioChannel); diff --git a/crossbow/radio_node.cpp b/crossbow/radio_node.cpp index 9a7865c..1579aa8 100644 --- a/crossbow/radio_node.cpp +++ b/crossbow/radio_node.cpp @@ -5,14 +5,14 @@ RadioNode::RadioNode(void) { } -static uint8_t RadioNode::getRadioRssi(void) +void RadioNode::readRssi(void) { - return 164 - constrain(LoRa.packetRssi() * -1, 0, 164); + rssi = 164 - constrain(LoRa.packetRssi() * -1, 0, 164); } -static uint8_t RadioNode::getRadioSnr(void) +void RadioNode::readSnr(void) { - return (uint8_t) constrain(LoRa.packetSnr(), 0, 255); + snr = (uint8_t) constrain(LoRa.packetSnr(), 0, 255); } uint8_t RadioNode::getChannel(void) { @@ -49,13 +49,13 @@ void RadioNode::readAndDecode( LoRa.read(tmpBuffer, bytesToRead); for (int i = 0; i < bytesToRead; i++) { - qspDecodeIncomingFrame(qsp, tmpBuffer[i], rxDeviceState, txDeviceState, radioState); + qspDecodeIncomingFrame(qsp, tmpBuffer[i], rxDeviceState, txDeviceState); } //After reading, flush radio buffer, we have no need for whatever might be over there LoRa.sleep(); LoRa.receive(); - + deviceState = RADIO_STATE_RX; bytesToRead = NO_DATA_TO_READ; } @@ -76,4 +76,19 @@ void RadioNode::hopFrequency(bool forward, uint8_t fromChannel, uint32_t timesta RadioNode::getFrequencyForChannel(_channel) ); LoRa.idle(); +} + +void RadioNode::handleChannelDwell(void) { + //In the beginning just keep jumping forward and try to resync over lost single frames + if (failedDwellsCount < 6 && getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME < millis()) { + failedDwellsCount++; + hopFrequency(true, getChannel(), getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME); + LoRa.receive(); + } + + // If we are loosing more frames, start jumping in the opposite direction since probably we are completely out of sync now + if (failedDwellsCount >= 6 && getChannelEntryMillis() + (RX_CHANNEL_DWELL_TIME * 5) < millis()) { + hopFrequency(false, getChannel(), getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME); //Start jumping in opposite direction to resync + LoRa.receive(); + } } \ No newline at end of file diff --git a/crossbow/radio_node.h b/crossbow/radio_node.h index 02bcd4a..b4346ce 100644 --- a/crossbow/radio_node.h +++ b/crossbow/radio_node.h @@ -18,8 +18,8 @@ class RadioNode { public: RadioNode(void); - static uint8_t getRadioRssi(void); - static uint8_t getRadioSnr(void); + void readRssi(void); + void readSnr(void); static uint32_t getFrequencyForChannel(uint8_t channel); static uint8_t getNextChannel(uint8_t channel); static uint8_t getPrevChannel(uint8_t channel); @@ -32,8 +32,13 @@ class RadioNode { ); uint8_t getChannel(void); uint32_t getChannelEntryMillis(void); + void handleChannelDwell(void); int8_t bytesToRead = -1; uint8_t deviceState = RADIO_STATE_RX; + uint8_t rssi = 0; + uint8_t snr = 0; + uint8_t lastReceivedChannel = 0; + uint8_t failedDwellsCount = 0; private: uint8_t _channel = 0; uint32_t _channelEntryMillis = 0; diff --git a/crossbow/tx_oled.cpp b/crossbow/tx_oled.cpp index cd4e930..65c377e 100644 --- a/crossbow/tx_oled.cpp +++ b/crossbow/tx_oled.cpp @@ -151,11 +151,11 @@ void TxOled::renderPageStats( _display.setCursor(0, 0); _display.setTextSize(3); - _display.print(radioState->rssi); + _display.print(radioNode.rssi); _display.setCursor(18, 28); _display.setTextSize(2); - _display.print(radioState->snr); + _display.print(radioNode.snr); _display.setCursor(74, 0); _display.setTextSize(3); diff --git a/crossbow/tx_oled.h b/crossbow/tx_oled.h index cd43e13..f571807 100644 --- a/crossbow/tx_oled.h +++ b/crossbow/tx_oled.h @@ -7,6 +7,9 @@ #include "Wire.h" #include "variables.h" #include "tactile.h" +#include "radio_node.h" + +extern volatile RadioNode radioNode; enum txOledPages { TX_PAGE_NONE, diff --git a/crossbow/variables.h b/crossbow/variables.h index 3cb5bb4..30b35a5 100644 --- a/crossbow/variables.h +++ b/crossbow/variables.h @@ -95,13 +95,7 @@ struct RadioState_t { uint8_t loraSpreadingFactor = 7; uint8_t loraCodingRate = 6; uint8_t loraTxPower = 17; // Defines output power of TX, defined in dBm range from 2-17 - uint8_t rssi = 0; - uint8_t snr = 0; uint32_t nextTxCheckMillis = 0; - - const uint32_t dwellTime = TX_TRANSMIT_SLOT_RATE * 2; - uint8_t lastReceivedChannel = 0; - uint8_t failedDwellsCount = 0; }; struct TxDeviceState_t { @@ -133,8 +127,8 @@ struct QspConfiguration_t { uint32_t lastFrameReceivedAt[QSP_FRAME_COUNT] = {0}; uint32_t anyFrameRecivedAt = 0; uint8_t deviceState = DEVICE_STATE_UNDETERMINED; - void (* onSuccessCallback)(QspConfiguration_t*, TxDeviceState_t*, RxDeviceState_t*, volatile RadioState_t*); - void (* onFailureCallback)(QspConfiguration_t*, TxDeviceState_t*, RxDeviceState_t*, volatile RadioState_t*); + void (* onSuccessCallback)(QspConfiguration_t*, TxDeviceState_t*, RxDeviceState_t*, uint8_t receivedChannel); + void (* onFailureCallback)(QspConfiguration_t*, TxDeviceState_t*, RxDeviceState_t*); bool canTransmit = false; bool forcePongFrame = false; uint8_t debugConfig = 0; From 948cc7915b37c84b161bccd7f776f8d65975a4af Mon Sep 17 00:00:00 2001 From: Pawel Spychalski Date: Wed, 16 May 2018 13:36:22 +0200 Subject: [PATCH 4/8] RadioState removed --- .vscode/settings.json | 5 ++++- crossbow/crossbow.ino | 32 ++++++-------------------------- crossbow/qsp.cpp | 2 +- crossbow/qsp.h | 2 +- crossbow/radio_node.cpp | 22 +++++++++++++++++++++- crossbow/radio_node.h | 7 ++++++- crossbow/tx_oled.cpp | 28 ++++++++++------------------ crossbow/tx_oled.h | 7 ------- crossbow/variables.h | 8 -------- 9 files changed, 49 insertions(+), 64 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 3f3fc72..72a79e6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,7 +5,10 @@ "algorithm": "cpp", "random": "cpp", "type_traits": "cpp", - "iterator": "cpp" + "iterator": "cpp", + "rope": "c", + "__locale": "c", + "string": "c" }, "files.exclude": { "**/build": true diff --git a/crossbow/crossbow.ino b/crossbow/crossbow.ino index b5467da..3aa6fd9 100644 --- a/crossbow/crossbow.ino +++ b/crossbow/crossbow.ino @@ -86,7 +86,6 @@ Tactile button1(BUTTON_1_PIN); QspConfiguration_t qsp = {}; RxDeviceState_t rxDeviceState = {}; TxDeviceState_t txDeviceState = {}; -volatile RadioState_t radioState = {}; uint8_t tmpBuffer[MAX_PACKET_SIZE]; @@ -177,10 +176,10 @@ void setup(void) } //Configure LoRa module - LoRa.setSignalBandwidth(radioState.loraBandwidth); - LoRa.setSpreadingFactor(radioState.loraSpreadingFactor); - LoRa.setCodingRate4(radioState.loraCodingRate); - LoRa.setTxPower(radioState.loraTxPower); + LoRa.setSignalBandwidth(radioNode.loraBandwidth); + LoRa.setSpreadingFactor(radioNode.loraSpreadingFactor); + LoRa.setCodingRate4(radioNode.loraCodingRate); + LoRa.setTxPower(radioNode.loraTxPower); LoRa.enableCrc(); //Setup ISR callback and start receiving @@ -210,7 +209,6 @@ void setup(void) #ifdef FEATURE_TX_OLED oled.init(); oled.page( - &radioState, &rxDeviceState, &txDeviceState, TX_PAGE_INIT @@ -320,7 +318,6 @@ void loop(void) #ifdef FEATURE_TX_OLED oled.loop( - &radioState, &rxDeviceState, &txDeviceState, &button0, @@ -355,26 +352,9 @@ void loop(void) * Detect the moment when radio module stopped transmittig and put it * back in to receive state */ - if ( - currentMillis > radioState.nextTxCheckMillis && - radioNode.deviceState == RADIO_STATE_TX && - !LoRa.isTransmitting() - ) { - - /* - * In case of TX module, hop right now - */ -#ifdef DEVICE_MODE_TX - radioNode.hopFrequency(true, radioNode.getChannel(), millis()); -#endif - - LoRa.receive(); - radioNode.deviceState = RADIO_STATE_RX; - radioState.nextTxCheckMillis = currentMillis + 1; //We check of TX done every 1ms - } + radioNode.handleTxDoneState(); radioNode.readAndDecode( - &radioState, &qsp, &rxDeviceState, &txDeviceState @@ -508,7 +488,7 @@ void loop(void) uint8_t size; LoRa.beginPacket(); //Prepare packet - qspEncodeFrame(&qsp, &radioState, tmpBuffer, &size, radioNode.getChannel()); + qspEncodeFrame(&qsp, tmpBuffer, &size, radioNode.getChannel()); //Sent it to radio in one SPI transaction LoRa.write(tmpBuffer, size); LoRa.endPacketAsync(); diff --git a/crossbow/qsp.cpp b/crossbow/qsp.cpp index 6a12363..fa4dc8d 100644 --- a/crossbow/qsp.cpp +++ b/crossbow/qsp.cpp @@ -222,7 +222,7 @@ void qspDecodeIncomingFrame( /** * Encode frame is corrent format and write to hardware */ -void qspEncodeFrame(QspConfiguration_t *qsp, volatile RadioState_t *radioState, uint8_t buffer[], uint8_t *size, uint8_t radioChannel) { +void qspEncodeFrame(QspConfiguration_t *qsp, uint8_t buffer[], uint8_t *size, uint8_t radioChannel) { //Salt CRC with bind key qspInitCrc(qsp); diff --git a/crossbow/qsp.h b/crossbow/qsp.h index 834368c..8d6d29b 100644 --- a/crossbow/qsp.h +++ b/crossbow/qsp.h @@ -17,6 +17,6 @@ void qspDecodeIncomingFrame( TxDeviceState_t *txDeviceState ); void qspClearPayload(QspConfiguration_t *qsp); -void qspEncodeFrame(QspConfiguration_t *qsp, volatile RadioState_t *radioState, uint8_t buffer[], uint8_t *size, uint8_t radioChannel); +void qspEncodeFrame(QspConfiguration_t *qsp, uint8_t buffer[], uint8_t *size, uint8_t radioChannel); void encodePingPayload(QspConfiguration_t *qsp, uint32_t currentMicros); \ No newline at end of file diff --git a/crossbow/radio_node.cpp b/crossbow/radio_node.cpp index 1579aa8..c44461e 100644 --- a/crossbow/radio_node.cpp +++ b/crossbow/radio_node.cpp @@ -36,7 +36,6 @@ static uint8_t RadioNode::getPrevChannel(uint8_t channel) { } void RadioNode::readAndDecode( - volatile RadioState_t *radioState, QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState @@ -91,4 +90,25 @@ void RadioNode::handleChannelDwell(void) { hopFrequency(false, getChannel(), getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME); //Start jumping in opposite direction to resync LoRa.receive(); } +} + +void RadioNode::handleTxDoneState(void) { + uint32_t currentMillis = millis(); + if ( + currentMillis > nextTxCheckMillis && + deviceState == RADIO_STATE_TX && + !LoRa.isTransmitting() + ) { + + /* + * In case of TX module, hop right now + */ +#ifdef DEVICE_MODE_TX + hopFrequency(true, getChannel(), currentMillis); +#endif + + LoRa.receive(); + deviceState = RADIO_STATE_RX; + nextTxCheckMillis = currentMillis + 1; //We check of TX done every 1ms + } } \ No newline at end of file diff --git a/crossbow/radio_node.h b/crossbow/radio_node.h index b4346ce..80d9123 100644 --- a/crossbow/radio_node.h +++ b/crossbow/radio_node.h @@ -25,7 +25,6 @@ class RadioNode { static uint8_t getPrevChannel(uint8_t channel); void hopFrequency(bool forward, uint8_t fromChannel, uint32_t timestamp); void readAndDecode( - volatile RadioState_t *radioState, QspConfiguration_t *qsp, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState @@ -33,15 +32,21 @@ class RadioNode { uint8_t getChannel(void); uint32_t getChannelEntryMillis(void); void handleChannelDwell(void); + void handleTxDoneState(); int8_t bytesToRead = -1; uint8_t deviceState = RADIO_STATE_RX; uint8_t rssi = 0; uint8_t snr = 0; uint8_t lastReceivedChannel = 0; uint8_t failedDwellsCount = 0; + uint32_t loraBandwidth = 250000; + uint8_t loraSpreadingFactor = 7; + uint8_t loraCodingRate = 6; + uint8_t loraTxPower = 17; // Defines output power of TX, defined in dBm range from 2-17 private: uint8_t _channel = 0; uint32_t _channelEntryMillis = 0; + uint32_t nextTxCheckMillis = 0; }; #endif \ No newline at end of file diff --git a/crossbow/tx_oled.cpp b/crossbow/tx_oled.cpp index 65c377e..35bbd1c 100644 --- a/crossbow/tx_oled.cpp +++ b/crossbow/tx_oled.cpp @@ -13,7 +13,6 @@ void TxOled::init() { } void TxOled::loop( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState, Tactile *button0, @@ -48,7 +47,6 @@ void TxOled::loop( if (update) { page( - radioState, rxDeviceState, txDeviceState, pageSequence[_mainPageSequenceIndex] @@ -58,26 +56,25 @@ void TxOled::loop( } void TxOled::page( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState, int page ) { switch (page) { case TX_PAGE_INIT: - renderPageInit(radioState, rxDeviceState, txDeviceState); + renderPageInit(rxDeviceState, txDeviceState); break; case TX_PAGE_STATS: - renderPageStats(radioState, rxDeviceState, txDeviceState); + renderPageStats(rxDeviceState, txDeviceState); break; case TX_PAGE_PWR: - renderPagePwr(radioState, rxDeviceState, txDeviceState); + renderPagePwr(rxDeviceState, txDeviceState); break; case TX_PAGE_BIND: - renderPageBind(radioState, rxDeviceState, txDeviceState); + renderPageBind(rxDeviceState, txDeviceState); break; case TX_PAGE_MODE: - renderPageMode(radioState, rxDeviceState, txDeviceState); + renderPageMode(rxDeviceState, txDeviceState); break; } @@ -85,7 +82,6 @@ void TxOled::page( } void TxOled::renderPagePwr( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ) { @@ -99,14 +95,13 @@ void TxOled::renderPagePwr( //TODO content _display.setCursor(0, 25); _display.setTextSize(3); - _display.print(radioState->loraTxPower); + _display.print(radioNode.loraTxPower); _display.print("dBm"); _display.display(); } void TxOled::renderPageBind( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ) { @@ -123,7 +118,6 @@ void TxOled::renderPageBind( } void TxOled::renderPageMode( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ) { @@ -142,7 +136,6 @@ void TxOled::renderPageMode( } void TxOled::renderPageStats( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ) { @@ -173,7 +166,6 @@ void TxOled::renderPageStats( } void TxOled::renderPageInit( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ) { @@ -183,22 +175,22 @@ void TxOled::renderPageInit( _display.setCursor(0, 0); _display.print("Rdy "); - _display.print(radioState->loraTxPower); + _display.print(radioNode.loraTxPower); _display.print("dBm"); _display.setTextSize(1); _display.setCursor(0, 32); _display.print("Bandwitdh: "); - _display.print(radioState->loraBandwidth / 1000); + _display.print(radioNode.loraBandwidth / 1000); _display.print("kHz"); _display.setCursor(0, 42); _display.print("SF: "); - _display.print(radioState->loraSpreadingFactor); + _display.print(radioNode.loraSpreadingFactor); _display.setCursor(64, 42); _display.print("CR: "); - _display.print(radioState->loraCodingRate); + _display.print(radioNode.loraCodingRate); _display.setCursor(0, 52); _display.print("Rate: "); diff --git a/crossbow/tx_oled.h b/crossbow/tx_oled.h index f571807..41c4b33 100644 --- a/crossbow/tx_oled.h +++ b/crossbow/tx_oled.h @@ -35,14 +35,12 @@ class TxOled { TxOled(void); void init(); void loop( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState, Tactile *button0, Tactile *button1 ); void page( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState, int page @@ -50,27 +48,22 @@ class TxOled { private: Adafruit_SSD1306 _display; void renderPageInit( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ); void renderPageStats( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ); void renderPagePwr( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ); void renderPageBind( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ); void renderPageMode( - volatile RadioState_t *radioState, RxDeviceState_t *rxDeviceState, TxDeviceState_t *txDeviceState ); diff --git a/crossbow/variables.h b/crossbow/variables.h index 30b35a5..38570d5 100644 --- a/crossbow/variables.h +++ b/crossbow/variables.h @@ -90,14 +90,6 @@ enum debugConfigFlags { #define NO_DATA_TO_READ -1 -struct RadioState_t { - uint32_t loraBandwidth = 250000; - uint8_t loraSpreadingFactor = 7; - uint8_t loraCodingRate = 6; - uint8_t loraTxPower = 17; // Defines output power of TX, defined in dBm range from 2-17 - uint32_t nextTxCheckMillis = 0; -}; - struct TxDeviceState_t { uint8_t flags = 0; uint32_t roundtrip = 0; From 434fe13fff62feca0f5734659bcf8214a0259ee9 Mon Sep 17 00:00:00 2001 From: Pawel Spychalski Date: Wed, 16 May 2018 14:23:09 +0200 Subject: [PATCH 5/8] Init moved to RadioNode --- crossbow/config.h | 4 ++-- crossbow/crossbow.ino | 39 ++------------------------------------- crossbow/radio_node.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ crossbow/radio_node.h | 2 ++ 4 files changed, 48 insertions(+), 39 deletions(-) diff --git a/crossbow/config.h b/crossbow/config.h index ebd82da..9dc179b 100644 --- a/crossbow/config.h +++ b/crossbow/config.h @@ -15,8 +15,8 @@ * DEVICE_MODE_TX * DEVICE_MODE_RX */ -// #define DEVICE_MODE_TX -#define DEVICE_MODE_RX +#define DEVICE_MODE_TX +// #define DEVICE_MODE_RX #define FEATURE_TX_OLED // #define FORCE_TX_WITHOUT_INPUT diff --git a/crossbow/crossbow.ino b/crossbow/crossbow.ino index 3aa6fd9..e3c3138 100644 --- a/crossbow/crossbow.ino +++ b/crossbow/crossbow.ino @@ -87,8 +87,6 @@ QspConfiguration_t qsp = {}; RxDeviceState_t rxDeviceState = {}; TxDeviceState_t txDeviceState = {}; -uint8_t tmpBuffer[MAX_PACKET_SIZE]; - void onQspSuccess(QspConfiguration_t *qsp, TxDeviceState_t *txDeviceState, RxDeviceState_t *rxDeviceState, uint8_t receivedChannel) { //If recide received a valid frame, that means it can start to talk radioNode.lastReceivedChannel = receivedChannel; @@ -162,30 +160,7 @@ void setup(void) qsp.deviceState = DEVICE_STATE_OK; #endif - /* - * Setup hardware - */ - LoRa.setPins( - LORA_SS_PIN, - LORA_RST_PIN, - LORA_DI0_PIN - ); - - if (!LoRa.begin(radioNode.getFrequencyForChannel(radioNode.getChannel()))) { - while (true); - } - - //Configure LoRa module - LoRa.setSignalBandwidth(radioNode.loraBandwidth); - LoRa.setSpreadingFactor(radioNode.loraSpreadingFactor); - LoRa.setCodingRate4(radioNode.loraCodingRate); - LoRa.setTxPower(radioNode.loraTxPower); - LoRa.enableCrc(); - - //Setup ISR callback and start receiving - LoRa.onReceive(onReceive); - LoRa.receive(); - radioNode.deviceState = RADIO_STATE_RX; + radioNode.init(LORA_SS_PIN, LORA_RST_PIN, LORA_DI0_PIN, onReceive); #ifdef DEVICE_MODE_RX //initiallize default ppm values @@ -485,17 +460,7 @@ void loop(void) if (qsp.canTransmit && transmitPayload) { - uint8_t size; - LoRa.beginPacket(); - //Prepare packet - qspEncodeFrame(&qsp, tmpBuffer, &size, radioNode.getChannel()); - //Sent it to radio in one SPI transaction - LoRa.write(tmpBuffer, size); - LoRa.endPacketAsync(); - - //Set state to be able to detect the moment when TX is done - radioNode.deviceState = RADIO_STATE_TX; - + radioNode.handleTx(&qsp); transmitPayload = false; } diff --git a/crossbow/radio_node.cpp b/crossbow/radio_node.cpp index c44461e..39fa248 100644 --- a/crossbow/radio_node.cpp +++ b/crossbow/radio_node.cpp @@ -5,6 +5,33 @@ RadioNode::RadioNode(void) { } +void RadioNode::init(uint8_t ss, uint8_t rst, uint8_t di0, void(*callback)(int)) { + /* + * Setup hardware + */ + LoRa.setPins( + ss, + rst, + di0 + ); + + if (!LoRa.begin(getFrequencyForChannel(getChannel()))) { + while (true); + } + + //Configure LoRa module + LoRa.setSignalBandwidth(loraBandwidth); + LoRa.setSpreadingFactor(loraSpreadingFactor); + LoRa.setCodingRate4(loraCodingRate); + LoRa.setTxPower(loraTxPower); + LoRa.enableCrc(); + + //Setup ISR callback and start receiving + LoRa.onReceive(callback); + LoRa.receive(); + deviceState = RADIO_STATE_RX; +} + void RadioNode::readRssi(void) { rssi = 164 - constrain(LoRa.packetRssi() * -1, 0, 164); @@ -111,4 +138,19 @@ void RadioNode::handleTxDoneState(void) { deviceState = RADIO_STATE_RX; nextTxCheckMillis = currentMillis + 1; //We check of TX done every 1ms } +} + +void RadioNode::handleTx(QspConfiguration_t *qsp) { + uint8_t size; + uint8_t tmpBuffer[MAX_PACKET_SIZE]; + + LoRa.beginPacket(); + //Prepare packet + qspEncodeFrame(qsp, tmpBuffer, &size, getChannel()); + //Sent it to radio in one SPI transaction + LoRa.write(tmpBuffer, size); + LoRa.endPacketAsync(); + + //Set state to be able to detect the moment when TX is done + deviceState = RADIO_STATE_TX; } \ No newline at end of file diff --git a/crossbow/radio_node.h b/crossbow/radio_node.h index 80d9123..e88fcc1 100644 --- a/crossbow/radio_node.h +++ b/crossbow/radio_node.h @@ -18,6 +18,7 @@ class RadioNode { public: RadioNode(void); + void init(uint8_t ss, uint8_t rst, uint8_t di0, void(*callback)(int)); void readRssi(void); void readSnr(void); static uint32_t getFrequencyForChannel(uint8_t channel); @@ -33,6 +34,7 @@ class RadioNode { uint32_t getChannelEntryMillis(void); void handleChannelDwell(void); void handleTxDoneState(); + void handleTx(QspConfiguration_t *qsp); int8_t bytesToRead = -1; uint8_t deviceState = RADIO_STATE_RX; uint8_t rssi = 0; From fc6fc95e1ed89f6620d45d1fd63c02ec75445eca Mon Sep 17 00:00:00 2001 From: Pawel Spychalski Date: Wed, 16 May 2018 15:08:58 +0200 Subject: [PATCH 6/8] SAMD compiler fixes --- crossbow/crossbow.ino | 2 +- crossbow/radio_node.h | 4 ++-- crossbow/tx_oled.h | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crossbow/crossbow.ino b/crossbow/crossbow.ino index e3c3138..a7fd2b4 100644 --- a/crossbow/crossbow.ino +++ b/crossbow/crossbow.ino @@ -33,7 +33,7 @@ Copyright (c) 20xx, MPL Contributor1 contrib1@example.net #error please select hardware #endif -volatile RadioNode radioNode; +RadioNode radioNode; /* * Main defines for device working in TX mode diff --git a/crossbow/radio_node.h b/crossbow/radio_node.h index e88fcc1..736c862 100644 --- a/crossbow/radio_node.h +++ b/crossbow/radio_node.h @@ -35,8 +35,8 @@ class RadioNode { void handleChannelDwell(void); void handleTxDoneState(); void handleTx(QspConfiguration_t *qsp); - int8_t bytesToRead = -1; - uint8_t deviceState = RADIO_STATE_RX; + volatile int8_t bytesToRead = -1; + volatile uint8_t deviceState = RADIO_STATE_RX; uint8_t rssi = 0; uint8_t snr = 0; uint8_t lastReceivedChannel = 0; diff --git a/crossbow/tx_oled.h b/crossbow/tx_oled.h index 41c4b33..5008b96 100644 --- a/crossbow/tx_oled.h +++ b/crossbow/tx_oled.h @@ -9,7 +9,7 @@ #include "tactile.h" #include "radio_node.h" -extern volatile RadioNode radioNode; +extern RadioNode radioNode; enum txOledPages { TX_PAGE_NONE, From 1c2bd0055e2ef9785d158123f30830734f53227b Mon Sep 17 00:00:00 2001 From: Pawel Spychalski Date: Wed, 16 May 2018 15:23:22 +0200 Subject: [PATCH 7/8] more SAMD fixes --- crossbow/radio_node.cpp | 6 +++--- crossbow/radio_node.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crossbow/radio_node.cpp b/crossbow/radio_node.cpp index 39fa248..0e7110e 100644 --- a/crossbow/radio_node.cpp +++ b/crossbow/radio_node.cpp @@ -50,15 +50,15 @@ uint32_t RadioNode::getChannelEntryMillis(void) { return _channelEntryMillis; } -static uint32_t RadioNode::getFrequencyForChannel(uint8_t channel) { +uint32_t RadioNode::getFrequencyForChannel(uint8_t channel) { return RADIO_FREQUENCY_MIN + (RADIO_CHANNEL_WIDTH * channel); } -static uint8_t RadioNode::getNextChannel(uint8_t channel) { +uint8_t RadioNode::getNextChannel(uint8_t channel) { return (channel + RADIO_HOP_OFFSET) % RADIO_CHANNEL_COUNT; } -static uint8_t RadioNode::getPrevChannel(uint8_t channel) { +uint8_t RadioNode::getPrevChannel(uint8_t channel) { return (RADIO_CHANNEL_COUNT + channel - RADIO_HOP_OFFSET) % RADIO_CHANNEL_COUNT; } diff --git a/crossbow/radio_node.h b/crossbow/radio_node.h index 736c862..43b1dd6 100644 --- a/crossbow/radio_node.h +++ b/crossbow/radio_node.h @@ -21,9 +21,9 @@ class RadioNode { void init(uint8_t ss, uint8_t rst, uint8_t di0, void(*callback)(int)); void readRssi(void); void readSnr(void); - static uint32_t getFrequencyForChannel(uint8_t channel); - static uint8_t getNextChannel(uint8_t channel); - static uint8_t getPrevChannel(uint8_t channel); + uint32_t getFrequencyForChannel(uint8_t channel); + uint8_t getNextChannel(uint8_t channel); + uint8_t getPrevChannel(uint8_t channel); void hopFrequency(bool forward, uint8_t fromChannel, uint32_t timestamp); void readAndDecode( QspConfiguration_t *qsp, From 35053daa908bc9eedd7ddc3af84a8bed433bac54 Mon Sep 17 00:00:00 2001 From: "Pawel Spychalski (DzikuVx)" Date: Wed, 16 May 2018 17:06:03 +0200 Subject: [PATCH 8/8] bugfixes --- .vscode/arduino.json | 2 +- crossbow/crossbow.ino | 28 ++++++++++++++-------------- crossbow/radio_node.cpp | 9 +++++---- crossbow/radio_node.h | 2 +- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/.vscode/arduino.json b/.vscode/arduino.json index 09e7173..e8e6b14 100644 --- a/.vscode/arduino.json +++ b/.vscode/arduino.json @@ -1,6 +1,6 @@ { "board": "bsfrance:avr:lora32u4", "sketch": "crossbow/crossbow.ino", - "port": "COM11", + "port": "COM7", "output": "../build" } \ No newline at end of file diff --git a/crossbow/crossbow.ino b/crossbow/crossbow.ino index a7fd2b4..4b53ad0 100644 --- a/crossbow/crossbow.ino +++ b/crossbow/crossbow.ino @@ -285,7 +285,18 @@ void loop(void) uint32_t currentMillis = millis(); -#ifdef DEVICE_MODE_TX +#ifdef DEVICE_MODE_RX + /* + * This routine handles resync of TX/RX while hoppping frequencies + */ + radioNode.handleChannelDwell(); + + /* + * Detect the moment when radio module stopped transmittig and put it + * back in to receive state + */ + radioNode.handleTxDoneState(false); +#else //Process buttons button0.loop(); @@ -314,21 +325,10 @@ void loop(void) txInput.restart(); serialRestartMillis = currentMillis; } -#endif - /* - * This routine handles resync of TX/RX while hoppping frequencies - */ -#ifdef DEVICE_MODE_RX - radioNode.handleChannelDwell(); + radioNode.handleTxDoneState(true); #endif - /* - * Detect the moment when radio module stopped transmittig and put it - * back in to receive state - */ - radioNode.handleTxDoneState(); - radioNode.readAndDecode( &qsp, &rxDeviceState, @@ -356,7 +356,7 @@ void loop(void) qsp.protocolState == QSP_STATE_IDLE && qsp.lastTxSlotTimestamp + TX_TRANSMIT_SLOT_RATE < currentMillis ) { - + int8_t frameToSend = getFrameToTransmit(&qsp); #ifndef FORCE_TX_WITHOUT_INPUT diff --git a/crossbow/radio_node.cpp b/crossbow/radio_node.cpp index 0e7110e..772dec8 100644 --- a/crossbow/radio_node.cpp +++ b/crossbow/radio_node.cpp @@ -119,8 +119,9 @@ void RadioNode::handleChannelDwell(void) { } } -void RadioNode::handleTxDoneState(void) { +void RadioNode::handleTxDoneState(bool hop) { uint32_t currentMillis = millis(); + if ( currentMillis > nextTxCheckMillis && deviceState == RADIO_STATE_TX && @@ -130,9 +131,9 @@ void RadioNode::handleTxDoneState(void) { /* * In case of TX module, hop right now */ -#ifdef DEVICE_MODE_TX - hopFrequency(true, getChannel(), currentMillis); -#endif + if (hop) { + hopFrequency(true, getChannel(), currentMillis); + } LoRa.receive(); deviceState = RADIO_STATE_RX; diff --git a/crossbow/radio_node.h b/crossbow/radio_node.h index 43b1dd6..e720c5c 100644 --- a/crossbow/radio_node.h +++ b/crossbow/radio_node.h @@ -33,7 +33,7 @@ class RadioNode { uint8_t getChannel(void); uint32_t getChannelEntryMillis(void); void handleChannelDwell(void); - void handleTxDoneState(); + void handleTxDoneState(bool hop); void handleTx(QspConfiguration_t *qsp); volatile int8_t bytesToRead = -1; volatile uint8_t deviceState = RADIO_STATE_RX;