kopia lustrzana https://github.com/jgromes/RadioLib
[APRS] Added APRS support
rodzic
3eb831d7e1
commit
df466486aa
|
@ -35,6 +35,8 @@ SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
|
||||||
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x
|
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, RFM2x and Si443x
|
||||||
* [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules:
|
* [__Hellschreiber__](https://www.sigidwiki.com/wiki/Hellschreiber) using 2-FSK or AFSK for modules:
|
||||||
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
|
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
|
||||||
|
* [__APRS__](https://www.sigidwiki.com/wiki/APRS) using AFSK for modules:
|
||||||
|
SX127x, RFM9x, SX126x, RF69, SX1231, CC1101, nRF24L01, RFM2x, Si443x and SX128x
|
||||||
|
|
||||||
### Supported Arduino platforms:
|
### Supported Arduino platforms:
|
||||||
* __Arduino__
|
* __Arduino__
|
||||||
|
@ -76,7 +78,6 @@ The list above is by no means exhaustive - RadioLib code is independent of the u
|
||||||
### In development:
|
### In development:
|
||||||
* __AX5243__ FSK module
|
* __AX5243__ FSK module
|
||||||
* __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules
|
* __LoRaWAN__ protocol for SX127x, RFM9x and SX126x modules
|
||||||
* __APRS__ protocol for all the modules that can transmit AX.25
|
|
||||||
* ___and more!___
|
* ___and more!___
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
RadioLib APRS Position Example
|
||||||
|
|
||||||
|
This example sends APRS position reports
|
||||||
|
using SX1278's FSK modem. The data is
|
||||||
|
modulated as AFSK at 1200 baud using Bell
|
||||||
|
202 tones.
|
||||||
|
|
||||||
|
DO NOT transmit in APRS bands unless
|
||||||
|
you have a ham radio license!
|
||||||
|
|
||||||
|
Other modules that can be used for APRS:
|
||||||
|
- SX127x/RFM9x
|
||||||
|
- RF69
|
||||||
|
- SX1231
|
||||||
|
- CC1101
|
||||||
|
- nRF24
|
||||||
|
- Si443x/RFM2x
|
||||||
|
|
||||||
|
For default module settings, see the wiki page
|
||||||
|
https://github.com/jgromes/RadioLib/wiki/Default-configuration
|
||||||
|
|
||||||
|
For full API reference, see the GitHub Pages
|
||||||
|
https://jgromes.github.io/RadioLib/
|
||||||
|
*/
|
||||||
|
|
||||||
|
// include the library
|
||||||
|
#include <RadioLib.h>
|
||||||
|
|
||||||
|
// SX1278 has the following connections:
|
||||||
|
// NSS pin: 10
|
||||||
|
// DIO0 pin: 2
|
||||||
|
// RESET pin: 9
|
||||||
|
// DIO1 pin: 3
|
||||||
|
SX1278 radio = new Module(10, 2, 9, 3);
|
||||||
|
|
||||||
|
// or using RadioShield
|
||||||
|
// https://github.com/jgromes/RadioShield
|
||||||
|
//SX1278 radio = RadioShield.ModuleA;
|
||||||
|
|
||||||
|
// create AFSK client instance using the FSK module
|
||||||
|
// pin 5 is connected to SX1278 DIO2
|
||||||
|
AFSKClient audio(&radio, 5);
|
||||||
|
|
||||||
|
// create AX.25 client instance using the AFSK instance
|
||||||
|
AX25Client ax25(&audio);
|
||||||
|
|
||||||
|
// create APRS client isntance using the AX.25 client
|
||||||
|
APRSClient aprs(&ax25);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
// initialize SX1278
|
||||||
|
// NOTE: moved to ISM band on purpose
|
||||||
|
// DO NOT transmit in APRS bands without ham radio license!
|
||||||
|
Serial.print(F("[SX1278] Initializing ... "));
|
||||||
|
int state = radio.beginFSK(434.0);
|
||||||
|
|
||||||
|
// when using one of the non-LoRa modules for AX.25
|
||||||
|
// (RF69, CC1101, Si4432 etc.), use the basic begin() method
|
||||||
|
// int state = radio.begin();
|
||||||
|
|
||||||
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
|
Serial.println(F("success!"));
|
||||||
|
} else {
|
||||||
|
Serial.print(F("failed, code "));
|
||||||
|
Serial.println(state);
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize AX.25 client
|
||||||
|
Serial.print(F("[AX.25] Initializing ... "));
|
||||||
|
// source station callsign: "N7LEM"
|
||||||
|
// source station SSID: 0
|
||||||
|
// preamble length: 8 bytes
|
||||||
|
state = ax25.begin("N7LEM");
|
||||||
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
|
Serial.println(F("success!"));
|
||||||
|
} else {
|
||||||
|
Serial.print(F("failed, code "));
|
||||||
|
Serial.println(state);
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize APRS client
|
||||||
|
Serial.print(F("[APRS] Initializing ... "));
|
||||||
|
// symbol: '>' (car)
|
||||||
|
state = aprs.begin('>');
|
||||||
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
|
Serial.println(F("success!"));
|
||||||
|
} else {
|
||||||
|
Serial.print(F("failed, code "));
|
||||||
|
Serial.println(state);
|
||||||
|
while(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
Serial.print(F("[APRS] Sending position ... "));
|
||||||
|
|
||||||
|
// send a location without message or timestamp
|
||||||
|
int state = aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E");
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
// send a location with message and without timestamp
|
||||||
|
state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!");
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
// send a location with message and timestamp
|
||||||
|
state |= aprs.sendPosition("N0CALL", 0, "4911.67N", "01635.96E", "I'm here!", "093045z");
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
if(state == RADIOLIB_ERR_NONE) {
|
||||||
|
Serial.println(F("success!"));
|
||||||
|
} else {
|
||||||
|
Serial.print(F("failed, code "));
|
||||||
|
Serial.println(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// wait one minute before transmitting again
|
||||||
|
delay(60000);
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ SSTVClient KEYWORD1
|
||||||
HellClient KEYWORD1
|
HellClient KEYWORD1
|
||||||
AFSKClient KEYWORD1
|
AFSKClient KEYWORD1
|
||||||
FSK4Client KEYWORD1
|
FSK4Client KEYWORD1
|
||||||
|
APRSClient KEYWORD1
|
||||||
|
|
||||||
# SSTV modes
|
# SSTV modes
|
||||||
Scottie1 KEYWORD1
|
Scottie1 KEYWORD1
|
||||||
|
@ -217,6 +218,9 @@ printGlyph KEYWORD2
|
||||||
tone KEYWORD2
|
tone KEYWORD2
|
||||||
noTone KEYWORD2
|
noTone KEYWORD2
|
||||||
|
|
||||||
|
# APRS
|
||||||
|
sendPosition KEYWORD2
|
||||||
|
|
||||||
#######################################
|
#######################################
|
||||||
# Constants (LITERAL1)
|
# Constants (LITERAL1)
|
||||||
#######################################
|
#######################################
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
- SSTV (SSTVClient)
|
- SSTV (SSTVClient)
|
||||||
- Hellschreiber (HellClient)
|
- Hellschreiber (HellClient)
|
||||||
- 4-FSK (FSK4Client)
|
- 4-FSK (FSK4Client)
|
||||||
|
- APRS (APRSClient)
|
||||||
|
|
||||||
\par Quick Links
|
\par Quick Links
|
||||||
Documentation for most common methods can be found in its reference page (see the list above).\n
|
Documentation for most common methods can be found in its reference page (see the list above).\n
|
||||||
|
@ -89,6 +90,7 @@
|
||||||
#include "protocols/RTTY/RTTY.h"
|
#include "protocols/RTTY/RTTY.h"
|
||||||
#include "protocols/SSTV/SSTV.h"
|
#include "protocols/SSTV/SSTV.h"
|
||||||
#include "protocols/FSK4/FSK4.h"
|
#include "protocols/FSK4/FSK4.h"
|
||||||
|
#include "protocols/APRS/APRS.h"
|
||||||
|
|
||||||
// only create Radio class when using RadioShield
|
// only create Radio class when using RadioShield
|
||||||
#if defined(RADIOLIB_RADIOSHIELD)
|
#if defined(RADIOLIB_RADIOSHIELD)
|
||||||
|
|
|
@ -245,6 +245,13 @@
|
||||||
*/
|
*/
|
||||||
#define RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE (-108)
|
#define RADIOLIB_ERR_INVALID_OOK_RSSI_PEAK_TYPE (-108)
|
||||||
|
|
||||||
|
// APRS status codes
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Supplied APRS symbol is invalid.
|
||||||
|
*/
|
||||||
|
#define RADIOLIB_ERR_INVALID_SYMBOL (-201)
|
||||||
|
|
||||||
// RTTY status codes
|
// RTTY status codes
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
#include "APRS.h"
|
||||||
|
|
||||||
|
APRSClient::APRSClient(AX25Client* ax) {
|
||||||
|
_ax = ax;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t APRSClient::begin(char symbol, bool alt) {
|
||||||
|
RADIOLIB_CHECK_RANGE(symbol, ' ', '}', RADIOLIB_ERR_INVALID_SYMBOL);
|
||||||
|
_symbol = symbol;
|
||||||
|
|
||||||
|
if(alt) {
|
||||||
|
_table = '\\';
|
||||||
|
} else {
|
||||||
|
_table = '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
return(RADIOLIB_ERR_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t APRSClient::sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg, char* time) {
|
||||||
|
#if !defined(RADIOLIB_STATIC_ONLY)
|
||||||
|
size_t len = 1 + strlen(lat) + 1 + strlen(lon);
|
||||||
|
if(msg != NULL) {
|
||||||
|
len += 1 + strlen(msg);
|
||||||
|
}
|
||||||
|
if(time != NULL) {
|
||||||
|
len += strlen(time);
|
||||||
|
}
|
||||||
|
char* info = new char[len];
|
||||||
|
#else
|
||||||
|
char info[RADIOLIB_STATIC_ARRAY_SIZE];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// build the info field
|
||||||
|
if((msg == NULL) && (time == NULL)) {
|
||||||
|
// no message, no timestamp
|
||||||
|
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "%s%c%s%c", lat, _table, lon, _symbol);
|
||||||
|
} else if((msg != NULL) && (time == NULL)) {
|
||||||
|
// message, no timestamp
|
||||||
|
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "%s%c%s%c%s", lat, _table, lon, _symbol, msg);
|
||||||
|
} else if((msg == NULL) && (time != NULL)) {
|
||||||
|
// timestamp, no message
|
||||||
|
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "%s%s%c%s%c", time, lat, _table, lon, _symbol);
|
||||||
|
} else {
|
||||||
|
// timestamp and message
|
||||||
|
sprintf(info, RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "%s%s%c%s%c%s", time, lat, _table, lon, _symbol, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
// send the frame
|
||||||
|
int16_t state = sendFrame(destCallsign, destSSID, info);
|
||||||
|
#if !defined(RADIOLIB_STATIC_ONLY)
|
||||||
|
delete[] info;
|
||||||
|
#endif
|
||||||
|
return(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t APRSClient::sendFrame(char* destCallsign, uint8_t destSSID, char* info) {
|
||||||
|
// get AX.25 callsign
|
||||||
|
char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1];
|
||||||
|
_ax->getCallsign(srcCallsign);
|
||||||
|
|
||||||
|
AX25Frame frameUI(destCallsign, destSSID, srcCallsign, _ax->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(_ax->sendFrame(&frameUI));
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
#if !defined(_RADIOLIB_RADIOLIB_APRS_H)
|
||||||
|
#define _RADIOLIB_RADIOLIB_APRS_H
|
||||||
|
|
||||||
|
#include "../../TypeDef.h"
|
||||||
|
|
||||||
|
#if !defined(RADIOLIB_EXCLUDE_APRS)
|
||||||
|
|
||||||
|
#include "../PhysicalLayer/PhysicalLayer.h"
|
||||||
|
#include "../AX25/AX25.h"
|
||||||
|
|
||||||
|
// APRS data type identifiers
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_NO_MSG "!"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_GPS_RAW "$"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_ITEM ")"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_TEST ","
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_NO_MSG "/"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_MSG ":"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_OBJECT ";"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_STATION_CAPABILITES "<"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_POSITION_NO_TIME_MSG "="
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_STATUS ">"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_QUERY "?"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_POSITION_TIME_MSG "@"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_TELEMETRY "T"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_MAIDENHEAD_BEACON "["
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_WEATHER_REPORT "_"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_USER_DEFINED "{"
|
||||||
|
#define RADIOLIB_APRS_DATA_TYPE_THIRD_PARTY "}"
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class APRSClient
|
||||||
|
|
||||||
|
\brief Client for APRS communication.
|
||||||
|
*/
|
||||||
|
class APRSClient {
|
||||||
|
public:
|
||||||
|
/*!
|
||||||
|
\brief Default constructor.
|
||||||
|
|
||||||
|
\param ax Pointer to the instance of AX25Client to be used for APRS.
|
||||||
|
*/
|
||||||
|
explicit APRSClient(AX25Client* ax);
|
||||||
|
|
||||||
|
// basic methods
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Initialization method.
|
||||||
|
|
||||||
|
\param symbol APRS symbol to be displayed.
|
||||||
|
|
||||||
|
\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 symbol, bool alt = false);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Transmit position.
|
||||||
|
|
||||||
|
\param destCallsign Destination station callsign.
|
||||||
|
|
||||||
|
\param destSSID Destination station SSID.
|
||||||
|
|
||||||
|
\param lat Latitude as a null-terminated string.
|
||||||
|
|
||||||
|
\param long Longitude as a null-terminated string.
|
||||||
|
|
||||||
|
\param msg Message to be transmitted. Defaults to NULL (no message).
|
||||||
|
|
||||||
|
\param msg Position timestamp. Defaults to NULL (no timestamp).
|
||||||
|
|
||||||
|
\returns \ref status_codes
|
||||||
|
*/
|
||||||
|
int16_t sendPosition(char* destCallsign, uint8_t destSSID, char* lat, char* lon, char* msg = NULL, char* time = NULL);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Transmit generic APRS frame.
|
||||||
|
|
||||||
|
\param destCallsign Destination station callsign.
|
||||||
|
|
||||||
|
\param destSSID Destination station SSID.
|
||||||
|
|
||||||
|
\param info AX.25 info field contents.
|
||||||
|
|
||||||
|
\returns \ref status_codes
|
||||||
|
*/
|
||||||
|
int16_t sendFrame(char* destCallsign, uint8_t destSSID, char* info);
|
||||||
|
|
||||||
|
#if !defined(RADIOLIB_GODMODE)
|
||||||
|
private:
|
||||||
|
#endif
|
||||||
|
AX25Client* _ax;
|
||||||
|
|
||||||
|
// default APRS symbol (car)
|
||||||
|
char _symbol = '>';
|
||||||
|
char _table = '/';
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Ładowanie…
Reference in New Issue