[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) { APRSClient::APRSClient(AX25Client* ax) {
axClient = 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); RADIOLIB_CHECK_RANGE(sym, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL);
symbol = sym; symbol = sym;
@ -18,6 +24,16 @@ int16_t APRSClient::begin(char sym, bool alt) {
table = '/'; 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); return(RADIOLIB_ERR_NONE);
} }
@ -30,7 +46,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat
if(time != NULL) { if(time != NULL) {
len += strlen(time); len += strlen(time);
} }
char* info = new char[len]; char* info = new char[len + 1];
#else #else
char info[RADIOLIB_STATIC_ARRAY_SIZE]; char info[RADIOLIB_STATIC_ARRAY_SIZE];
#endif #endif
@ -49,6 +65,7 @@ int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat
// timestamp and message // timestamp and message
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, table, lon, symbol, msg); 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 // send the frame
int16_t state = sendFrame(destCallsign, destSSID, info); 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'; info[infoPos++] = '\0';
// send the frame // 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) #if !defined(RADIOLIB_STATIC_ONLY)
delete[] info; delete[] info;
#endif #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) { int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) {
// get AX.25 callsign // encoding depends on whether AX.25 should be used or not
char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1]; if(this->axClient != nullptr) {
axClient->getCallsign(srcCallsign); // 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 | 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_CONTROL_POLL_FINAL_DISABLED | RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME,
RADIOLIB_AX25_PID_NO_LAYER_3, (const char*)info); 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 #endif

View file

@ -58,6 +58,10 @@
// alias for unused altitude in Mic-E // alias for unused altitude in Mic-E
#define RADIOLIB_APRS_MIC_E_ALTITUDE_UNUSED -1000000 #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 \class APRSClient
\brief Client for APRS communication. \brief Client for APRS communication.
@ -65,20 +69,28 @@
class APRSClient { class APRSClient {
public: 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. \param ax Pointer to the instance of AX25Client to be used for APRS.
*/ */
explicit APRSClient(AX25Client* ax); 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 // basic methods
/*! /*!
\brief Initialization method. \brief Initialization method.
\param sym APRS symbol to be displayed. \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. \param alt Whether to use the primary (false) or alternate (true) symbol table. Defaults to primary table.
\returns \ref status_codes \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. \brief Transmit position.
@ -120,10 +132,15 @@ class APRSClient {
private: private:
#endif #endif
AX25Client* axClient; AX25Client* axClient;
PhysicalLayer* phyLayer;
// default APRS symbol (car) // default APRS symbol (car)
char symbol = '>'; char symbol = '>';
char table = '/'; char table = '/';
// source callsign when using APRS over LoRa
char src[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = { 0 };
uint8_t id = 0;
}; };
#endif #endif