Add support for KISS extension for radio control and signal reports

pull/15/head
sh123 2021-02-05 18:57:06 +02:00
rodzic 1f1b3efb7e
commit 4c178d8c65
7 zmienionych plików z 110 dodań i 36 usunięć

Wyświetl plik

@ -33,3 +33,4 @@
#define CFG_RF_TO_IS true
#define CFG_IS_TO_RF false
#define CFG_BEACON false
#define CFG_KISS_EXTENSIONS false

Wyświetl plik

@ -25,7 +25,7 @@ void initializeConfig(LoraPrs::Config &cfg) {
// client/server mode switch
cfg.IsClientMode = CFG_IS_CLIENT_MODE;
// lora parameters
cfg.LoraFreq = CFG_LORA_FREQ;
cfg.LoraBw = CFG_LORA_BW;
@ -64,6 +64,7 @@ void initializeConfig(LoraPrs::Config &cfg) {
cfg.EnableIsToRf = CFG_IS_TO_RF; // send data from aprsis to rf
cfg.EnableRepeater = CFG_DIGIREPEAT; // digirepeat incoming packets
cfg.EnableBeacon = CFG_BEACON; // enable periodic AprsRawBeacon beacon to rf and aprsis if rf to aprsis is enabled
cfg.EnableKissExtensions = CFG_KISS_EXTENSIONS; // radio control and signal reports
}
LoraPrs::Service loraPrsService;

Wyświetl plik

@ -61,12 +61,13 @@ void Processor::resetState()
state_ = State::Void;
}
bool Processor::processCommand(unsigned char rxByte) {
bool Processor::processCommand(byte rxByte) {
switch (rxByte) {
case Cmd::Data:
if (!onRigTxBegin()) return false;
state_ = State::GetData;
dataType_ = DataType::Raw;
break;
case Cmd::P:
state_ = State::GetP;
@ -74,6 +75,11 @@ bool Processor::processCommand(unsigned char rxByte) {
case Cmd::SlotTime:
state_ = State::GetSlotTime;
break;
case Cmd::RadioControl:
state_ = State::GetData;
dataType_ = DataType::Control;
cmdBuffer_.clear();
break;
default:
// unknown command
resetState();
@ -83,7 +89,34 @@ bool Processor::processCommand(unsigned char rxByte) {
return true;
}
bool Processor::receiveByte(unsigned char rxByte) {
void Processor::processData(byte rxByte) {
switch (rxByte) {
case Marker::Fesc:
state_ = State::Escape;
break;
case Marker::Fend:
if (cmd_ == Cmd::Data) {
if (dataType_ == DataType::Raw) {
onRigTxEnd();
} else if (dataType_ == DataType::Control) {
onRadioControlCommand(cmdBuffer_);
}
}
resetState();
break;
default:
if (cmd_ == Cmd::Data) {
if (dataType_ == DataType::Raw) {
onRigTx(rxByte);
} else if (dataType_ == DataType::Control) {
cmdBuffer_.push_back(rxByte);
}
}
break;
}
}
bool Processor::receiveByte(byte rxByte) {
switch (state_) {
case State::Void:
@ -106,18 +139,7 @@ bool Processor::receiveByte(unsigned char rxByte) {
state_ = State::GetData;
break;
case State::GetData:
if (rxByte == Marker::Fesc) {
state_ = State::Escape;
}
else if (rxByte == Marker::Fend) {
if (cmd_ == Cmd::Data) {
onRigTxEnd();
}
resetState();
}
else if (cmd_ == Cmd::Data) {
onRigTx(rxByte);
}
processData(rxByte);
break;
case State::Escape:
if (rxByte == Marker::Tfend) {

Wyświetl plik

@ -40,22 +40,20 @@ protected:
SlotTime = 0x03,
// extended to modem
Frequency = 0x10,
Bandwidth = 0x11,
Power = 0x12,
SyncWord = 0x13,
SpreadingFactor = 0x14,
CodingRate = 0x15,
EnableCrc = 0x16,
RadioControl = 0x10,
// extended events from modem
SignalLevelRssi = 0x30,
SignalLevelSnr = 0x31,
// extended from modem
RadioSignalLevel = 0x30,
// end of cmds
NoCmd = 0x80
};
enum DataType {
Raw = 0,
Control
};
const int CfgTxQueueSize = 4096;
protected:
@ -68,20 +66,20 @@ protected:
virtual bool onSerialRx(byte *b) = 0;
virtual void onControlCommand(Cmd cmd, byte value) = 0;
/*
virtual void onControlCommand(Cmd cmd, int value) = 0;
virtual void onControlCommand(Cmd cmd, long value) = 0;
*/
virtual void onRadioControlCommand(const std::vector<byte> &command) = 0;
private:
bool receiveByte(unsigned char rxByte);
bool processCommand(unsigned char rxByte);
bool receiveByte(byte rxByte);
void processData(byte rxByte);
bool processCommand(byte rxByte);
void resetState();
private:
Cmd cmd_;
DataType dataType_;
State state_;
std::shared_ptr<cppQueue> txQueue_;
std::vector<byte> cmdBuffer_;
};
} // Kiss

Wyświetl plik

@ -13,8 +13,8 @@ struct Config
long LoraBw; // lora bandwidth, e.g. 125e3
int LoraSf; // lora spreading factor, e.g. 12
int LoraCodingRate; // lora coding rate, e.g. 7
int LoraSync; // lora sync word/packet id, 0x3f
int LoraPower; // lora power level in dbm, 20
int LoraSync; // lora sync word/packet id, 0x3f
bool LoraEnableCrc; // lora crc check enabled
byte LoraPinSs; // lora ss pin
@ -41,6 +41,7 @@ struct Config
bool EnableIsToRf; // true - enable APRS-IS to RF submission
bool EnableRepeater; // true - digirepeat incoming packets based on WIDEn-n paths
bool EnableBeacon; // true - send AprsRawBeacon to RF and APRS-IS if EnableRfToIs is true
bool EnableKissExtensions; // true - enable kiss extensions for radio control and signal reports
};
} // LoraPrs

Wyświetl plik

@ -225,6 +225,16 @@ void Service::onAprsisDataAvailable()
}
}
void Service::sendSignalReportEvent(int rssi, float snr)
{
struct LoraSignalLevelEvent event;
event.rssi = htobe16(rssi);
event.snr = htobe16(snr * 100);
serialSend((const byte *)&event, sizeof(LoraSignalLevelEvent));
}
bool Service::sendAX25ToLora(const AX25::Payload &payload)
{
byte buf[CfgMaxAX25PayloadSize];
@ -250,12 +260,16 @@ void Service::onLoraDataAvailable(int packetSize)
}
serialSend(rxBuf, rxBufIndex);
long frequencyError = LoRa.packetFrequencyError();
if (config_.EnableAutoFreqCorrection) {
config_.LoraFreq -= frequencyError;
LoRa.setFrequency(config_.LoraFreq);
}
if (config_.EnableKissExtensions) {
sendSignalReportEvent(LoRa.packetRssi(), LoRa.packetSnr());
}
if (!config_.IsClientMode) {
processIncomingRawPacketAsServer(rxBuf, rxBufIndex);
}
@ -347,5 +361,23 @@ void Service::onControlCommand(Cmd cmd, byte value)
break;
}
}
void Service::onRadioControlCommand(const std::vector<byte> &rawCommand) {
if (config_.EnableKissExtensions && rawCommand.size() == sizeof(LoraControlCommand)) {
const struct LoraControlCommand * controlCommand = reinterpret_cast<const struct LoraControlCommand*>(rawCommand.data());
config_.LoraFreq = be32toh(controlCommand->freq);
config_.LoraBw = be32toh(controlCommand->bw);
config_.LoraSf = be16toh(controlCommand->sf);
config_.LoraCodingRate = be16toh(controlCommand->cr);
config_.LoraPower = be16toh(controlCommand->pwr);
config_.LoraSync = be16toh(controlCommand->sync);
config_.LoraEnableCrc = controlCommand->crc;
setupLora(config_.LoraFreq, config_.LoraBw, config_.LoraSf,
config_.LoraCodingRate, config_.LoraPower, config_.LoraSync, config_.LoraEnableCrc);
}
}
} // LoraPrs

