diff --git a/README.md b/README.md index f1c6709..28de088 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Can be used in two modes: - **as a LoRa APRS client**, you need to use APRSDroid application (https://aprsdroid.org), connect to the modem using bluetooth, data will be re-transmitted through the LoRa radio, this is similar to APRSDroid micromodem - https://unsigned.io/micromodem/, received data will be sent back to the APRSDroid using bluetooth. By having two clients you can not only send your position, but also send and receive APRS messages. - **as a LoRa APRS iGate server**, which connects to your WiFI and forwards received LoRa APRS positions into the APRS-IS network, it also reports client signal level, by appending it into the APRS comment, so you can see your signal reports in different locations (could be enabled or disabled). It also supports: - **APRS-IS to RF gating**, so it is possible to enable it together with the filter in the config - - **RF digirepating** for basic `WIDEn-n` paths, `TRACE` and others are not supported yet + - **RF digirepating** for `WIDEn-n`, `TRACEn-n` new style paths, for `TRACE` will insert own callsign before digipeating - Own station periodic beacon announcement to APRS-IS and RF # Compatible Boards @@ -35,7 +35,7 @@ All work was done on ESP32-WROOM with custom made LoRa shield, if your ESP32 boa - lora spread factor `cfg.LoraSf`, 12 (should decode down to -20dB, choosen with the goal for minimum signal decode) - lora coding rate `cfg.LoraCodingRate`, 7 - lora output power `cfg.LoraPower`, 20 (max 20 dBm ~ 100mW, change to lower value if needed) - - sync word `cfg.LoraSync`, 0xf3 + - sync word `cfg.LoraSync`, 0x3f - consider minimum decode level based on on BW + SF ![alt text](images/bandwidth_vs_sf.jpg) - use 80 MHz ESP32 frequency in Arduino SDK, it will prolong battery life when operating portable, higher CPU speed is not required, there are no CPU intensive operations - uses LoRa **built-in checksum** calculation to drop broken packets diff --git a/ax25_callsign.cpp b/ax25_callsign.cpp index c328102..9b7bf17 100644 --- a/ax25_callsign.cpp +++ b/ax25_callsign.cpp @@ -54,11 +54,11 @@ String Callsign::ToString() const return result; } -bool Callsign::Digirepeat(const String &ownCallsign) +bool Callsign::Digirepeat() { - // only WIDE supported - if (call_.startsWith("WIDE*")) return false; - if (call_.startsWith("WIDE") && call_.length() >= 5) { + // only WIDE and TRACE supported + if (call_.startsWith("WIDE*") || call_.startsWith("TRACE*")) return false; + if ((call_.startsWith("WIDE") || call_.startsWith("TRACE")) && call_.length() >= 5) { char wideLevel = call_.charAt(4); if ((wideLevel == '1' || wideLevel == '2' || wideLevel == '3') && ssid_ > 0) { if (--ssid_ == 0) { diff --git a/ax25_callsign.h b/ax25_callsign.h index 742061a..09cdab3 100644 --- a/ax25_callsign.h +++ b/ax25_callsign.h @@ -16,11 +16,12 @@ public: Callsign(String inputText); inline bool IsValid() const { return isValid_; }; + inline bool IsTrace() const { return call_.startsWith("TRACE"); } String ToString() const; bool ToBinary(byte *txPayload, int bufferLength) const; - bool Digirepeat(const String &ownCallsign); + bool Digirepeat(); private: bool encode(byte *txPtr, int bufferLength) const; diff --git a/ax25_payload.cpp b/ax25_payload.cpp index 0cba185..aaf6dfd 100644 --- a/ax25_payload.cpp +++ b/ax25_payload.cpp @@ -86,16 +86,34 @@ String Payload::ToString(String customComment) return txt + String("\n"); } -bool Payload::Digirepeat(const String &ownCallsign) +bool Payload::Digirepeat(const Callsign &ownCallsign) { - for (int i = 0; i < rptCallsCount_; i++) { - if (rptCalls_[i].Digirepeat(ownCallsign)) { + for (int i = 0; i < rptCallsCount_; i++) { + if (rptCalls_[i].Digirepeat()) { + // if trace was digirepeated insert own callsign + if (rptCalls_[i].IsTrace()) { + InsertRptCallsign(ownCallsign, i); + } return true; } } return false; } +bool Payload::InsertRptCallsign(const Callsign &rptCallsign, int index) +{ + if (rptCallsCount_ >= RptMaxCount + || index >= RptMaxCount + || index >= rptCallsCount_) return false; + + for (int i = index; i < rptCallsCount_; i++) { + rptCalls_[i + 1] = rptCalls_[i]; + } + rptCalls_[index] = rptCallsign; + rptCallsCount_++; + return true; +} + bool Payload::fromBinary(const byte *rxPayload, int payloadLength) { const byte *rxPtr = rxPayload; diff --git a/ax25_payload.h b/ax25_payload.h index ace98d4..6b548b6 100644 --- a/ax25_payload.h +++ b/ax25_payload.h @@ -18,13 +18,15 @@ public: String ToString(String customComment); int ToBinary(byte *txPayload, int bufferLength) const; - bool Digirepeat(const String &ownCallsign); + bool Digirepeat(const Callsign &ownCallsign); void Dump(); private: bool fromString(String inputText); bool fromBinary(const byte *rxPayload, int payloadLength); + bool InsertRptCallsign(const Callsign &rptCallsign, int index); + private: enum AX25Ctrl { UI = 0x03 diff --git a/esp32_loraprs.ino b/esp32_loraprs.ino index 2a5cad3..493284b 100644 --- a/esp32_loraprs.ino +++ b/esp32_loraprs.ino @@ -20,7 +20,7 @@ void initializeConfig() { cfg.LoraBw = 125e3; cfg.LoraSf = 12; cfg.LoraCodingRate = 7; - cfg.LoraSync = 0xf3; + cfg.LoraSync = 0x3f; cfg.LoraPower = 20; // aprs configuration @@ -29,7 +29,7 @@ void initializeConfig() { cfg.AprsLogin = "NOCALL-10"; cfg.AprsPass = "12345"; cfg.AprsFilter = "r/35.60/139.80/25"; - cfg.AprsRawBeacon = "NOCALL-10>APZMDM,WIDE1-1:!0000.00N/00000.00E#LoRA 433.775MHz/BW125/SF12/CR7/0xf3"; + cfg.AprsRawBeacon = "NOCALL-10>APZMDM,WIDE1-1:!0000.00N/00000.00E#LoRa 433.775MHz/BW125/SF12/CR7/0xf3"; cfg.AprsRawBeaconPeriodMinutes = 20; // bluetooth device name diff --git a/loraprs_service.cpp b/loraprs_service.cpp index 4158713..2395b60 100644 --- a/loraprs_service.cpp +++ b/loraprs_service.cpp @@ -16,7 +16,10 @@ void Service::setup(const Config &conf) // config isClient_ = conf.IsClientMode; loraFreq_ = conf.LoraFreq; - ownCallsign_ = conf.AprsLogin; + ownCallsign_ = AX25::Callsign(conf.AprsLogin); + if (!ownCallsign_.IsValid()) { + Serial.println("Own callsign is not valid"); + } aprsLogin_ = String("user ") + conf.AprsLogin + String(" pass ") + conf.AprsPass + String(" vers ") + CfgLoraprsVersion; diff --git a/loraprs_service.h b/loraprs_service.h index fcef0f3..d359804 100644 --- a/loraprs_service.h +++ b/loraprs_service.h @@ -75,7 +75,7 @@ private: bool isClient_; long loraFreq_; - String ownCallsign_; + AX25::Callsign ownCallsign_; String aprsHost_; int aprsPort_;