This commit is contained in:
Pawel Spychalski
2018-05-16 11:01:00 +02:00
parent 24efa929ca
commit a48497365d
6 changed files with 125 additions and 85 deletions

View File

@@ -13,6 +13,7 @@ Copyright (c) 20xx, MPL Contributor1 contrib1@example.net
#include "main_variables.h" #include "main_variables.h"
#include "qsp.h" #include "qsp.h"
#include "sbus.h" #include "sbus.h"
#include "radio_node.h"
#ifdef ARDUINO_AVR_FEATHER32U4 #ifdef ARDUINO_AVR_FEATHER32U4
#define LORA_SS_PIN 8 #define LORA_SS_PIN 8
@@ -32,6 +33,8 @@ Copyright (c) 20xx, MPL Contributor1 contrib1@example.net
#error please select hardware #error please select hardware
#endif #endif
volatile RadioNode radioNode;
/* /*
* Main defines for device working in TX mode * Main defines for device working in TX mode
*/ */
@@ -87,57 +90,18 @@ volatile RadioState_t radioState = {};
uint8_t tmpBuffer[MAX_PACKET_SIZE]; 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) { 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 //If recide received a valid frame, that means it can start to talk
qsp->canTransmit = true; qsp->canTransmit = true;
radioState->rssi = getRadioRssi(); radioState->rssi = radioNode.getRadioRssi();
radioState->snr = getRadioSnr(); radioState->snr = radioNode.getRadioSnr();
/* /*
* RX module hops to next channel after frame has been received * RX module hops to next channel after frame has been received
*/ */
#ifdef DEVICE_MODE_RX #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 radioState->failedDwellsCount = 0; // We received a frame, so we can just reset this counter
LoRa.receive(); //Put radio back into receive mode LoRa.receive(); //Put radio back into receive mode
#endif #endif
@@ -206,7 +170,7 @@ void setup(void)
LORA_DI0_PIN LORA_DI0_PIN
); );
if (!LoRa.begin(getFrequencyForChannel(radioState.channel))) { if (!LoRa.begin(radioNode.getFrequencyForChannel(radioNode.getChannel()))) {
while (true); while (true);
} }
@@ -384,15 +348,15 @@ void loop(void)
#ifdef DEVICE_MODE_RX #ifdef DEVICE_MODE_RX
//In the beginning just keep jumping forward and try to resync over lost single frames //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++; 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(); LoRa.receive();
} }
// If we are loosing more frames, start jumping in the opposite direction since probably we are completely out of sync now // 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) { if (radioState.failedDwellsCount >= 6 && radioNode.getChannelEntryMillis() + (RX_CHANNEL_DWELL_TIME * 5) < currentMillis) {
hopFrequency(&radioState, false, radioState.channel, radioState.channelEntryMillis + RX_CHANNEL_DWELL_TIME); //Start jumping in opposite direction to resync radioNode.hopFrequency(false, radioNode.getChannel(), radioNode.getChannelEntryMillis() + RX_CHANNEL_DWELL_TIME); //Start jumping in opposite direction to resync
LoRa.receive(); LoRa.receive();
} }
@@ -412,7 +376,7 @@ void loop(void)
* In case of TX module, hop right now * In case of TX module, hop right now
*/ */
#ifdef DEVICE_MODE_TX #ifdef DEVICE_MODE_TX
hopFrequency(&radioState, true, radioState.channel, millis()); radioNode.hopFrequency(true, radioNode.getChannel(), millis());
#endif #endif
LoRa.receive(); LoRa.receive();
@@ -566,7 +530,7 @@ void loop(void)
uint8_t size; uint8_t size;
LoRa.beginPacket(); LoRa.beginPacket();
//Prepare packet //Prepare packet
qspEncodeFrame(&qsp, &radioState, tmpBuffer, &size); qspEncodeFrame(&qsp, &radioState, tmpBuffer, &size, radioNode.getChannel());
//Sent it to radio in one SPI transaction //Sent it to radio in one SPI transaction
LoRa.write(tmpBuffer, size); LoRa.write(tmpBuffer, size);
LoRa.endPacketAsync(); LoRa.endPacketAsync();

View File

@@ -224,14 +224,14 @@ void qspDecodeIncomingFrame(
/** /**
* Encode frame is corrent format and write to hardware * 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 //Salt CRC with bind key
qspInitCrc(qsp); qspInitCrc(qsp);
//Write frame type and length //Write frame type and length
// We are no longer sending payload length, so 4 bits are now free for other usages // 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 = qsp->payloadLength & 0x0f;
uint8_t data = radioState->channel; uint8_t data = radioChannel;
data |= (qsp->frameToSend << 4) & 0xf0; data |= (qsp->frameToSend << 4) & 0xf0;
qspComputeCrc(qsp, data); qspComputeCrc(qsp, data);
buffer[0] = data; buffer[0] = data;

View File

@@ -16,6 +16,6 @@ void qspDecodeIncomingFrame(
volatile RadioState_t *radioState volatile RadioState_t *radioState
); );
void qspClearPayload(QspConfiguration_t *qsp); 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); void encodePingPayload(QspConfiguration_t *qsp, uint32_t currentMicros);

53
crossbow/radio_node.cpp Normal file
View File

@@ -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();
}

55
crossbow/radio_node.h Normal file
View File

@@ -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

View File

@@ -1,4 +1,5 @@
#include "Arduino.h" #include "Arduino.h"
#include "radio_node.h"
#pragma once #pragma once
@@ -13,11 +14,6 @@
#define RX_TASK_HEALTH 200 //5Hz should be enough #define RX_TASK_HEALTH 200 //5Hz should be enough
#define RSSI_CHANNEL 11 #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 CHANNEL_ID 0x01
#define QSP_PAYLOAD_LENGTH 32 #define QSP_PAYLOAD_LENGTH 32
@@ -83,34 +79,6 @@ enum debugConfigFlags {
#define NO_DATA_TO_READ -1 #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 { struct TxDeviceState_t {
uint8_t flags = 0; uint8_t flags = 0;
uint32_t roundtrip = 0; uint32_t roundtrip = 0;