kopia lustrzana https://github.com/sh123/esp32_loraprs
Config and AX25 message reafactoring (#5)
* Refactoring * Add support for aprsis filter and print out incoming packets into the serialpull/6/head
rodzic
80963bdf11
commit
1ae790c5d5
|
@ -0,0 +1,88 @@
|
|||
#include "aprsmsg.h"
|
||||
|
||||
namespace AX25 {
|
||||
|
||||
Payload::Payload(byte *rxPayload, int payloadLength)
|
||||
{
|
||||
parsePayload(rxPayload, payloadLength);
|
||||
}
|
||||
|
||||
String Payload::ToText(const String &customComment)
|
||||
{
|
||||
String txt = srcCall_ + String(">") + dstCall_;
|
||||
|
||||
if (rptFirst_.length() > 0) {
|
||||
txt += String(",") + rptFirst_;
|
||||
}
|
||||
if (rptSecond_.length() > 0) {
|
||||
txt += String(",") + rptSecond_;
|
||||
}
|
||||
|
||||
txt += String(":") + body_;
|
||||
|
||||
if (body_.startsWith("=")) {
|
||||
txt += customComment;
|
||||
}
|
||||
|
||||
return txt + String("\n");
|
||||
}
|
||||
|
||||
bool Payload::parsePayload(byte *rxPayload, int payloadLength)
|
||||
{
|
||||
byte *rxPtr = rxPayload;
|
||||
|
||||
dstCall_ = decodeCall(rxPtr);
|
||||
rxPtr += CallsignSize;
|
||||
if (rxPtr >= rxPayload + payloadLength) return false;
|
||||
|
||||
srcCall_ = decodeCall(rxPtr);
|
||||
rxPtr += CallsignSize;
|
||||
if (rxPtr >= rxPayload + payloadLength) return false;
|
||||
|
||||
if ((rxPayload[2 * CallsignSize - 1] & 1) == 0) {
|
||||
rptFirst_ = decodeCall(rxPtr);
|
||||
rxPtr += CallsignSize;
|
||||
if (rxPtr >= rxPayload + payloadLength) return false;
|
||||
|
||||
if ((rxPayload[3 * CallsignSize - 1] & 1) == 0) {
|
||||
rptSecond_ = decodeCall(rxPtr);
|
||||
rxPtr += CallsignSize;
|
||||
}
|
||||
}
|
||||
if ((rxPtr + 1) >= rxPayload + payloadLength) return false;
|
||||
|
||||
if (*(rxPtr++) != AX25Ctrl::UI) return false;
|
||||
if (*(rxPtr++) != AX25Pid::NoLayer3) return false;
|
||||
|
||||
while (rxPtr < rxPayload + payloadLength) {
|
||||
body_ += String((char)*(rxPtr++));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
String Payload::decodeCall(byte *rxPtr)
|
||||
{
|
||||
byte callsign[CallsignSize];
|
||||
char ssid;
|
||||
|
||||
byte *ptr = rxPtr;
|
||||
|
||||
memset(callsign, 0, sizeof(callsign));
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
char c = *(ptr++) >> 1;
|
||||
callsign[i] = (c == ' ') ? '\0' : c;
|
||||
}
|
||||
callsign[CallsignSize-1] = '\0';
|
||||
ssid = (*ptr >> 1);
|
||||
|
||||
String result = String((char*)callsign);
|
||||
|
||||
if (result.length() > 0 && ssid >= '0' && ssid <= '9') {
|
||||
result += String("-") + String(ssid);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // AX25
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef APRSMSG_H
|
||||
#define APRSMSG_H
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
namespace AX25 {
|
||||
|
||||
class Payload
|
||||
{
|
||||
public:
|
||||
Payload(byte *rxPayload, int payloadLength);
|
||||
String ToText(const String &customComment);
|
||||
|
||||
private:
|
||||
String decodeCall(byte *rxPtr);
|
||||
bool parsePayload(byte *rxPayload, int payloadLength);
|
||||
|
||||
private:
|
||||
enum AX25Ctrl {
|
||||
UI = 0x03
|
||||
};
|
||||
|
||||
enum AX25Pid {
|
||||
NoLayer3 = 0xf0
|
||||
};
|
||||
|
||||
const int MaxPayloadSize = 16;
|
||||
const int CallsignSize = 7;
|
||||
|
||||
private:
|
||||
String srcCall_, dstCall_;
|
||||
String rptFirst_, rptSecond_;
|
||||
String body_;
|
||||
};
|
||||
|
||||
} // AX25
|
||||
|
||||
#endif // APRSMSG_H
|
|
@ -5,46 +5,39 @@
|
|||
#define LED_BUILTIN 2
|
||||
#define LED_TOGGLE_PERIOD 1000
|
||||
|
||||
#define LORAPRS_CLIENT
|
||||
|
||||
// https://vienna.iaru-r1.org/wp-content/uploads/2019/01/VIE19-C5-015-OEVSV-LORA-APRS-433-MHz.pdf
|
||||
#ifdef LORAPRS_CLIENT
|
||||
// calibrate client based on server frequency drift report
|
||||
#define LORAPRS_FREQ 433.775E6
|
||||
//#define LORAPRS_FREQ 433.7688E6
|
||||
#else
|
||||
#define LORAPRS_FREQ 433.775E6
|
||||
//#define LORAPRS_FREQ 433.770E6
|
||||
#endif
|
||||
|
||||
#ifdef LORAPRS_CLIENT
|
||||
#define LORAPRS_BT_NAME "loraprs_client"
|
||||
#define LORAPRS_WIFI_SSID ""
|
||||
#define LORAPRS_WIFI_KEY ""
|
||||
#define LORAPRS_LOGIN "NOCALL-0"
|
||||
#define LORAPRS_PASS "00000"
|
||||
#define LORAPRS_FREQ_CORR false
|
||||
#else
|
||||
#define LORAPRS_BT_NAME ""
|
||||
#define LORAPRS_WIFI_SSID "<your access point name>"
|
||||
#define LORAPRS_WIFI_KEY "<your access point key>"
|
||||
#define LORAPRS_LOGIN "NOCALL-0"
|
||||
#define LORAPRS_PASS "12345"
|
||||
#define LORAPRS_FREQ_CORR false
|
||||
//#define LORAPRS_FREQ_CORR true
|
||||
#endif
|
||||
|
||||
LoraPrs loraPrs(
|
||||
LORAPRS_FREQ,
|
||||
LORAPRS_BT_NAME,
|
||||
LORAPRS_WIFI_SSID,
|
||||
LORAPRS_WIFI_KEY,
|
||||
LORAPRS_LOGIN,
|
||||
LORAPRS_PASS,
|
||||
LORAPRS_FREQ_CORR);
|
||||
LoraPrsConfig cfg;
|
||||
LoraPrs loraPrs;
|
||||
|
||||
auto watchdogLedTimer = timer_create_default();
|
||||
|
||||
void initializeConfig() {
|
||||
cfg.IsClientMode = true;
|
||||
|
||||
cfg.LoraFreq = 433.775E6; // 433.7688E6;
|
||||
cfg.LoraBw = 125e3;
|
||||
cfg.LoraSf = 12;
|
||||
cfg.LoraCodingRate = 7;
|
||||
cfg.LoraSync = 0xf3;
|
||||
cfg.LoraPower = 20;
|
||||
|
||||
cfg.AprsHost = "rotate.aprs2.net";
|
||||
cfg.AprsPort = 14580;
|
||||
cfg.AprsLogin = "NOCALL-1";
|
||||
cfg.AprsPass = "00000";
|
||||
cfg.AprsFilter = "r/35.60/139.80/25";
|
||||
|
||||
cfg.BtName = "loraprs";
|
||||
|
||||
cfg.WifiSsid = "<wifi ssid>";
|
||||
cfg.WifiKey = "<wifi key>";
|
||||
|
||||
cfg.EnableSignalReport = true;
|
||||
cfg.EnableAutoFreqCorrection = true;
|
||||
cfg.EnablePersistentAprsConnection = true;
|
||||
cfg.EnableIsToRf = false;
|
||||
cfg.EnableRepeater = false;
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, 1);
|
||||
|
@ -52,7 +45,8 @@ void setup() {
|
|||
Serial.begin(115200);
|
||||
while (!Serial);
|
||||
|
||||
loraPrs.setup();
|
||||
initializeConfig();
|
||||
loraPrs.setup(cfg);
|
||||
|
||||
watchdogLedTimer.every(LED_TOGGLE_PERIOD, toggleWatchdogLed);
|
||||
}
|
||||
|
|
203
loraprs.cpp
203
loraprs.cpp
|
@ -1,36 +1,46 @@
|
|||
#include "loraprs.h"
|
||||
|
||||
LoraPrs::LoraPrs(long loraFreq, const String &btName, const String &wifiName, const String &wifiKey,
|
||||
const String &aprsLoginCallsign, const String &aprsPass, bool autoCorrectFreq)
|
||||
LoraPrs::LoraPrs()
|
||||
: serialBt_()
|
||||
, loraFreq_(loraFreq)
|
||||
, autoCorrectFreq_(autoCorrectFreq)
|
||||
, btName_(btName)
|
||||
, wifiName_(wifiName)
|
||||
, wifiKey_(wifiKey)
|
||||
, kissState_(KissState::Void)
|
||||
, kissCmd_(KissCmd::NoCmd)
|
||||
{
|
||||
aprsLogin_ = "";
|
||||
aprsLogin_ += "user ";
|
||||
aprsLogin_ += aprsLoginCallsign;
|
||||
aprsLogin_ += " pass ";
|
||||
aprsLogin_ += aprsPass;
|
||||
aprsLogin_ += " vers ";
|
||||
aprsLogin_ += CfgLoraprsVersion;
|
||||
aprsLogin_ += "\n";
|
||||
}
|
||||
|
||||
void LoraPrs::setup()
|
||||
void LoraPrs::setup(const LoraPrsConfig &conf)
|
||||
{
|
||||
setupWifi(wifiName_, wifiKey_);
|
||||
setupLora(loraFreq_);
|
||||
setupBt(btName_);
|
||||
isClient_ = conf.IsClientMode;
|
||||
loraFreq_ = conf.LoraFreq;
|
||||
|
||||
aprsLogin_ = String("user ") + conf.AprsLogin + String(" pass ") +
|
||||
conf.AprsPass + String(" vers ") + CfgLoraprsVersion;
|
||||
if (conf.AprsFilter.length() > 0) {
|
||||
aprsLogin_ += String(" filter ") + conf.AprsFilter;
|
||||
}
|
||||
aprsLogin_ += String("\n");
|
||||
|
||||
aprsHost_ = conf.AprsHost;
|
||||
aprsPort_ = conf.AprsPort;
|
||||
|
||||
autoCorrectFreq_ = conf.EnableAutoFreqCorrection;
|
||||
addSignalReport_ = conf.EnableSignalReport;
|
||||
persistentConn_ = conf.EnablePersistentAprsConnection;
|
||||
enableIsToRf_ = conf.EnableIsToRf;
|
||||
enableRepeater_ = conf.EnableRepeater;
|
||||
|
||||
setupWifi(conf.WifiSsid, conf.WifiKey);
|
||||
|
||||
setupLora(conf.LoraFreq, conf.LoraBw, conf.LoraSf, conf.LoraCodingRate, conf.LoraPower, conf.LoraSync);
|
||||
setupBt(conf.BtName);
|
||||
|
||||
if (!isClient_ && persistentConn_) {
|
||||
reconnectAprsis();
|
||||
}
|
||||
}
|
||||
|
||||
void LoraPrs::setupWifi(const String &wifiName, const String &wifiKey)
|
||||
{
|
||||
if (wifiName.length() != 0) {
|
||||
if (!isClient_) {
|
||||
Serial.print("WIFI connecting to " + wifiName);
|
||||
|
||||
WiFi.setHostname("loraprs");
|
||||
|
@ -59,7 +69,21 @@ void LoraPrs::reconnectWifi() {
|
|||
Serial.println("ok");
|
||||
}
|
||||
|
||||
void LoraPrs::setupLora(int loraFreq)
|
||||
bool LoraPrs::reconnectAprsis() {
|
||||
|
||||
Serial.print("APRSIS connecting...");
|
||||
|
||||
if (!aprsisConn_.connect(aprsHost_.c_str(), aprsPort_)) {
|
||||
Serial.println("Failed to connect to " + aprsHost_ + ":" + aprsPort_);
|
||||
return false;
|
||||
}
|
||||
Serial.println("ok");
|
||||
|
||||
aprsisConn_.print(aprsLogin_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoraPrs::setupLora(int loraFreq, int bw, byte sf, byte cr, byte pwr, byte sync)
|
||||
{
|
||||
Serial.print("LoRa init...");
|
||||
|
||||
|
@ -69,11 +93,11 @@ void LoraPrs::setupLora(int loraFreq)
|
|||
Serial.print(".");
|
||||
delay(500);
|
||||
}
|
||||
LoRa.setSyncWord(CfgSync);
|
||||
LoRa.setSpreadingFactor(CfgSpread);
|
||||
LoRa.setSignalBandwidth(CfgBw);
|
||||
LoRa.setCodingRate4(CfgCodingRate);
|
||||
LoRa.setTxPower(CfgPower);
|
||||
LoRa.setSyncWord(sync);
|
||||
LoRa.setSpreadingFactor(sf);
|
||||
LoRa.setSignalBandwidth(bw);
|
||||
LoRa.setCodingRate4(cr);
|
||||
LoRa.setTxPower(pwr);
|
||||
LoRa.enableCrc();
|
||||
|
||||
Serial.println("ok");
|
||||
|
@ -81,7 +105,7 @@ void LoraPrs::setupLora(int loraFreq)
|
|||
|
||||
void LoraPrs::setupBt(const String &btName)
|
||||
{
|
||||
if (btName.length() != 0) {
|
||||
if (isClient_) {
|
||||
Serial.print("BT init " + btName + "...");
|
||||
|
||||
if (serialBt_.begin(btName)) {
|
||||
|
@ -96,111 +120,46 @@ void LoraPrs::setupBt(const String &btName)
|
|||
|
||||
void LoraPrs::loop()
|
||||
{
|
||||
if (WiFi.status() != WL_CONNECTED && wifiName_.length() != 0) {
|
||||
reconnectWifi();
|
||||
if (!isClient_) {
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
reconnectWifi();
|
||||
}
|
||||
if (!aprsisConn_.connected()) {
|
||||
reconnectAprsis();
|
||||
}
|
||||
while (aprsisConn_.available() > 0) {
|
||||
char c = aprsisConn_.read();
|
||||
Serial.print(c);
|
||||
}
|
||||
}
|
||||
if (serialBt_.available()) {
|
||||
onBtReceived();
|
||||
onBtDataAvailable();
|
||||
}
|
||||
if (int packetSize = LoRa.parsePacket()) {
|
||||
onLoraReceived(packetSize);
|
||||
onLoraDataAvailable(packetSize);
|
||||
}
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void LoraPrs::onAprsReceived(const String &aprsMessage)
|
||||
void LoraPrs::onRfAprsReceived(const String &aprsMessage)
|
||||
{
|
||||
if (WiFi.status() == WL_CONNECTED) {
|
||||
WiFiClient wifiClient;
|
||||
if (isClient_) return;
|
||||
|
||||
if (WiFi.status() != WL_CONNECTED) {
|
||||
reconnectWifi();
|
||||
}
|
||||
if (!aprsisConn_.connected()) {
|
||||
reconnectAprsis();
|
||||
}
|
||||
Serial.print(aprsMessage);
|
||||
aprsisConn_.print(aprsMessage);
|
||||
|
||||
if (!wifiClient.connect(CfgAprsHost.c_str(), CfgAprsPort)) {
|
||||
Serial.println("Failed to connect to " + CfgAprsHost + ":" + CfgAprsPort);
|
||||
return;
|
||||
}
|
||||
wifiClient.print(aprsLogin_);
|
||||
Serial.print(aprsMessage);
|
||||
wifiClient.print(aprsMessage);
|
||||
wifiClient.stop();
|
||||
}
|
||||
else {
|
||||
Serial.println("Wifi not connected, not sent");
|
||||
if (!persistentConn_) {
|
||||
aprsisConn_.stop();
|
||||
}
|
||||
}
|
||||
|
||||
String LoraPrs::decodeCall(byte *rxPtr)
|
||||
{
|
||||
byte callsign[7];
|
||||
char ssid;
|
||||
|
||||
byte *ptr = rxPtr;
|
||||
|
||||
memset(callsign, 0, sizeof(callsign));
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
char c = *(ptr++) >> 1;
|
||||
callsign[i] = (c == ' ') ? '\0' : c;
|
||||
}
|
||||
callsign[6] = '\0';
|
||||
ssid = (*ptr >> 1);
|
||||
|
||||
String result = String((char*)callsign);
|
||||
if (result.length() > 0 && ssid >= '0' && ssid <= '9') {
|
||||
result += String("-") + String(ssid);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
String LoraPrs::convertAX25ToAprs(byte *rxPayload, int payloadLength, const String &signalReport)
|
||||
{
|
||||
byte *rxPtr = rxPayload;
|
||||
String srcCall, dstCall, rptFirst, rptSecond, result;
|
||||
|
||||
dstCall = decodeCall(rxPtr);
|
||||
rxPtr += 7;
|
||||
|
||||
srcCall = decodeCall(rxPtr);
|
||||
rxPtr += 7;
|
||||
|
||||
if ((rxPayload[13] & 1) == 0) {
|
||||
rptFirst = decodeCall(rxPtr);
|
||||
rxPtr += 7;
|
||||
|
||||
if ((rxPayload[20] & 1) == 0) {
|
||||
rptSecond = decodeCall(rxPtr);
|
||||
rxPtr += 7;
|
||||
}
|
||||
}
|
||||
|
||||
if (*(rxPtr++) != AX25Ctrl::UI) return result;
|
||||
if (*(rxPtr++) != AX25Pid::NoLayer3) return result;
|
||||
|
||||
result += srcCall + String(">") + dstCall;
|
||||
|
||||
if (rptFirst.length() > 0) {
|
||||
result += String(",") + rptFirst;
|
||||
}
|
||||
if (rptSecond.length() > 0) {
|
||||
result += String(",") + rptSecond;
|
||||
}
|
||||
|
||||
result += ":";
|
||||
|
||||
bool appendReport = ((char)*rxPtr == '=');
|
||||
|
||||
while (rxPtr < rxPayload + payloadLength) {
|
||||
result += String((char)*(rxPtr++));
|
||||
}
|
||||
|
||||
if (appendReport) {
|
||||
result += signalReport;
|
||||
}
|
||||
|
||||
result += "\n";
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void LoraPrs::onLoraReceived(int packetSize)
|
||||
void LoraPrs::onLoraDataAvailable(int packetSize)
|
||||
{
|
||||
int rxBufIndex = 0;
|
||||
byte rxBuf[packetSize];
|
||||
|
@ -247,10 +206,10 @@ void LoraPrs::onLoraReceived(int packetSize)
|
|||
LoRa.setFrequency(loraFreq_);
|
||||
}
|
||||
|
||||
String aprsMsg = convertAX25ToAprs(rxBuf, rxBufIndex, signalReport);
|
||||
String aprsMsg = AX25::Payload(rxBuf, rxBufIndex).ToText(addSignalReport_ ? signalReport : String());
|
||||
|
||||
if (aprsMsg.length() != 0) {
|
||||
onAprsReceived(aprsMsg);
|
||||
onRfAprsReceived(aprsMsg);
|
||||
}
|
||||
|
||||
delay(50);
|
||||
|
@ -262,7 +221,7 @@ void LoraPrs::kissResetState()
|
|||
kissState_ = KissState::Void;
|
||||
}
|
||||
|
||||
void LoraPrs::onBtReceived()
|
||||
void LoraPrs::onBtDataAvailable()
|
||||
{
|
||||
while (serialBt_.available()) {
|
||||
byte txByte = serialBt_.read();
|
||||
|
|
89
loraprs.h
89
loraprs.h
|
@ -7,32 +7,61 @@
|
|||
#include <WiFi.h>
|
||||
|
||||
#include "BluetoothSerial.h"
|
||||
#include "aprsmsg.h"
|
||||
|
||||
class LoraPrsConfig
|
||||
{
|
||||
public:
|
||||
bool IsClientMode;
|
||||
|
||||
long LoraFreq;
|
||||
int LoraBw;
|
||||
byte LoraSf;
|
||||
byte LoraCodingRate;
|
||||
byte LoraSync;
|
||||
byte LoraPower;
|
||||
|
||||
int AprsPort;
|
||||
String AprsHost;
|
||||
String AprsLogin;
|
||||
String AprsPass;
|
||||
String AprsFilter;
|
||||
|
||||
String BtName;
|
||||
|
||||
String WifiSsid;
|
||||
String WifiKey;
|
||||
|
||||
bool EnableSignalReport;
|
||||
bool EnableAutoFreqCorrection;
|
||||
bool EnablePersistentAprsConnection;
|
||||
bool EnableIsToRf;
|
||||
bool EnableRepeater;
|
||||
};
|
||||
|
||||
class LoraPrs
|
||||
{
|
||||
public:
|
||||
LoraPrs(long loraFreq, const String &btName, const String &wifiName, const String &wifiKey,
|
||||
const String &aprsLoginCallsign, const String& aprsPass, bool autoCorrectFreq);
|
||||
LoraPrs();
|
||||
|
||||
void setup();
|
||||
void setup(const LoraPrsConfig &conf);
|
||||
void loop();
|
||||
|
||||
private:
|
||||
void setupWifi(const String &wifiName, const String &wifiKey);
|
||||
void setupLora(int loraFreq);
|
||||
void setupLora(int loraFreq, int bw, byte sf, byte cr, byte pwr, byte sync);
|
||||
void setupBt(const String &btName);
|
||||
|
||||
void reconnectWifi();
|
||||
|
||||
void onLoraReceived(int packetSize);
|
||||
void onBtReceived();
|
||||
void onAprsReceived(const String & aprsMessage);
|
||||
|
||||
bool reconnectAprsis();
|
||||
|
||||
void onLoraDataAvailable(int packetSize);
|
||||
void onBtDataAvailable();
|
||||
|
||||
void onRfAprsReceived(const String &aprsMessage);
|
||||
|
||||
void kissResetState();
|
||||
|
||||
String convertAX25ToAprs(byte *rxPayload, int payloadLength, const String &signalReport);
|
||||
String decodeCall(byte *rxPtr);
|
||||
|
||||
private:
|
||||
enum KissMarker {
|
||||
Fend = 0xc0,
|
||||
|
@ -53,43 +82,31 @@ private:
|
|||
NoCmd = 0x80
|
||||
};
|
||||
|
||||
enum AX25Ctrl {
|
||||
UI = 0x03
|
||||
};
|
||||
|
||||
enum AX25Pid {
|
||||
NoLayer3 = 0xf0
|
||||
};
|
||||
|
||||
const String CfgLoraprsVersion = "LoRAPRS 0.1";
|
||||
|
||||
|
||||
const byte CfgPinSs = 5;
|
||||
const byte CfgPinRst = 26;
|
||||
const byte CfgPinDio0 = 14;
|
||||
|
||||
const int CfgBw = 125e3;
|
||||
const byte CfgSpread = 12;
|
||||
//const int CfgBw = 20e3;
|
||||
//const byte CfgSpread = 9;
|
||||
const byte CfgCodingRate = 7;
|
||||
const byte CfgSync = 0xf3;
|
||||
const byte CfgPower = 20;
|
||||
|
||||
const int CfgAprsPort = 14580;
|
||||
const String CfgAprsHost = "rotate.aprs2.net";
|
||||
|
||||
private:
|
||||
bool isClient_;
|
||||
long loraFreq_;
|
||||
bool autoCorrectFreq_;
|
||||
String btName_;
|
||||
String wifiName_;
|
||||
String wifiKey_;
|
||||
|
||||
String aprsHost_;
|
||||
int aprsPort_;
|
||||
String aprsLogin_;
|
||||
|
||||
bool autoCorrectFreq_;
|
||||
bool addSignalReport_;
|
||||
bool persistentConn_;
|
||||
bool enableIsToRf_;
|
||||
bool enableRepeater_;
|
||||
|
||||
KissCmd kissCmd_;
|
||||
KissState kissState_;
|
||||
|
||||
BluetoothSerial serialBt_;
|
||||
WiFiClient aprsisConn_;
|
||||
};
|
||||
|
||||
#endif // LORAPRS_H
|
||||
|
|
Ładowanie…
Reference in New Issue