[AX25] Added AFSK support

This commit is contained in:
jgromes 2020-04-30 17:10:21 +02:00
parent 072e4288c9
commit ed69931041
5 changed files with 165 additions and 9 deletions

View file

@ -19,6 +19,9 @@
Frames shown in this example are not
exhaustive; all possible AX.25 frames
should be supported.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library

View file

@ -12,6 +12,9 @@
- SX126x
- nRF24
- Si443x/RFM2x
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
@ -37,8 +40,8 @@ void setup() {
// initialize SX1278
Serial.print(F("[SX1278] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 1.2 kbps (1200 baud AFSK AX.25)
// frequency deviation: 0.5 kHz (1200 baud AFSK AX.25)
// bit rate: 1.2 kbps (1200 baud 2-FSK AX.25)
// frequency deviation: 0.5 kHz (1200 baud 2-FSK AX.25)
int state = fsk.beginFSK(434.0, 1.2, 0.5);
// when using one of the non-LoRa modules for AX.25

View file

@ -0,0 +1,100 @@
/*
RadioLib AX.25 Transmit AFSK Example
This example sends AX.25 messages using
SX1278's FSK modem. The data is modulated
as AFSK at 1200 baud using Bell 202 tones.
Other modules that can be used for AX.25
with AFSK modulation:
- SX127x/RFM9x
- RF69
- SX1231
- CC1101
- nRF24
- Si443x/RFM2x
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 fsk = new Module(10, 2, 9, 3);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1278 fsk = RadioShield.ModuleA;
// create AFSK client instance using the FSK module
// pin 5 is connected to SX1278 DIO2
AFSKClient audio(&fsk, 5);
// create AX.25 client instance using the AFSK instance
AX25Client ax25(&audio);
void setup() {
Serial.begin(9600);
// initialize SX1278
Serial.print(F("[SX1278] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// frequency deviation: 50.0 kHz
// Rx bandwidth: 125.0 kHz
// output power: 13 dBm
// current limit: 100 mA
int state = fsk.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 = fsk.begin();
if(state == 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 == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
// send AX.25 unnumbered information frame
Serial.print(F("[AX.25] Sending UI frame ... "));
// destination station callsign: "NJ7P"
// destination station SSID: 0
int state = ax25.transmit("Hello World!", "NJ7P");
if (state == ERR_NONE) {
// the packet was successfully transmitted
Serial.println(F("success!"));
} else {
// some error occurred
Serial.print(F("failed, code "));
Serial.println(state);
}
delay(1000);
}

View file

@ -112,6 +112,12 @@ void AX25Frame::setSendSequence(uint8_t seqNumber) {
AX25Client::AX25Client(PhysicalLayer* phy) {
_phy = phy;
_audio = nullptr;
}
AX25Client::AX25Client(AFSKClient* audio) {
_phy = audio->_phy;
_audio = audio;
}
int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t preambleLen) {
@ -130,11 +136,14 @@ int16_t AX25Client::begin(const char* srcCallsign, uint8_t srcSSID, uint8_t prea
// save preamble length
_preambleLen = preambleLen;
// disable physical layer data shaping and set encoding to NRZ
int16_t state = _phy->setDataShaping(0.0);
RADIOLIB_ASSERT(state);
// set module frequency deviation to 0 if using FSK
int16_t state = ERR_NONE;
if(_audio == nullptr) {
state = _phy->setFrequencyDeviation(0);
RADIOLIB_ASSERT(state);
state = _phy->setEncoding(0);
state = _phy->setEncoding(0);
}
return(state);
}
@ -154,7 +163,7 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) {
if(strlen(frame->destCallsign) > AX25_MAX_CALLSIGN_LEN) {
return(ERR_INVALID_CALLSIGN);
}
// check repeater configuration
#ifndef RADIOLIB_STATIC_ONLY
if(!(((frame->repeaterCallsigns == NULL) && (frame->repeaterSSIDs == NULL) && (frame->numRepeaters == 0)) ||
@ -333,7 +342,32 @@ int16_t AX25Client::sendFrame(AX25Frame* frame) {
}
// transmit
int16_t state = _phy->transmit(stuffedFrameBuff, stuffedFrameBuffLen);
int16_t state = ERR_NONE;
if(_audio == nullptr) {
state = _phy->transmit(stuffedFrameBuff, stuffedFrameBuffLen);
} else {
_phy->transmitDirect();
// iterate over all bytes in the buffer
for(uint32_t i = 0; i < stuffedFrameBuffLen; i++) {
// check each bit
for(uint16_t mask = 0x80; mask >= 0x01; mask >>= 1) {
uint32_t start = micros();
if(stuffedFrameBuff[i] & mask) {
_audio->tone(AX25_AFSK_MARK, false);
} else {
_audio->tone(AX25_AFSK_SPACE, false);
}
while(micros() - start < 833) {
yield();
}
}
}
_audio->noTone();
}
// deallocate memory
#ifndef RADIOLIB_STATIC_ONLY

View file

@ -3,6 +3,7 @@
#include "../../TypeDef.h"
#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)) )
@ -69,6 +70,13 @@
#define AX25_PID_NO_LAYER_3 0xF0
#define AX25_PID_ESCAPE_CHARACTER 0xFF
// AFSK tones in Hz
#define AX25_AFSK_MARK 1200
#define AX25_AFSK_SPACE 2200
// tone duration in us (for 1200 baud AFSK)
#define AX25_AFSK_TONE_DURATION 833
/*!
\class AX25Frame
@ -254,12 +262,19 @@ class AX25Frame {
class AX25Client {
public:
/*!
\brief Default constructor.
\brief Constructor for 2-FSK mode.
\param phy Pointer to the wireless module providing PhysicalLayer communication.
*/
AX25Client(PhysicalLayer* phy);
/*!
\brief Constructor for AFSK mode.
\param audio Pointer to the AFSK instance providing audio.
*/
AX25Client(AFSKClient* audio);
// basic methods
/*!
@ -301,6 +316,7 @@ class AX25Client {
private:
#endif
PhysicalLayer* _phy;
AFSKClient* _audio;
char _srcCallsign[AX25_MAX_CALLSIGN_LEN + 1];
uint8_t _srcSSID;