Wyświetl plik

@ -6,6 +6,7 @@
#include <LoRa.h>
#include <WiFi.h>
#include <cppQueue.h>
#include <endian.h>
#include "BluetoothSerial.h"
#include "ax25_payload.h"
@ -33,6 +34,7 @@ private:
void onLoraDataAvailable(int packetSize);
void onAprsisDataAvailable();
void sendSignalReportEvent(int rssi, float snr);
void sendPeriodicBeacon();
void sendToAprsis(const String &aprsMessage);
bool sendAX25ToLora(const AX25::Payload &payload);
@ -55,7 +57,24 @@ protected:
virtual bool onSerialRx(byte *b);
virtual void onControlCommand(Cmd cmd, byte value);
virtual void onRadioControlCommand(const std::vector<byte> &command);
private:
struct LoraSignalLevelEvent {
int rssi;
int snr;
} __attribute__((packed));
struct LoraControlCommand {
long freq;
long bw;
int sf;
int cr;
int pwr;
int sync;
bool crc;
} __attribute__((packed));
private:
const String CfgLoraprsVersion = "LoRAPRS 0.1";
@ -65,7 +84,7 @@ private:
const int CfgWiFiConnRetryMaxTimes = 10;
const int CfgMaxAX25PayloadSize = 512;
// csma paramters, overriden with KISS commands
// csma parameters, overriden with KISS commands
const long CfgCsmaPersistence = 100; // 255 for real time, lower for higher traffic
const long CfgCsmaSlotTimeMs = 500; // 0 for real time, otherwise set to average tx duration