[APRS] Added support for APRS over LoRa

This commit is contained in:
jgromes 2023-07-21 18:18:05 +02:00
parent 1bc7c5771c
commit 247ca753f1
2 changed files with 67 additions and 12 deletions

View file

@ -6,9 +6,15 @@
APRSClient::APRSClient(AX25Client* ax) {
axClient = ax;
phyLayer = nullptr;
}
int16_t APRSClient::begin(char sym, bool alt) {
APRSClient::APRSClient(PhysicalLayer* phy) {
axClient = nullptr;
phyLayer = phy;
}
int16_t APRSClient::begin(char sym, char* callsign, uint8_t ssid, bool alt) {
RADIOLIB_CHECK_RANGE(sym, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL);
symbol = sym;
@ -18,6 +24,16 @@ int16_t APRSClient::begin(char sym, bool alt) {
table = '/';
}
if((!src) && (this->phyLayer != nullptr)) {
return(RADIOLIB_ERR_INVALID_CALLSIGN);
}
if(strlen(callsign) > RADIOLIB_AX25_MAX_CALLSIGN_LEN) {
return(RADIOLIB_ERR_INVALID_CALLSIGN);
}
memcpy(this->src, callsign, strlen(callsign));
this->id = ssid;
return(RADIOLIB_ERR_NONE);
}
@ -30,7 +46,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat
if(time != NULL) {
len += strlen(time);
}
char* info = new char[len];
char* info = new char[len + 1];
#else
char info[RADIOLIB_STATIC_ARRAY_SIZE];
#endif
@ -49,6 +65,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat
// timestamp and message
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg);
}
info[len] = '\0';
// send the frame
int16_t state = sendFrame(destCallsign, destSSID, info);
@ -211,7 +228,12 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp
info[infoPos++] = '\0';
// send the frame
int16_t state = sendFrame(destCallsign, 0, info);
uint8_t destSSID = 0;
if(this->phyLayer != nullptr) {
// TODO make SSID configurable?
destSSID = 1;
}
int16_t state = sendFrame(destCallsign, destSSID, info);
#if !defined(RADIOLIB_STATIC_ONLY)
delete[] info;
#endif
@ -219,15 +241,31 @@ int16_t APRSClient::sendMicE(float lat, float lon, uint16_t heading, uint16_t sp
}
int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) {
// get AX.25 callsign
char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1];
axClient->getCallsign(srcCallsign);
// encoding depends on whether AX.25 should be used or not
if(this->axClient != nullptr) {
// AX.25/classical mode, get AX.25 callsign
char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1];
axClient->getCallsign(srcCallsign);
AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION |
RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME,
RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info);
AX25Frame frameUI(destCallsign, destSSID, srcCallsign, axClient->getSSID(), RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION |
RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME,
RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info);
return(axClient->sendFrame(&frameUI));
return(axClient->sendFrame(&frameUI));
} else if(this->phyLayer != nullptr) {
// non-AX.25/LoRa mode
size_t len = RADIOLIB_APRS_LORA_HEADER_LEN + strlen(this->src) + 4 + strlen(destCallsign) + 11 + strlen(info);
Serial.println(len);
uint8_t* buff = new uint8_t[len];
snprintf(buff, len, RADIOLIB_APRS_LORA_HEADER "%s-%d>%s,WIDE%d-%d:%s", this->src, this->id, destCallsign, destSSID, destSSID, info);
int16_t res = this->phyLayer->transmit(buff, strlen(buff));
delete[] buff;
return(res);
}
return(RADIOLIB_ERR_WRONG_MODEM);
}
#endif

View file

@ -58,6 +58,10 @@
// alias for unused altitude in Mic-E
#define RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED -1000000
// special header applied for APRS over LoRa
#define RADIOLIB_APRS_LORA_HEADER "<\xff\x01"
#define RADIOLIB_APRS_LORA_HEADER_LEN (3)
/*!
\class APRSClient
\brief Client for APRS communication.
@ -65,20 +69,28 @@
class APRSClient {
public:
/*!
\brief Default constructor.
\brief Constructor for "classic" mode using AX.25/AFSK.
\param ax Pointer to the instance of AX25Client to be used for APRS.
*/
explicit APRSClient(AX25Client* ax);
/*!
\brief Constructor for LoRa mode.
\param phy Pointer to the wireless module providing PhysicalLayer communication.
*/
explicit APRSClient(PhysicalLayer* phy);
// basic methods
/*!
\brief Initialization method.
\param sym APRS symbol to be displayed.
\param callsign Source callsign. Required and only used for APRS over LoRa, ignored in classic mode.
\param ssid Source SSID. Only used for APRS over LoRa, ignored in classic mode, defaults to 0.
\param alt Whether to use the primary (false) or alternate (true) symbol table. Defaults to primary table.
\returns \ref status_codes
*/
int16_t begin(char sym, bool alt = false);
int16_t begin(char sym, char* callsign = NULL, uint8_t ssid = 0, bool alt = false);
/*!
\brief Transmit position.
@ -120,10 +132,15 @@ class APRSClient {
private:
#endif
AX25Client* axClient;
PhysicalLayer* phyLayer;
// default APRS symbol (car)
char symbol = '>';
char table = '/';
// source callsign when using APRS over LoRa
char src[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 };
uint8_t id = 0;
};
#endif