385 lines
14 KiB
C++
385 lines
14 KiB
C++
#if !defined(_RADIOLIB_RADIOLIB_AX25_H)
|
|
#define _RADIOLIB_RADIOLIB_AX25_H
|
|
|
|
#include "../../TypeDef.h"
|
|
|
|
#if !defined(RADIOLIB_EXCLUDE_AX25)
|
|
|
|
#include "../PhysicalLayer/PhysicalLayer.h"
|
|
#include "../AFSK/AFSK.h"
|
|
|
|
// macros to access bits in byte array, from http://www.mathcs.emory.edu/~cheung/Courses/255/Syllabus/1-C-intro/bit-array.html
|
|
#define SET_BIT_IN_ARRAY(A, k) ( A[(k/8)] |= (1 << (k%8)) )
|
|
#define CLEAR_BIT_IN_ARRAY(A, k) ( A[(k/8)] &= ~(1 << (k%8)) )
|
|
#define TEST_BIT_IN_ARRAY(A, k) ( A[(k/8)] & (1 << (k%8)) )
|
|
#define GET_BIT_IN_ARRAY(A, k) ( (A[(k/8)] & (1 << (k%8))) ? 1 : 0 )
|
|
|
|
// CRC-CCITT calculation macros
|
|
#define XOR(A, B) ( ((A) || (B)) && !((A) && (B)) )
|
|
#define CRC_CCITT_POLY 0x1021 // generator polynomial
|
|
#define CRC_CCITT_POLY_REVERSED 0x8408 // CRC_CCITT_POLY in reversed bit order
|
|
#define CRC_CCITT_INIT 0xFFFF // initial value
|
|
|
|
// maximum callsign length in bytes
|
|
#define RADIOLIB_AX25_MAX_CALLSIGN_LEN 6
|
|
|
|
// flag field MSB LSB DESCRIPTION
|
|
#define RADIOLIB_AX25_FLAG 0b01111110 // 7 0 AX.25 frame start/end flag
|
|
|
|
// address field
|
|
#define RADIOLIB_AX25_SSID_COMMAND_DEST 0b10000000 // 7 7 frame type: command (set in destination SSID)
|
|
#define RADIOLIB_AX25_SSID_COMMAND_SOURCE 0b00000000 // 7 7 command (set in source SSID)
|
|
#define RADIOLIB_AX25_SSID_RESPONSE_DEST 0b00000000 // 7 7 response (set in destination SSID)
|
|
#define RADIOLIB_AX25_SSID_RESPONSE_SOURCE 0b10000000 // 7 7 response (set in source SSID)
|
|
#define RADIOLIB_AX25_SSID_HAS_NOT_BEEN_REPEATED 0b00000000 // 7 7 not repeated yet (set in repeater SSID)
|
|
#define RADIOLIB_AX25_SSID_HAS_BEEN_REPEATED 0b10000000 // 7 7 repeated (set in repeater SSID)
|
|
#define RADIOLIB_AX25_SSID_RESERVED_BITS 0b01100000 // 6 5 reserved bits in SSID
|
|
#define RADIOLIB_AX25_SSID_HDLC_EXTENSION_CONTINUE 0b00000000 // 0 0 HDLC extension bit: next octet contains more address information
|
|
#define RADIOLIB_AX25_SSID_HDLC_EXTENSION_END 0b00000001 // 0 0 address field end
|
|
|
|
// control field
|
|
#define RADIOLIB_AX25_CONTROL_U_SET_ASYNC_BAL_MODE 0b01101100 // 7 2 U frame type: set asynchronous balanced mode (connect request)
|
|
#define RADIOLIB_AX25_CONTROL_U_SET_ASYNC_BAL_MODE_EXT 0b00101100 // 7 2 set asynchronous balanced mode extended (connect request with module 128)
|
|
#define RADIOLIB_AX25_CONTROL_U_DISCONNECT 0b01000000 // 7 2 disconnect request
|
|
#define RADIOLIB_AX25_CONTROL_U_DISCONNECT_MODE 0b00001100 // 7 2 disconnect mode (system busy or disconnected)
|
|
#define RADIOLIB_AX25_CONTROL_U_UNNUMBERED_ACK 0b01100000 // 7 2 unnumbered acknowledge
|
|
#define RADIOLIB_AX25_CONTROL_U_FRAME_REJECT 0b10000100 // 7 2 frame reject
|
|
#define RADIOLIB_AX25_CONTROL_U_UNNUMBERED_INFORMATION 0b00000000 // 7 2 unnumbered information
|
|
#define RADIOLIB_AX25_CONTROL_U_EXHANGE_IDENTIFICATION 0b10101100 // 7 2 exchange ID
|
|
#define RADIOLIB_AX25_CONTROL_U_TEST 0b11100000 // 7 2 test
|
|
#define RADIOLIB_AX25_CONTROL_POLL_FINAL_ENABLED 0b00010000 // 4 4 control field poll/final bit: enabled
|
|
#define RADIOLIB_AX25_CONTROL_POLL_FINAL_DISABLED 0b00000000 // 4 4 disabled
|
|
#define RADIOLIB_AX25_CONTROL_S_RECEIVE_READY 0b00000000 // 3 2 S frame type: receive ready (system ready to receive)
|
|
#define RADIOLIB_AX25_CONTROL_S_RECEIVE_NOT_READY 0b00000100 // 3 2 receive not ready (TNC buffer full)
|
|
#define RADIOLIB_AX25_CONTROL_S_REJECT 0b00001000 // 3 2 reject (out of sequence or duplicate)
|
|
#define RADIOLIB_AX25_CONTROL_S_SELECTIVE_REJECT 0b00001100 // 3 2 selective reject (single frame repeat request)
|
|
#define RADIOLIB_AX25_CONTROL_INFORMATION_FRAME 0b00000000 // 0 0 frame type: information (I frame)
|
|
#define RADIOLIB_AX25_CONTROL_SUPERVISORY_FRAME 0b00000001 // 1 0 supervisory (S frame)
|
|
#define RADIOLIB_AX25_CONTROL_UNNUMBERED_FRAME 0b00000011 // 1 0 unnumbered (U frame)
|
|
|
|
// protocol identifier field
|
|
#define RADIOLIB_AX25_PID_ISO_8208 0x01
|
|
#define RADIOLIB_AX25_PID_TCP_IP_COMPRESSED 0x06
|
|
#define RADIOLIB_AX25_PID_TCP_IP_UNCOMPRESSED 0x07
|
|
#define RADIOLIB_AX25_PID_SEGMENTATION_FRAGMENT 0x08
|
|
#define RADIOLIB_AX25_PID_TEXNET_DATAGRAM_PROTOCOL 0xC3
|
|
#define RADIOLIB_AX25_PID_LINK_QUALITY_PROTOCOL 0xC4
|
|
#define RADIOLIB_AX25_PID_APPLETALK 0xCA
|
|
#define RADIOLIB_AX25_PID_APPLETALK_ARP 0xCB
|
|
#define RADIOLIB_AX25_PID_ARPA_INTERNET_PROTOCOL 0xCC
|
|
#define RADIOLIB_AX25_PID_ARPA_ADDRESS_RESOLUTION 0xCD
|
|
#define RADIOLIB_AX25_PID_FLEXNET 0xCE
|
|
#define RADIOLIB_AX25_PID_NET_ROM 0xCF
|
|
#define RADIOLIB_AX25_PID_NO_LAYER_3 0xF0
|
|
#define RADIOLIB_AX25_PID_ESCAPE_CHARACTER 0xFF
|
|
|
|
// AFSK tones in Hz
|
|
#define RADIOLIB_AX25_AFSK_MARK 1200
|
|
#define RADIOLIB_AX25_AFSK_SPACE 2200
|
|
|
|
// tone duration in us (for 1200 baud AFSK)
|
|
#define RADIOLIB_AX25_AFSK_TONE_DURATION 833
|
|
|
|
/*!
|
|
\class AX25Frame
|
|
|
|
\brief Abstraction of AX.25 frame format.
|
|
*/
|
|
class AX25Frame {
|
|
public:
|
|
/*!
|
|
\brief Callsign of the destination station.
|
|
*/
|
|
char destCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1];
|
|
|
|
/*!
|
|
\brief SSID of the destination station.
|
|
*/
|
|
uint8_t destSSID;
|
|
|
|
/*!
|
|
\brief Callsign of the source station.
|
|
*/
|
|
char srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1];
|
|
|
|
/*!
|
|
\brief SSID of the source station.
|
|
*/
|
|
uint8_t srcSSID;
|
|
|
|
/*!
|
|
\brief Number of repeaters to be used.
|
|
*/
|
|
uint8_t numRepeaters;
|
|
|
|
/*!
|
|
\brief The control field.
|
|
*/
|
|
uint8_t control;
|
|
|
|
/*!
|
|
\brief The protocol identifier (PID) field.
|
|
*/
|
|
uint8_t protocolID;
|
|
|
|
/*!
|
|
\brief Number of bytes in the information field.
|
|
*/
|
|
uint16_t infoLen;
|
|
|
|
/*!
|
|
\brief Receive sequence number.
|
|
*/
|
|
uint8_t rcvSeqNumber;
|
|
|
|
/*!
|
|
\brief Send sequence number.
|
|
*/
|
|
uint16_t sendSeqNumber;
|
|
|
|
#if !defined(RADIOLIB_STATIC_ONLY)
|
|
/*!
|
|
\brief The info field.
|
|
*/
|
|
uint8_t* info;
|
|
|
|
/*!
|
|
\brief Array of repeater callsigns.
|
|
*/
|
|
char** repeaterCallsigns;
|
|
|
|
/*!
|
|
\brief Array of repeater SSIDs.
|
|
*/
|
|
uint8_t* repeaterSSIDs;
|
|
#else
|
|
/*!
|
|
\brief The info field.
|
|
*/
|
|
uint8_t info[RADIOLIB_STATIC_ARRAY_SIZE];
|
|
|
|
/*!
|
|
\brief Array of repeater callsigns.
|
|
*/
|
|
char repeaterCallsigns[8][RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1];
|
|
|
|
/*!
|
|
\brief Array of repeater SSIDs.
|
|
*/
|
|
uint8_t repeaterSSIDs[8];
|
|
#endif
|
|
|
|
/*!
|
|
\brief Overloaded constructor, for frames without info field.
|
|
|
|
\param destCallsign Callsign of the destination station.
|
|
|
|
\param destSSID SSID of the destination station.
|
|
|
|
\param srcCallsign Callsign of the source station.
|
|
|
|
\param srcSSID SSID of the source station.
|
|
|
|
\param control The control field.
|
|
*/
|
|
AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control);
|
|
|
|
/*!
|
|
\brief Overloaded constructor, for frames with C-string info field.
|
|
|
|
\param destCallsign Callsign of the destination station.
|
|
|
|
\param destSSID SSID of the destination station.
|
|
|
|
\param srcCallsign Callsign of the source station.
|
|
|
|
\param srcSSID SSID of the source station.
|
|
|
|
\param control The control field.
|
|
|
|
\param protocolID The protocol identifier (PID) field. Set to zero if the frame doesn't have this field.
|
|
|
|
\param info Information field, in the form of null-terminated C-string.
|
|
*/
|
|
AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, const char* info);
|
|
|
|
/*!
|
|
\brief Default constructor.
|
|
|
|
\param destCallsign Callsign of the destination station.
|
|
|
|
\param destSSID SSID of the destination station.
|
|
|
|
\param srcCallsign Callsign of the source station.
|
|
|
|
\param srcSSID SSID of the source station.
|
|
|
|
\param control The control field.
|
|
|
|
\param protocolID The protocol identifier (PID) field. Set to zero if the frame doesn't have this field.
|
|
|
|
\param info Information field, in the form of arbitrary binary buffer.
|
|
|
|
\param infoLen Number of bytes in the information field.
|
|
*/
|
|
AX25Frame(const char* destCallsign, uint8_t destSSID, const char* srcCallsign, uint8_t srcSSID, uint8_t control, uint8_t protocolID, uint8_t* info, uint16_t infoLen);
|
|
|
|
/*!
|
|
\brief Copy constructor.
|
|
|
|
\param frame AX25Frame instance to copy.
|
|
*/
|
|
AX25Frame(const AX25Frame& frame);
|
|
|
|
/*!
|
|
\brief Default destructor.
|
|
*/
|
|
~AX25Frame();
|
|
|
|
/*!
|
|
\brief Overload for assignment operator.
|
|
|
|
\param frame rvalue AX25Frame.
|
|
*/
|
|
AX25Frame& operator=(const AX25Frame& frame);
|
|
|
|
/*!
|
|
\brief Method to set the repeater callsigns and SSIDs.
|
|
|
|
\param repeaterCallsigns Array of repeater callsigns in the form of null-terminated C-strings.
|
|
|
|
\param repeaterSSIDs Array of repeater SSIDs.
|
|
|
|
\param numRepeaters Number of repeaters, maximum is 8.
|
|
|
|
\returns \ref status_codes
|
|
*/
|
|
int16_t setRepeaters(char** repeaterCallsigns, uint8_t* repeaterSSIDs, uint8_t numRepeaters);
|
|
|
|
/*!
|
|
\brief Method to set receive sequence number.
|
|
|
|
\param seqNumber Sequence number to set, 0 to 7.
|
|
*/
|
|
void setRecvSequence(uint8_t seqNumber);
|
|
|
|
/*!
|
|
\brief Method to set send sequence number.
|
|
|
|
\param seqNumber Sequence number to set, 0 to 7.
|
|
*/
|
|
void setSendSequence(uint8_t seqNumber);
|
|
};
|
|
|
|
/*!
|
|
\class AX25Client
|
|
|
|
\brief Client for AX25 communication.
|
|
*/
|
|
class AX25Client {
|
|
public:
|
|
/*!
|
|
\brief Constructor for 2-FSK mode.
|
|
|
|
\param phy Pointer to the wireless module providing PhysicalLayer communication.
|
|
*/
|
|
explicit AX25Client(PhysicalLayer* phy);
|
|
|
|
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
|
/*!
|
|
\brief Constructor for AFSK mode.
|
|
|
|
\param audio Pointer to the AFSK instance providing audio.
|
|
*/
|
|
explicit AX25Client(AFSKClient* audio);
|
|
|
|
/*!
|
|
\brief Set AFSK tone correction offset. On some platforms, this is required to get the audio produced by the setup to match the expected 1200/2200 Hz tones.
|
|
|
|
\param mark Positive or negative correction offset for mark audio frequency in Hz.
|
|
|
|
\param space Positive or negative correction offset for space audio frequency in Hz.
|
|
|
|
\param length Audio tone length modifier, defaults to 1.0.
|
|
|
|
\returns \ref status_codes
|
|
*/
|
|
int16_t setCorrection(int16_t mark, int16_t space, float length = 1.0f);
|
|
#endif
|
|
|
|
// basic methods
|
|
|
|
/*!
|
|
\brief Initialization method.
|
|
|
|
\param srcCallsign Callsign of the source station.
|
|
|
|
\param srcSSID 4-bit SSID of the source station (in case there are more stations with the same callsign). Defaults to 0.
|
|
|
|
\param preambleLen Number of "preamble" bytes (RADIOLIB_AX25_FLAG) sent ahead of the actual AX.25 frame. Does not include the first RADIOLIB_AX25_FLAG byte, which is considered part of the frame. Defaults to 8.
|
|
|
|
\returns \ref status_codes
|
|
*/
|
|
int16_t begin(const char* srcCallsign, uint8_t srcSSID = 0x00, uint8_t preambleLen = 8);
|
|
|
|
/*!
|
|
\brief Transmit unnumbered information (UI) frame.
|
|
|
|
\param str Data to be sent as Arduino String.
|
|
|
|
\param destCallsign Callsign of the destination station.
|
|
|
|
\param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). Defaults to 0.
|
|
|
|
\returns \ref status_codes
|
|
*/
|
|
int16_t transmit(String& str, const char* destCallsign, uint8_t destSSID = 0x00);
|
|
|
|
/*!
|
|
\brief Transmit unnumbered information (UI) frame.
|
|
|
|
\param str Data to be sent.
|
|
|
|
\param destCallsign Callsign of the destination station.
|
|
|
|
\param destSSID 4-bit SSID of the destination station (in case there are more stations with the same callsign). Defaults to 0.
|
|
|
|
\returns \ref status_codes
|
|
*/
|
|
int16_t transmit(const char* str, const char* destCallsign, uint8_t destSSID = 0x00);
|
|
|
|
/*!
|
|
\brief Transmit arbitrary AX.25 frame.
|
|
|
|
\param frame Frame to be sent.
|
|
|
|
\returns \ref status_codes
|
|
*/
|
|
int16_t sendFrame(AX25Frame* frame);
|
|
|
|
#if !defined(RADIOLIB_GODMODE)
|
|
private:
|
|
#endif
|
|
friend class APRSClient;
|
|
|
|
PhysicalLayer* _phy;
|
|
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
|
AFSKClient* _audio;
|
|
uint32_t _afskMark;
|
|
uint32_t _afskSpace;
|
|
uint32_t _afskLen;
|
|
#endif
|
|
|
|
char _srcCallsign[RADIOLIB_AX25_MAX_CALLSIGN_LEN + 1] = {0, 0, 0, 0, 0, 0, 0};
|
|
uint8_t _srcSSID = 0;
|
|
uint16_t _preambleLen = 0;
|
|
|
|
static uint16_t getFrameCheckSequence(uint8_t* buff, size_t len);
|
|
|
|
void getCallsign(char* buff);
|
|
uint8_t getSSID();
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif
|