kopia lustrzana https://github.com/sh123/esp32_loraprs
Added circular buffers for both tx and rx, use LoRa ISR for receve with optional possibility to switch it off
rodzic
c4addc78a0
commit
8636f1eb9d
|
@ -66,7 +66,7 @@ Install via libraries:
|
||||||
- Arduino ESP32 library: https://github.com/espressif/arduino-esp32
|
- Arduino ESP32 library: https://github.com/espressif/arduino-esp32
|
||||||
- LoRa arduino library: https://github.com/sandeepmistry/arduino-LoRa
|
- LoRa arduino library: https://github.com/sandeepmistry/arduino-LoRa
|
||||||
- Arduino Timer library: https://github.com/contrem/arduino-timer
|
- Arduino Timer library: https://github.com/contrem/arduino-timer
|
||||||
- cppQueue library: https://github.com/SMFSW/Queue
|
- CircularBuffer library: https://github.com/rlogiacco/CircularBuffer
|
||||||
|
|
||||||
# Software Setup
|
# Software Setup
|
||||||
- **NB! select next partition scheme for ESP32 in Arduino IDE Tools menu:** "Minimal SPIFFS (1.9 MB APP with OTA/190 KB SPIFFS)"
|
- **NB! select next partition scheme for ESP32 in Arduino IDE Tools menu:** "Minimal SPIFFS (1.9 MB APP with OTA/190 KB SPIFFS)"
|
||||||
|
|
|
@ -34,6 +34,7 @@ void initializeConfig(LoraPrs::Config &cfg) {
|
||||||
cfg.LoraPinSs = CFG_LORA_PIN_SS;
|
cfg.LoraPinSs = CFG_LORA_PIN_SS;
|
||||||
cfg.LoraPinRst = CFG_LORA_PIN_RST;
|
cfg.LoraPinRst = CFG_LORA_PIN_RST;
|
||||||
cfg.LoraPinDio0 = CFG_LORA_PIN_DIO0;
|
cfg.LoraPinDio0 = CFG_LORA_PIN_DIO0;
|
||||||
|
cfg.LoraUseIsr = true;
|
||||||
|
|
||||||
// aprs configuration
|
// aprs configuration
|
||||||
cfg.AprsHost = "rotate.aprs2.net";
|
cfg.AprsHost = "rotate.aprs2.net";
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
#include "kiss_processor.h"
|
#include "kiss_processor.h"
|
||||||
|
|
||||||
namespace Kiss {
|
namespace Kiss {
|
||||||
|
|
||||||
|
CircularBuffer<uint8_t, Processor::CfgSerialToRigQueueSize> Processor::serialToRigQueue_;
|
||||||
|
CircularBuffer<uint8_t, Processor::CfgRigToSerialQueueSize> Processor::rigToSerialQueue_;
|
||||||
|
CircularBuffer<uint8_t, Processor::CfgRigToSerialQueueSize> Processor::rigToSerialQueueIndex_;
|
||||||
|
|
||||||
Processor::Processor()
|
Processor::Processor()
|
||||||
: state_(State::GetStart)
|
: state_(State::GetStart)
|
||||||
, txQueue_(new cppQueue(sizeof(unsigned char), CfgTxQueueSize))
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Processor::serialSend(Cmd cmd, const byte *b, int dataLength) {
|
void Processor::serialSend(Cmd cmd, const byte *packet, int packetLength) {
|
||||||
onSerialTx((byte)Marker::Fend);
|
onSerialTx((byte)Marker::Fend);
|
||||||
onSerialTx((byte)cmd);
|
onSerialTx((byte)cmd);
|
||||||
|
|
||||||
for (int i = 0; i < dataLength; i++) {
|
for (int i = 0; i < packetLength; i++) {
|
||||||
byte rxByte = b[i];
|
byte rxByte = packet[i];
|
||||||
|
|
||||||
if (rxByte == Marker::Fend) {
|
if (rxByte == Marker::Fend) {
|
||||||
onSerialTx((byte)Marker::Fesc);
|
onSerialTx((byte)Marker::Fesc);
|
||||||
|
@ -26,33 +29,101 @@ void Processor::serialSend(Cmd cmd, const byte *b, int dataLength) {
|
||||||
else {
|
else {
|
||||||
onSerialTx(rxByte);
|
onSerialTx(rxByte);
|
||||||
}
|
}
|
||||||
yield();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onSerialTx((byte)Marker::Fend);
|
onSerialTx((byte)Marker::Fend);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Processor::serialProcessRx()
|
void ICACHE_RAM_ATTR Processor::serialQueueIsr(Cmd cmd, const byte *packet, int packetLength) {
|
||||||
|
if (!rigToSerialQueueIndex_.unshift(packetLength)) {
|
||||||
|
Serial.println("Rig to serial queue is full!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < packetLength; i++) {
|
||||||
|
if (!rigToSerialQueue_.unshift(packet[i])) {
|
||||||
|
Serial.println("Rig to serial queue is full!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Processor::rigQueue(Cmd cmd, const byte *packet, int packetLength) {
|
||||||
|
bool result = 1;
|
||||||
|
result &= serialToRigQueue_.unshift(Marker::Fend);
|
||||||
|
result &= serialToRigQueue_.unshift(cmd);
|
||||||
|
|
||||||
|
for (int i = 0; i < packetLength; i++) {
|
||||||
|
byte rxByte = packet[i];
|
||||||
|
|
||||||
|
if (rxByte == Marker::Fend) {
|
||||||
|
result &= serialToRigQueue_.unshift(Marker::Fesc);
|
||||||
|
result &= serialToRigQueue_.unshift(Marker::Tfend);
|
||||||
|
}
|
||||||
|
else if (rxByte == Marker::Fesc) {
|
||||||
|
result &= serialToRigQueue_.unshift(Marker::Fesc);
|
||||||
|
result &= serialToRigQueue_.unshift(Marker::Tfesc);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result &= serialToRigQueue_.unshift(rxByte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result &= serialToRigQueue_.unshift(Marker::Fend);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
Serial.println("Serial to rig queue overflow!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Processor::processRigToSerial()
|
||||||
|
{
|
||||||
|
bool isProcessed = false;
|
||||||
|
|
||||||
|
if (rigToSerialQueueIndex_.isEmpty()) {
|
||||||
|
return isProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!rigToSerialQueueIndex_.isEmpty()) {
|
||||||
|
|
||||||
|
int rxPacketSize = rigToSerialQueueIndex_.pop();
|
||||||
|
byte buf[rxPacketSize];
|
||||||
|
|
||||||
|
for (int i = 0; i < rxPacketSize; i++) {
|
||||||
|
buf[i] = rigToSerialQueue_.pop();
|
||||||
|
}
|
||||||
|
serialSend(Cmd::Data, buf, rxPacketSize);
|
||||||
|
onRigPacket(&buf, rxPacketSize);
|
||||||
|
|
||||||
|
isProcessed = true;
|
||||||
|
yield();
|
||||||
|
}
|
||||||
|
return isProcessed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Processor::processSerialToRig()
|
||||||
{
|
{
|
||||||
while (onSerialRxHasData() || !txQueue_->isEmpty()) {
|
bool isProcessed = false;
|
||||||
|
|
||||||
|
while (onSerialRxHasData() || !serialToRigQueue_.isEmpty()) {
|
||||||
byte rxByte;
|
byte rxByte;
|
||||||
if (onSerialRxHasData()) {
|
if (onSerialRxHasData()) {
|
||||||
if (onSerialRx(&rxByte)) {
|
if (onSerialRx(&rxByte)) {
|
||||||
if (!txQueue_->push((void *)&rxByte)) {
|
if (!serialToRigQueue_.unshift(rxByte)) {
|
||||||
Serial.println("TX queue is full");
|
Serial.println("Serial to rig buffer is full!");
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!txQueue_->isEmpty()) {
|
if (!serialToRigQueue_.isEmpty()) {
|
||||||
if (txQueue_->peek((void *)&rxByte)) {
|
rxByte = serialToRigQueue_.pop();
|
||||||
if (receiveByte(rxByte)) {
|
if (receiveByte(rxByte)) {
|
||||||
txQueue_->drop();
|
isProcessed = true;
|
||||||
}
|
} else {
|
||||||
|
serialToRigQueue_.push(rxByte);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
yield();
|
yield();
|
||||||
}
|
}
|
||||||
|
return isProcessed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Processor::processCommand(byte rxByte) {
|
bool Processor::processCommand(byte rxByte) {
|
||||||
|
|
|
@ -2,9 +2,11 @@
|
||||||
#define KISS_PROCESSOR_H
|
#define KISS_PROCESSOR_H
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <cppQueue.h>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
#define CIRCULAR_BUFFER_INT_SAFE
|
||||||
|
#include <CircularBuffer.h>
|
||||||
|
|
||||||
namespace Kiss {
|
namespace Kiss {
|
||||||
|
|
||||||
class Processor {
|
class Processor {
|
||||||
|
@ -41,19 +43,26 @@ protected:
|
||||||
Control
|
Control
|
||||||
};
|
};
|
||||||
|
|
||||||
const int CfgTxQueueSize = 4096;
|
static const int CfgSerialToRigQueueSize = 4096;
|
||||||
|
static const int CfgRigToSerialQueueSize = 4096;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Processor();
|
Processor();
|
||||||
|
|
||||||
void serialSend(Cmd cmd, const byte *b, int dataLength);
|
void serialSend(Cmd cmd, const byte *packet, int packetLength);
|
||||||
void serialProcessRx();
|
static void ICACHE_RAM_ATTR serialQueueIsr(Cmd cmd, const byte *packet, int packetLength);
|
||||||
|
|
||||||
|
void rigQueue(Cmd cmd, const byte *packet, int packetLength);
|
||||||
|
|
||||||
|
bool processRigToSerial();
|
||||||
|
bool processSerialToRig();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool onRigTxBegin() = 0;
|
virtual bool onRigTxBegin() = 0;
|
||||||
virtual void onRigTx(byte b) = 0;
|
virtual void onRigTx(byte b) = 0;
|
||||||
virtual void onRigTxEnd() = 0;
|
virtual void onRigTxEnd() = 0;
|
||||||
|
virtual void onRigPacket(void *packet, int packetLength) = 0;
|
||||||
|
|
||||||
virtual void onSerialTx(byte b) = 0;
|
virtual void onSerialTx(byte b) = 0;
|
||||||
virtual bool onSerialRxHasData() = 0;
|
virtual bool onSerialRxHasData() = 0;
|
||||||
virtual bool onSerialRx(byte *b) = 0;
|
virtual bool onSerialRx(byte *b) = 0;
|
||||||
|
@ -69,8 +78,11 @@ private:
|
||||||
private:
|
private:
|
||||||
State state_;
|
State state_;
|
||||||
DataType dataType_;
|
DataType dataType_;
|
||||||
std::shared_ptr<cppQueue> txQueue_;
|
|
||||||
std::vector<byte> cmdBuffer_;
|
std::vector<byte> cmdBuffer_;
|
||||||
|
|
||||||
|
static CircularBuffer<uint8_t, CfgSerialToRigQueueSize> serialToRigQueue_;
|
||||||
|
static CircularBuffer<uint8_t, CfgRigToSerialQueueSize> rigToSerialQueue_;
|
||||||
|
static CircularBuffer<uint8_t, CfgRigToSerialQueueSize> rigToSerialQueueIndex_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // Kiss
|
} // Kiss
|
||||||
|
|
|
@ -20,6 +20,7 @@ struct Config
|
||||||
byte LoraPinSs; // lora ss pin
|
byte LoraPinSs; // lora ss pin
|
||||||
byte LoraPinRst; // lora rst pin
|
byte LoraPinRst; // lora rst pin
|
||||||
byte LoraPinDio0; // lora dio0 pin
|
byte LoraPinDio0; // lora dio0 pin
|
||||||
|
bool LoraUseIsr; // true to use interrupts
|
||||||
|
|
||||||
int AprsPort; // aprs server port, 14580
|
int AprsPort; // aprs server port, 14580
|
||||||
String AprsHost; // aprs server hostname, rotate.aprs2.net
|
String AprsHost; // aprs server hostname, rotate.aprs2.net
|
||||||
|
|
|
@ -20,18 +20,18 @@ void Service::setup(const Config &conf)
|
||||||
if (!ownCallsign_.IsValid()) {
|
if (!ownCallsign_.IsValid()) {
|
||||||
Serial.println("Own callsign is not valid");
|
Serial.println("Own callsign is not valid");
|
||||||
}
|
}
|
||||||
|
|
||||||
aprsLoginCommand_ = String("user ") + config_.AprsLogin + String(" pass ") +
|
aprsLoginCommand_ = String("user ") + config_.AprsLogin + String(" pass ") +
|
||||||
config_.AprsPass + String(" vers ") + CfgLoraprsVersion;
|
config_.AprsPass + String(" vers ") + CfgLoraprsVersion;
|
||||||
if (config_.AprsFilter.length() > 0) {
|
if (config_.AprsFilter.length() > 0) {
|
||||||
aprsLoginCommand_ += String(" filter ") + config_.AprsFilter;
|
aprsLoginCommand_ += String(" filter ") + config_.AprsFilter;
|
||||||
}
|
}
|
||||||
aprsLoginCommand_ += String("\n");
|
aprsLoginCommand_ += String("\n");
|
||||||
|
|
||||||
// peripherals
|
// peripherals
|
||||||
setupLora(config_.LoraFreq, config_.LoraBw, config_.LoraSf,
|
setupLora(config_.LoraFreq, config_.LoraBw, config_.LoraSf,
|
||||||
config_.LoraCodingRate, config_.LoraPower, config_.LoraSync, config_.LoraEnableCrc);
|
config_.LoraCodingRate, config_.LoraPower, config_.LoraSync, config_.LoraEnableCrc);
|
||||||
|
|
||||||
if (needsWifi()) {
|
if (needsWifi()) {
|
||||||
setupWifi(config_.WifiSsid, config_.WifiKey);
|
setupWifi(config_.WifiSsid, config_.WifiKey);
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ void Service::setup(const Config &conf)
|
||||||
if (needsBt() || config_.BtName.length() > 0) {
|
if (needsBt() || config_.BtName.length() > 0) {
|
||||||
setupBt(config_.BtName);
|
setupBt(config_.BtName);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsAprsis() && config_.EnablePersistentAprsConnection) {
|
if (needsAprsis() && config_.EnablePersistentAprsConnection) {
|
||||||
reconnectAprsis();
|
reconnectAprsis();
|
||||||
}
|
}
|
||||||
|
@ -125,8 +125,12 @@ void Service::setupLora(long loraFreq, long bw, int sf, int cr, int pwr, int syn
|
||||||
if (enableCrc) {
|
if (enableCrc) {
|
||||||
LoRa.enableCrc();
|
LoRa.enableCrc();
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println("ok");
|
if (config_.LoraUseIsr) {
|
||||||
|
LoRa.onReceive(onLoraDataAvailableIsr);
|
||||||
|
LoRa.receive();
|
||||||
|
}
|
||||||
|
Serial.println("ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Service::setupBt(const String &btName)
|
void Service::setupBt(const String &btName)
|
||||||
|
@ -152,11 +156,20 @@ void Service::loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
// RX path, Rig -> Serial
|
// RX path, Rig -> Serial
|
||||||
if (int packetSize = LoRa.parsePacket()) {
|
bool isRigToSerialProcessed = false;
|
||||||
onLoraDataAvailable(packetSize);
|
|
||||||
|
if (config_.LoraUseIsr) {
|
||||||
|
isRigToSerialProcessed = processRigToSerial();
|
||||||
|
} else {
|
||||||
|
if (int packetSize = LoRa.parsePacket()) {
|
||||||
|
loraReceive(packetSize);
|
||||||
|
isRigToSerialProcessed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TX path, Serial -> Rig
|
// TX path, Serial -> Rig
|
||||||
else {
|
if (!isRigToSerialProcessed) {
|
||||||
|
|
||||||
long currentTime = millis();
|
long currentTime = millis();
|
||||||
if (currentTime > csmaSlotTimePrev_ + csmaSlotTime_ && random(0, 255) < csmaP_) {
|
if (currentTime > csmaSlotTimePrev_ + csmaSlotTime_ && random(0, 255) < csmaP_) {
|
||||||
if (aprsisConn_.available() > 0) {
|
if (aprsisConn_.available() > 0) {
|
||||||
|
@ -166,7 +179,9 @@ void Service::loop()
|
||||||
sendPeriodicBeacon();
|
sendPeriodicBeacon();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
serialProcessRx();
|
if (processSerialToRig() && config_.LoraUseIsr) {
|
||||||
|
LoRa.receive();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
csmaSlotTimePrev_ = currentTime;
|
csmaSlotTimePrev_ = currentTime;
|
||||||
}
|
}
|
||||||
|
@ -174,6 +189,18 @@ void Service::loop()
|
||||||
delay(CfgPollDelayMs);
|
delay(CfgPollDelayMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ICACHE_RAM_ATTR void Service::onLoraDataAvailableIsr(int packetSize)
|
||||||
|
{
|
||||||
|
// TODO, move to separate ESP32 task
|
||||||
|
int rxBufIndex = 0;
|
||||||
|
byte rxBuf[packetSize];
|
||||||
|
|
||||||
|
for (int i = 0; i < packetSize; i++) {
|
||||||
|
rxBuf[rxBufIndex++] = LoRa.read();
|
||||||
|
}
|
||||||
|
serialQueueIsr(Cmd::Data, rxBuf, rxBufIndex);
|
||||||
|
}
|
||||||
|
|
||||||
void Service::sendPeriodicBeacon()
|
void Service::sendPeriodicBeacon()
|
||||||
{
|
{
|
||||||
long currentMs = millis();
|
long currentMs = millis();
|
||||||
|
@ -212,7 +239,7 @@ void Service::sendToAprsis(const String &aprsMessage)
|
||||||
void Service::onAprsisDataAvailable()
|
void Service::onAprsisDataAvailable()
|
||||||
{
|
{
|
||||||
String aprsisData;
|
String aprsisData;
|
||||||
|
|
||||||
while (aprsisConn_.available() > 0) {
|
while (aprsisConn_.available() > 0) {
|
||||||
char c = aprsisConn_.read();
|
char c = aprsisConn_.read();
|
||||||
if (c == '\r') continue;
|
if (c == '\r') continue;
|
||||||
|
@ -231,7 +258,7 @@ void Service::onAprsisDataAvailable()
|
||||||
sendAX25ToLora(payload);
|
sendAX25ToLora(payload);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Serial.println("Unknown payload from APRSIS, ignoring...");
|
Serial.println("Unknown payload from APRSIS, ignoring");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,7 +273,7 @@ void Service::sendSignalReportEvent(int rssi, float snr)
|
||||||
serialSend(Cmd::SignalReport, (const byte *)&signalReport, sizeof(SignalReport));
|
serialSend(Cmd::SignalReport, (const byte *)&signalReport, sizeof(SignalReport));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Service::sendAX25ToLora(const AX25::Payload &payload)
|
bool Service::sendAX25ToLora(const AX25::Payload &payload)
|
||||||
{
|
{
|
||||||
byte buf[CfgMaxAX25PayloadSize];
|
byte buf[CfgMaxAX25PayloadSize];
|
||||||
int bytesWritten = payload.ToBinary(buf, sizeof(buf));
|
int bytesWritten = payload.ToBinary(buf, sizeof(buf));
|
||||||
|
@ -254,63 +281,69 @@ bool Service::sendAX25ToLora(const AX25::Payload &payload)
|
||||||
Serial.println("Failed to serialize payload");
|
Serial.println("Failed to serialize payload");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
LoRa.beginPacket();
|
rigQueue(Cmd::Data, buf, bytesWritten);
|
||||||
LoRa.write(buf, bytesWritten);
|
|
||||||
LoRa.endPacket();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Service::onLoraDataAvailable(int packetSize)
|
void Service::onRigPacket(void *packet, int packetLength)
|
||||||
{
|
{
|
||||||
int rxBufIndex = 0;
|
|
||||||
byte rxBuf[packetSize];
|
|
||||||
|
|
||||||
while (LoRa.available()) {
|
|
||||||
byte rxByte = LoRa.read();
|
|
||||||
rxBuf[rxBufIndex++] = rxByte;
|
|
||||||
yield();
|
|
||||||
}
|
|
||||||
serialSend(Cmd::Data, rxBuf, rxBufIndex);
|
|
||||||
long frequencyError = LoRa.packetFrequencyError();
|
long frequencyError = LoRa.packetFrequencyError();
|
||||||
|
|
||||||
if (config_.EnableAutoFreqCorrection && abs(frequencyError) > CfgFreqCorrMinHz) {
|
if (config_.EnableAutoFreqCorrection && abs(frequencyError) > CfgFreqCorrMinHz) {
|
||||||
config_.LoraFreq -= frequencyError;
|
config_.LoraFreq -= frequencyError;
|
||||||
|
Serial.print("Correcting frequency: "); Serial.println(frequencyError);
|
||||||
LoRa.setFrequency(config_.LoraFreq);
|
LoRa.setFrequency(config_.LoraFreq);
|
||||||
|
if (config_.LoraUseIsr) {
|
||||||
|
LoRa.idle();
|
||||||
|
LoRa.receive();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config_.EnableKissExtensions) {
|
if (config_.EnableKissExtensions) {
|
||||||
sendSignalReportEvent(LoRa.packetRssi(), LoRa.packetSnr());
|
sendSignalReportEvent(LoRa.packetRssi(), LoRa.packetSnr());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config_.IsClientMode) {
|
if (!config_.IsClientMode) {
|
||||||
processIncomingRawPacketAsServer(rxBuf, rxBufIndex);
|
processIncomingRawPacketAsServer((const byte*)packet, packetLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Service::loraReceive(int packetSize)
|
||||||
|
{
|
||||||
|
int rxBufIndex = 0;
|
||||||
|
byte rxBuf[packetSize];
|
||||||
|
|
||||||
|
while (LoRa.available()) {
|
||||||
|
rxBuf[rxBufIndex++] = LoRa.read();
|
||||||
|
}
|
||||||
|
serialSend(Cmd::Data, rxBuf, rxBufIndex);
|
||||||
|
onRigPacket(rxBuf, rxBufIndex);
|
||||||
|
}
|
||||||
|
|
||||||
void Service::processIncomingRawPacketAsServer(const byte *packet, int packetLength) {
|
void Service::processIncomingRawPacketAsServer(const byte *packet, int packetLength) {
|
||||||
|
|
||||||
float snr = LoRa.packetSnr();
|
|
||||||
int rssi = LoRa.packetRssi();
|
|
||||||
long frequencyError = LoRa.packetFrequencyError();
|
|
||||||
|
|
||||||
String signalReport = String(" ") +
|
|
||||||
String("rssi: ") +
|
|
||||||
String(snr < 0 ? rssi + snr : rssi) +
|
|
||||||
String("dBm, ") +
|
|
||||||
String("snr: ") +
|
|
||||||
String(snr) +
|
|
||||||
String("dB, ") +
|
|
||||||
String("err: ") +
|
|
||||||
String(frequencyError) +
|
|
||||||
String("Hz");
|
|
||||||
|
|
||||||
AX25::Payload payload(packet, packetLength);
|
AX25::Payload payload(packet, packetLength);
|
||||||
|
|
||||||
if (payload.IsValid()) {
|
if (payload.IsValid()) {
|
||||||
|
|
||||||
|
float snr = LoRa.packetSnr();
|
||||||
|
int rssi = LoRa.packetRssi();
|
||||||
|
long frequencyError = LoRa.packetFrequencyError();
|
||||||
|
|
||||||
|
String signalReport = String(" ") +
|
||||||
|
String("rssi: ") +
|
||||||
|
String(snr < 0 ? rssi + snr : rssi) +
|
||||||
|
String("dBm, ") +
|
||||||
|
String("snr: ") +
|
||||||
|
String(snr) +
|
||||||
|
String("dB, ") +
|
||||||
|
String("err: ") +
|
||||||
|
String(frequencyError) +
|
||||||
|
String("Hz");
|
||||||
|
|
||||||
String textPayload = payload.ToString(config_.EnableSignalReport ? signalReport : String());
|
String textPayload = payload.ToString(config_.EnableSignalReport ? signalReport : String());
|
||||||
Serial.println(textPayload);
|
Serial.println(textPayload);
|
||||||
|
|
||||||
if (config_.EnableRfToIs) {
|
if (config_.EnableRfToIs) {
|
||||||
sendToAprsis(textPayload);
|
sendToAprsis(textPayload);
|
||||||
Serial.println("Packet sent to APRS-IS");
|
Serial.println("Packet sent to APRS-IS");
|
||||||
|
@ -326,7 +359,7 @@ void Service::processIncomingRawPacketAsServer(const byte *packet, int packetLen
|
||||||
|
|
||||||
bool Service::onRigTxBegin()
|
bool Service::onRigTxBegin()
|
||||||
{
|
{
|
||||||
delay(CfgPollDelayMs); // LoRa may drop packet if removed
|
delay(CfgPollDelayMs);
|
||||||
return (LoRa.beginPacket() == 1);
|
return (LoRa.beginPacket() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include <SPI.h>
|
#include <SPI.h>
|
||||||
#include <LoRa.h>
|
#include <LoRa.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <cppQueue.h>
|
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
|
|
||||||
#include "BluetoothSerial.h"
|
#include "BluetoothSerial.h"
|
||||||
|
@ -30,8 +29,10 @@ private:
|
||||||
|
|
||||||
void reconnectWifi() const;
|
void reconnectWifi() const;
|
||||||
bool reconnectAprsis();
|
bool reconnectAprsis();
|
||||||
|
|
||||||
|
static ICACHE_RAM_ATTR void onLoraDataAvailableIsr(int packetSize);
|
||||||
|
|
||||||
void onLoraDataAvailable(int packetSize);
|
void loraReceive(int packetSize);
|
||||||
void onAprsisDataAvailable();
|
void onAprsisDataAvailable();
|
||||||
|
|
||||||
void sendSignalReportEvent(int rssi, float snr);
|
void sendSignalReportEvent(int rssi, float snr);
|
||||||
|
@ -51,7 +52,8 @@ protected:
|
||||||
virtual bool onRigTxBegin();
|
virtual bool onRigTxBegin();
|
||||||
virtual void onRigTx(byte b);
|
virtual void onRigTx(byte b);
|
||||||
virtual void onRigTxEnd();
|
virtual void onRigTxEnd();
|
||||||
|
virtual void onRigPacket(void *packet, int packetLength);
|
||||||
|
|
||||||
virtual void onSerialTx(byte b);
|
virtual void onSerialTx(byte b);
|
||||||
virtual bool onSerialRxHasData();
|
virtual bool onSerialRxHasData();
|
||||||
virtual bool onSerialRx(byte *b);
|
virtual bool onSerialRx(byte *b);
|
||||||
|
@ -79,12 +81,13 @@ private:
|
||||||
const String CfgLoraprsVersion = "LoRAPRS 0.1";
|
const String CfgLoraprsVersion = "LoRAPRS 0.1";
|
||||||
|
|
||||||
// processor config
|
// processor config
|
||||||
const int CfgConnRetryMs = 500;
|
const int CfgConnRetryMs = 500; // connection retry delay, e.g. wifi
|
||||||
const int CfgPollDelayMs = 5;
|
const int CfgPollDelayMs = 5; // main loop delay
|
||||||
const int CfgWiFiConnRetryMaxTimes = 10;
|
const int CfgWiFiConnRetryMaxTimes = 10; // wifi number of connection retries
|
||||||
const int CfgMaxAX25PayloadSize = 512;
|
const int CfgMaxAX25PayloadSize = 512; // maximum ax25 payload size
|
||||||
const int CfgFreqCorrMinHz = 150;
|
const int CfgFreqCorrMinHz = 1000; // correct if deviation is larger than this number
|
||||||
const int CfgMaxAprsInMessageSize = 255;
|
// NB! small value causes frequent corrections, which locks LoRa ISR
|
||||||
|
const int CfgMaxAprsInMessageSize = 255; // maximum aprsis to rf message size
|
||||||
|
|
||||||
// csma parameters, overriden with KISS commands
|
// csma parameters, overriden with KISS commands
|
||||||
const long CfgCsmaPersistence = 100; // 255 for real time, lower for higher traffic
|
const long CfgCsmaPersistence = 100; // 255 for real time, lower for higher traffic
|
||||||
|
|
Ładowanie…
Reference in New Issue