Implement digirepeating and own beacon announcement

pull/15/head
sh123 2020-06-14 17:59:35 +03:00
rodzic 9c06c93ec0
commit 752128197e
5 zmienionych plików z 127 dodań i 58 usunięć

Wyświetl plik

@ -96,17 +96,18 @@ bool Callsign::fromString(String callsign)
{ {
// "ABCDEF-XX" // "ABCDEF-XX"
if (callsign.length() > CallsignSize + 2 || callsign.length() == 0) return false; if (callsign.length() > CallsignSize + 2 || callsign.length() == 0) return false;
int delimIndex = callsign.indexOf('-'); int delimIndex = callsign.indexOf('-');
// "ABCDEF-" // "ABCDEF-"
if (delimIndex = callsign.length() - 1) return false; if (delimIndex != -1 && delimIndex == callsign.length() - 1) return false;
call_ = callsign; call_ = callsign;
ssid_ = 0; ssid_ = 0;
if (delimIndex == -1) { if (delimIndex == -1) {
// "ABCDEFG" // "ABCDEF"
if (callsign.length() >= CallsignSize) return false; if (call_.length() >= CallsignSize) return false;
} }
else { else {
call_ = callsign.substring(0, delimIndex); call_ = callsign.substring(0, delimIndex);
@ -134,6 +135,8 @@ bool Callsign::fromBinary(const byte *rxPtr, int length)
ssid_ = (*ptr >> 1) & 0x0f; ssid_ = (*ptr >> 1) & 0x0f;
call_ = String((char*)callsign); call_ = String((char*)callsign);
if (call_.length() == 0) return false;
return true; return true;
} }

Wyświetl plik

@ -105,21 +105,26 @@ bool Payload::fromBinary(const byte *rxPayload, int payloadLength)
// destination address // destination address
dstCall_ = AX25::Callsign(rxPtr, CallsignSize); dstCall_ = AX25::Callsign(rxPtr, CallsignSize);
if (!dstCall_.IsValid()) return false;
rxPtr += CallsignSize; rxPtr += CallsignSize;
if (rxPtr >= rxEnd) return false; if (rxPtr >= rxEnd) return false;
// source address // source address
srcCall_ = AX25::Callsign(rxPtr, CallsignSize); srcCall_ = AX25::Callsign(rxPtr, CallsignSize);
if (!srcCall_.IsValid()) return false;
rxPtr += CallsignSize; rxPtr += CallsignSize;
if (rxPtr >= rxEnd) return false; if (rxPtr >= rxEnd) return false;
rptCallsCount_ = 0; rptCallsCount_ = 0;
// digipeater addresses // digipeater addresses
for (int i = 0; i < RptMaxCount; i++) { for (int i = 0, j = 0; i < RptMaxCount; i++) {
if ((rxPayload[(i + 2) * CallsignSize - 1] & 1) == 0) { if ((rxPayload[(i + 2) * CallsignSize - 1] & 1) == 0) {
rptCalls_[i] = AX25::Callsign(rxPtr, CallsignSize); rptCalls_[j] = AX25::Callsign(rxPtr, CallsignSize);
rptCallsCount_++; if (rptCalls_[j].IsValid()) {
rptCallsCount_++;
j++;
}
rxPtr += CallsignSize; rxPtr += CallsignSize;
if (rxPtr >= rxEnd) return false; if (rxPtr >= rxEnd) return false;
} }
@ -150,7 +155,8 @@ bool Payload::fromString(String inputText)
if (rptIndex == -1 || infoIndex == -1) return false; if (rptIndex == -1 || infoIndex == -1) return false;
info_ = inputText.substring(infoIndex + 1); info_ = inputText.substring(infoIndex + 1);
srcCall_ = inputText.substring(0, rptIndex); srcCall_ = AX25::Callsign(inputText.substring(0, rptIndex));
if (!srcCall_.IsValid()) return false;
String paths = inputText.substring(rptIndex + 1, infoIndex); String paths = inputText.substring(rptIndex + 1, infoIndex);
rptCallsCount_ = 0; rptCallsCount_ = 0;
@ -159,11 +165,14 @@ bool Payload::fromString(String inputText)
int nextIndex = paths.indexOf(',', index); int nextIndex = paths.indexOf(',', index);
String pathItem = paths.substring(index, nextIndex == -1 ? paths.length() : nextIndex); String pathItem = paths.substring(index, nextIndex == -1 ? paths.length() : nextIndex);
if (index == 0) { if (index == 0) {
dstCall_ = pathItem; dstCall_ = AX25::Callsign(pathItem);
if (!dstCall_.IsValid()) return false;
} }
else { else {
rptCallsCount_++; rptCalls_[rptCallsCount_] = AX25::Callsign(pathItem);
rptCalls_[rptCallsCount_ - 1] = pathItem; if (rptCalls_[rptCallsCount_].IsValid()) {
rptCallsCount_++;
}
} }
if (nextIndex == -1) break; if (nextIndex == -1) break;
index = nextIndex + 1; index = nextIndex + 1;

Wyświetl plik

@ -11,32 +11,42 @@ LoraPrs loraPrs;
auto watchdogLedTimer = timer_create_default(); auto watchdogLedTimer = timer_create_default();
void initializeConfig() { void initializeConfig() {
cfg.IsClientMode = true;
cfg.LoraFreq = 433.775E6; // 433.7688E6; // client/server mode switch
cfg.IsClientMode = false;
// lora parameters
cfg.LoraFreq = 433.775E6;
cfg.LoraBw = 125e3; cfg.LoraBw = 125e3;
cfg.LoraSf = 12; cfg.LoraSf = 12;
cfg.LoraCodingRate = 7; cfg.LoraCodingRate = 7;
cfg.LoraSync = 0xf3; cfg.LoraSync = 0xf3;
cfg.LoraPower = 20; cfg.LoraPower = 20;
// aprs configuration
cfg.AprsHost = "rotate.aprs2.net"; cfg.AprsHost = "rotate.aprs2.net";
cfg.AprsPort = 14580; cfg.AprsPort = 14580;
cfg.AprsLogin = "NOCALL-1"; cfg.AprsLogin = "NOCALL-1";
cfg.AprsPass = "00000"; cfg.AprsPass = "12345";
cfg.AprsFilter = "r/35.60/139.80/25"; cfg.AprsFilter = "r/35.60/139.80/25";
cfg.AprsRawBeacon = "NOCALL-1>APZMDM,WIDE1-1:!0000.00N/00000.00E#LoRA 433.775MHz/BW125/SF12/CR7/0xf3";
cfg.AprsRawBeaconPeriodMinutes = 20;
// bluetooth device name
cfg.BtName = "loraprs"; cfg.BtName = "loraprs";
// server mode wifi paramaters
cfg.WifiSsid = "<wifi ssid>"; cfg.WifiSsid = "<wifi ssid>";
cfg.WifiKey = "<wifi key>"; cfg.WifiKey = "<wifi key>";
cfg.EnableSignalReport = true; // configuration flags and features
cfg.EnableAutoFreqCorrection = true; cfg.EnableAutoFreqCorrection = true; // automatic tune to any incoming packet frequency
cfg.EnablePersistentAprsConnection = true; cfg.EnableSignalReport = true; // signal report will be added to the comment sent to aprsis
cfg.EnableRfToIs = true; cfg.EnablePersistentAprsConnection = true; // keep aprsis connection open, otherwise connect on new data only
cfg.EnableIsToRf = false; cfg.EnableRfToIs = true; // send data from rf to aprsis
cfg.EnableRepeater = false; cfg.EnableIsToRf = false; // send data from aprsis to rf
cfg.EnableRepeater = false; // digirepeat incoming packets
cfg.EnableBeacon = false; // enable periodic AprsRawBeacon beacon to rf and aprsis if rf to aprsis is enabled
} }
void setup() { void setup() {

Wyświetl plik

@ -9,6 +9,9 @@ LoraPrs::LoraPrs()
void LoraPrs::setup(const LoraPrsConfig &conf) void LoraPrs::setup(const LoraPrsConfig &conf)
{ {
previousBeaconMs_ = 0;
// config
isClient_ = conf.IsClientMode; isClient_ = conf.IsClientMode;
loraFreq_ = conf.LoraFreq; loraFreq_ = conf.LoraFreq;
ownCallsign_ = conf.AprsLogin; ownCallsign_ = conf.AprsLogin;
@ -22,6 +25,8 @@ void LoraPrs::setup(const LoraPrsConfig &conf)
aprsHost_ = conf.AprsHost; aprsHost_ = conf.AprsHost;
aprsPort_ = conf.AprsPort; aprsPort_ = conf.AprsPort;
aprsBeacon_ = conf.AprsRawBeacon;
aprsBeaconPeriodMinutes_ = conf.AprsRawBeaconPeriodMinutes;
autoCorrectFreq_ = conf.EnableAutoFreqCorrection; autoCorrectFreq_ = conf.EnableAutoFreqCorrection;
addSignalReport_ = conf.EnableSignalReport; addSignalReport_ = conf.EnableSignalReport;
@ -29,13 +34,20 @@ void LoraPrs::setup(const LoraPrsConfig &conf)
enableRfToIs_ = conf.EnableRfToIs; enableRfToIs_ = conf.EnableRfToIs;
enableIsToRf_ = conf.EnableIsToRf; enableIsToRf_ = conf.EnableIsToRf;
enableRepeater_ = conf.EnableRepeater; enableRepeater_ = conf.EnableRepeater;
enableBeacon_ = conf.EnableBeacon;
setupWifi(conf.WifiSsid, conf.WifiKey);
// peripherals
setupLora(conf.LoraFreq, conf.LoraBw, conf.LoraSf, conf.LoraCodingRate, conf.LoraPower, conf.LoraSync); setupLora(conf.LoraFreq, conf.LoraBw, conf.LoraSf, conf.LoraCodingRate, conf.LoraPower, conf.LoraSync);
setupBt(conf.BtName);
if (needsWifi()) {
setupWifi(conf.WifiSsid, conf.WifiKey);
}
if (needsBt()) {
setupBt(conf.BtName);
}
if (!isClient_ && persistentConn_) { if (needsAprsis() && persistentConn_) {
reconnectAprsis(); reconnectAprsis();
} }
} }
@ -107,31 +119,27 @@ void LoraPrs::setupLora(int loraFreq, int bw, byte sf, byte cr, byte pwr, byte s
void LoraPrs::setupBt(const String &btName) void LoraPrs::setupBt(const String &btName)
{ {
if (isClient_) { Serial.print("BT init " + btName + "...");
Serial.print("BT init " + btName + "...");
if (serialBt_.begin(btName)) { if (serialBt_.begin(btName)) {
Serial.println("ok"); Serial.println("ok");
} }
else else
{ {
Serial.println("failed"); Serial.println("failed");
}
} }
} }
void LoraPrs::loop() void LoraPrs::loop()
{ {
if (!isClient_) { if (needsWifi() && WiFi.status() != WL_CONNECTED) {
if (WiFi.status() != WL_CONNECTED) { reconnectWifi();
reconnectWifi(); }
} if (needsAprsis() && !aprsisConn_.connected() && persistentConn_) {
if (!aprsisConn_.connected()) { reconnectAprsis();
reconnectAprsis(); }
} if (aprsisConn_.available() > 0) {
if (aprsisConn_.available() > 0) { onAprsisDataAvailable();
onAprsisDataAvailable();
}
} }
if (serialBt_.available()) { if (serialBt_.available()) {
onBtDataAvailable(); onBtDataAvailable();
@ -139,15 +147,37 @@ void LoraPrs::loop()
if (int packetSize = LoRa.parsePacket()) { if (int packetSize = LoRa.parsePacket()) {
onLoraDataAvailable(packetSize); onLoraDataAvailable(packetSize);
} }
if (needsBeacon()) {
sendBeacon();
}
delay(10); delay(10);
} }
void LoraPrs::sendBeacon()
{
long currentMs = millis();
if (previousBeaconMs_ == 0 || currentMs - previousBeaconMs_ >= aprsBeaconPeriodMinutes_ * 60 * 1000) {
AX25::Payload payload(aprsBeacon_);
if (payload.IsValid()) {
sendToLora(payload);
if (enableRfToIs_) {
sendToAprsis(payload.ToString(String()));
}
Serial.println("Sent beacon");
}
else {
Serial.println("Beacon payload is invalid");
}
previousBeaconMs_ = currentMs;
}
}
void LoraPrs::sendToAprsis(String aprsMessage) void LoraPrs::sendToAprsis(String aprsMessage)
{ {
if (WiFi.status() != WL_CONNECTED) { if (needsWifi() && WiFi.status() != WL_CONNECTED) {
reconnectWifi(); reconnectWifi();
} }
if (!aprsisConn_.connected()) { if (needsAprsis() && !aprsisConn_.connected()) {
reconnectAprsis(); reconnectAprsis();
} }
aprsisConn_.print(aprsMessage); aprsisConn_.print(aprsMessage);
@ -171,17 +201,17 @@ void LoraPrs::onAprsisDataAvailable()
if (enableIsToRf_ && aprsisData.length() > 0) { if (enableIsToRf_ && aprsisData.length() > 0) {
AX25::Payload payload(aprsisData); AX25::Payload payload(aprsisData);
sendToLora(payload); if (payload.IsValid()) {
sendToLora(payload);
}
else {
Serial.println("Invalid payload from APRSIS");
}
} }
} }
bool LoraPrs::sendToLora(const AX25::Payload &payload) bool LoraPrs::sendToLora(const AX25::Payload &payload)
{ {
if (!payload.IsValid()) {
Serial.println("Invalid payload from APRSIS");
return false;
}
byte buf[512]; byte buf[512];
int bytesWritten = payload.ToBinary(buf, sizeof(buf)); int bytesWritten = payload.ToBinary(buf, sizeof(buf));
if (bytesWritten <= 0) { if (bytesWritten <= 0) {
@ -191,7 +221,7 @@ bool LoraPrs::sendToLora(const AX25::Payload &payload)
} }
LoRa.beginPacket(); LoRa.beginPacket();
LoRa.write(buf, bytesWritten); LoRa.write(buf, bytesWritten);
LoRa.endPacket(true); LoRa.endPacket();
return true; return true;
} }
@ -247,7 +277,7 @@ void LoraPrs::onLoraDataAvailable(int packetSize)
if (payload.IsValid()) { if (payload.IsValid()) {
String textPayload = payload.ToString(addSignalReport_ ? signalReport : String()); String textPayload = payload.ToString(addSignalReport_ ? signalReport : String());
Serial.print(textPayload); Serial.print(textPayload);
if (enableRfToIs_ && !isClient_) { if (enableRfToIs_ && !isClient_) {
sendToAprsis(textPayload); sendToAprsis(textPayload);
} }

Wyświetl plik

@ -25,6 +25,8 @@ struct LoraPrsConfig
String AprsLogin; String AprsLogin;
String AprsPass; String AprsPass;
String AprsFilter; String AprsFilter;
String AprsRawBeacon;
int AprsRawBeaconPeriodMinutes;
String BtName; String BtName;
@ -37,6 +39,7 @@ struct LoraPrsConfig
bool EnableRfToIs; bool EnableRfToIs;
bool EnableIsToRf; bool EnableIsToRf;
bool EnableRepeater; bool EnableRepeater;
bool EnableBeacon;
}; };
class LoraPrs class LoraPrs
@ -59,11 +62,18 @@ private:
void onBtDataAvailable(); void onBtDataAvailable();
void onAprsisDataAvailable(); void onAprsisDataAvailable();
void sendBeacon();
void sendToAprsis(String aprsMessage); void sendToAprsis(String aprsMessage);
bool sendToLora(const AX25::Payload &payload); bool sendToLora(const AX25::Payload &payload);
void kissResetState(); void kissResetState();
inline bool needsAprsis() const { return !isClient_ && (enableRfToIs_ || enableIsToRf_); }
inline bool needsWifi() const { return needsAprsis(); }
inline bool needsBt() const { return isClient_; }
inline bool needsBeacon() const { return !isClient_ && enableBeacon_; }
private: private:
enum KissMarker { enum KissMarker {
Fend = 0xc0, Fend = 0xc0,
@ -85,21 +95,23 @@ private:
}; };
const String CfgLoraprsVersion = "LoRAPRS 0.1"; const String CfgLoraprsVersion = "LoRAPRS 0.1";
const String CfgAprsSoftware = "APZLRA";
const byte CfgPinSs = 5; const byte CfgPinSs = 5;
const byte CfgPinRst = 26; const byte CfgPinRst = 26;
const byte CfgPinDio0 = 14; const byte CfgPinDio0 = 14;
private: private:
// config
bool isClient_; bool isClient_;
long loraFreq_; long loraFreq_;
String ownCallsign_; String ownCallsign_;
String aprsHost_; String aprsHost_;
int aprsPort_; int aprsPort_;
String aprsLogin_; String aprsLogin_;
String aprsBeacon_;
int aprsBeaconPeriodMinutes_;
bool autoCorrectFreq_; bool autoCorrectFreq_;
bool addSignalReport_; bool addSignalReport_;
@ -107,10 +119,15 @@ private:
bool enableRfToIs_; bool enableRfToIs_;
bool enableIsToRf_; bool enableIsToRf_;
bool enableRepeater_; bool enableRepeater_;
bool enableBeacon_;
// state
KissCmd kissCmd_; KissCmd kissCmd_;
KissState kissState_; KissState kissState_;
long previousBeaconMs_;
// peripherals
BluetoothSerial serialBt_; BluetoothSerial serialBt_;
WiFiClient aprsisConn_; WiFiClient aprsisConn_;
}; };