kopia lustrzana https://github.com/sh123/esp32_loraprs
Added support for TRACEn-n path and changed sync word to 0x3f for compatibility
rodzic
dff45cf9ac
commit
d7f8779d47
|
@ -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 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:
|
- **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
|
- **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
|
- Own station periodic beacon announcement to APRS-IS and RF
|
||||||
|
|
||||||
# Compatible Boards
|
# 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 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 coding rate `cfg.LoraCodingRate`, 7
|
||||||
- lora output power `cfg.LoraPower`, 20 (max 20 dBm ~ 100mW, change to lower value if needed)
|
- 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 
|
- consider minimum decode level based on on BW + SF 
|
||||||
- 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
|
- 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
|
- uses LoRa **built-in checksum** calculation to drop broken packets
|
||||||
|
|
|
@ -54,11 +54,11 @@ String Callsign::ToString() const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Callsign::Digirepeat(const String &ownCallsign)
|
bool Callsign::Digirepeat()
|
||||||
{
|
{
|
||||||
// only WIDE supported
|
// only WIDE and TRACE supported
|
||||||
if (call_.startsWith("WIDE*")) return false;
|
if (call_.startsWith("WIDE*") || call_.startsWith("TRACE*")) return false;
|
||||||
if (call_.startsWith("WIDE") && call_.length() >= 5) {
|
if ((call_.startsWith("WIDE") || call_.startsWith("TRACE")) && call_.length() >= 5) {
|
||||||
char wideLevel = call_.charAt(4);
|
char wideLevel = call_.charAt(4);
|
||||||
if ((wideLevel == '1' || wideLevel == '2' || wideLevel == '3') && ssid_ > 0) {
|
if ((wideLevel == '1' || wideLevel == '2' || wideLevel == '3') && ssid_ > 0) {
|
||||||
if (--ssid_ == 0) {
|
if (--ssid_ == 0) {
|
||||||
|
|
|
@ -16,11 +16,12 @@ public:
|
||||||
Callsign(String inputText);
|
Callsign(String inputText);
|
||||||
|
|
||||||
inline bool IsValid() const { return isValid_; };
|
inline bool IsValid() const { return isValid_; };
|
||||||
|
inline bool IsTrace() const { return call_.startsWith("TRACE"); }
|
||||||
|
|
||||||
String ToString() const;
|
String ToString() const;
|
||||||
bool ToBinary(byte *txPayload, int bufferLength) const;
|
bool ToBinary(byte *txPayload, int bufferLength) const;
|
||||||
|
|
||||||
bool Digirepeat(const String &ownCallsign);
|
bool Digirepeat();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool encode(byte *txPtr, int bufferLength) const;
|
bool encode(byte *txPtr, int bufferLength) const;
|
||||||
|
|
|
@ -86,16 +86,34 @@ String Payload::ToString(String customComment)
|
||||||
return txt + String("\n");
|
return txt + String("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Payload::Digirepeat(const String &ownCallsign)
|
bool Payload::Digirepeat(const Callsign &ownCallsign)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < rptCallsCount_; i++) {
|
for (int i = 0; i < rptCallsCount_; i++) {
|
||||||
if (rptCalls_[i].Digirepeat(ownCallsign)) {
|
if (rptCalls_[i].Digirepeat()) {
|
||||||
|
// if trace was digirepeated insert own callsign
|
||||||
|
if (rptCalls_[i].IsTrace()) {
|
||||||
|
InsertRptCallsign(ownCallsign, i);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
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)
|
bool Payload::fromBinary(const byte *rxPayload, int payloadLength)
|
||||||
{
|
{
|
||||||
const byte *rxPtr = rxPayload;
|
const byte *rxPtr = rxPayload;
|
||||||
|
|
|
@ -18,13 +18,15 @@ public:
|
||||||
String ToString(String customComment);
|
String ToString(String customComment);
|
||||||
int ToBinary(byte *txPayload, int bufferLength) const;
|
int ToBinary(byte *txPayload, int bufferLength) const;
|
||||||
|
|
||||||
bool Digirepeat(const String &ownCallsign);
|
bool Digirepeat(const Callsign &ownCallsign);
|
||||||
void Dump();
|
void Dump();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fromString(String inputText);
|
bool fromString(String inputText);
|
||||||
bool fromBinary(const byte *rxPayload, int payloadLength);
|
bool fromBinary(const byte *rxPayload, int payloadLength);
|
||||||
|
|
||||||
|
bool InsertRptCallsign(const Callsign &rptCallsign, int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum AX25Ctrl {
|
enum AX25Ctrl {
|
||||||
UI = 0x03
|
UI = 0x03
|
||||||
|
|
|
@ -20,7 +20,7 @@ void initializeConfig() {
|
||||||
cfg.LoraBw = 125e3;
|
cfg.LoraBw = 125e3;
|
||||||
cfg.LoraSf = 12;
|
cfg.LoraSf = 12;
|
||||||
cfg.LoraCodingRate = 7;
|
cfg.LoraCodingRate = 7;
|
||||||
cfg.LoraSync = 0xf3;
|
cfg.LoraSync = 0x3f;
|
||||||
cfg.LoraPower = 20;
|
cfg.LoraPower = 20;
|
||||||
|
|
||||||
// aprs configuration
|
// aprs configuration
|
||||||
|
@ -29,7 +29,7 @@ void initializeConfig() {
|
||||||
cfg.AprsLogin = "NOCALL-10";
|
cfg.AprsLogin = "NOCALL-10";
|
||||||
cfg.AprsPass = "12345";
|
cfg.AprsPass = "12345";
|
||||||
cfg.AprsFilter = "r/35.60/139.80/25";
|
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;
|
cfg.AprsRawBeaconPeriodMinutes = 20;
|
||||||
|
|
||||||
// bluetooth device name
|
// bluetooth device name
|
||||||
|
|
|
@ -16,7 +16,10 @@ void Service::setup(const Config &conf)
|
||||||
// config
|
// config
|
||||||
isClient_ = conf.IsClientMode;
|
isClient_ = conf.IsClientMode;
|
||||||
loraFreq_ = conf.LoraFreq;
|
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 ") +
|
aprsLogin_ = String("user ") + conf.AprsLogin + String(" pass ") +
|
||||||
conf.AprsPass + String(" vers ") + CfgLoraprsVersion;
|
conf.AprsPass + String(" vers ") + CfgLoraprsVersion;
|
||||||
|
|
|
@ -75,7 +75,7 @@ private:
|
||||||
bool isClient_;
|
bool isClient_;
|
||||||
long loraFreq_;
|
long loraFreq_;
|
||||||
|
|
||||||
String ownCallsign_;
|
AX25::Callsign ownCallsign_;
|
||||||
|
|
||||||
String aprsHost_;
|
String aprsHost_;
|
||||||
int aprsPort_;
|
int aprsPort_;
|
||||||
|
|
Ładowanie…
Reference in New Issue