[RTTY] Added AFSK support

This commit is contained in:
jgromes 2020-04-30 17:11:09 +02:00
parent 0a705f5bb9
commit f7f81cd41e
3 changed files with 182 additions and 11 deletions

View file

@ -0,0 +1,133 @@
/*
RadioLib RTTY Transmit AFSK Example
This example sends RTTY message using SX1278's
FSK modem. The data is modulated as AFSK.
Other modules that can be used for RTTY:
- SX127x/RFM9x
- RF69
- SX1231
- CC1101
- 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 RTTY client instance using the AFSK instance
RTTYClient rtty(&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();
// when using one of the non-LoRa modules for RTTY
// (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 RTTY client
// NOTE: Unlike FSK RTTY, AFSK requires no rounding of
// the frequency shift.
Serial.print(F("[RTTY] Initializing ... "));
// space frequency: 400 Hz
// frequency shift: 170 Hz
// baud rate: 45 baud
// encoding: ASCII (7-bit)
// stop bits: 1
state = rtty.begin(400, 170, 45);
if(state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
/*
// RadioLib also provides ITA2 ("Baudot") support
rtty.begin(400, 170, 45, ITA2);
// All transmissions in loop() (strings and numbers)
// will now be encoded using ITA2 code
// ASCII characters that do not have ITA2 equivalent
// will be sent as NUL (including lower case letters!)
*/
}
void loop() {
Serial.print(F("[RTTY] Sending RTTY data ... "));
// send out idle condition for 500 ms
rtty.idle();
delay(500);
// RTTYClient supports all methods of the Serial class
// Arduino String class
String aStr = "Arduino String";
rtty.println(aStr);
// character array (C-String)
rtty.println("C-String");
// string saved in flash
rtty.println(F("Flash String"));
// character
rtty.println('c');
// byte
// formatting DEC/HEX/OCT/BIN is supported for
// any integer type (byte/int/long)
rtty.println(255, HEX);
// integer number
int i = 1000;
rtty.println(i);
// floating point number
float f = -3.1415;
rtty.println(f, 3);
Serial.println(F("done!"));
// wait for a second before transmitting again
delay(1000);
}

View file

@ -106,12 +106,20 @@ uint16_t ITA2String::getBits(char c) {
RTTYClient::RTTYClient(PhysicalLayer* phy) { RTTYClient::RTTYClient(PhysicalLayer* phy) {
_phy = phy; _phy = phy;
_audio = nullptr;
}
RTTYClient::RTTYClient(AFSKClient* audio) {
_phy = audio->_phy;
_audio = audio;
} }
int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding, uint8_t stopBits) { int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t encoding, uint8_t stopBits) {
// save configuration // save configuration
_encoding = encoding; _encoding = encoding;
_stopBits = stopBits; _stopBits = stopBits;
_baseHz = base;
_shiftHz = shift;
switch(encoding) { switch(encoding) {
case ASCII: case ASCII:
@ -148,15 +156,17 @@ int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc
// calculate 24-bit frequency // calculate 24-bit frequency
_base = (base * 1000000.0) / _phy->getFreqStep(); _base = (base * 1000000.0) / _phy->getFreqStep();
// set module frequency deviation to 0 // set module frequency deviation to 0 if using FSK
int16_t state = _phy->setFrequencyDeviation(0); int16_t state = ERR_NONE;
if(_audio == nullptr) {
state = _phy->setFrequencyDeviation(0);
}
return(state); return(state);
} }
void RTTYClient::idle() { void RTTYClient::idle() {
_phy->transmitDirect(); transmitDirect();
mark(); mark();
} }
@ -190,7 +200,7 @@ size_t RTTYClient::write(uint8_t b) {
mark(); mark();
} }
_phy->standby(); standby();
return(1); return(1);
} }
@ -391,7 +401,7 @@ size_t RTTYClient::println(double d, int digits) {
void RTTYClient::mark() { void RTTYClient::mark() {
uint32_t start = micros(); uint32_t start = micros();
_phy->transmitDirect(_base + _shift); transmitDirect(_base + _shift, _baseHz + _shiftHz);
while(micros() - start < _bitDuration) { while(micros() - start < _bitDuration) {
yield(); yield();
} }
@ -399,7 +409,7 @@ void RTTYClient::mark() {
void RTTYClient::space() { void RTTYClient::space() {
uint32_t start = micros(); uint32_t start = micros();
_phy->transmitDirect(_base); transmitDirect(_base, _baseHz);
while(micros() - start < _bitDuration) { while(micros() - start < _bitDuration) {
yield(); yield();
} }
@ -505,3 +515,19 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) {
return n; return n;
} }
int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) {
if(_audio != nullptr) {
return(_audio->tone(freqHz));
} else {
return(_phy->transmitDirect(freq));
}
}
int16_t RTTYClient::standby() {
if(_audio != nullptr) {
return(_audio->noTone());
} else {
return(_phy->standby());
}
}

View file

@ -3,6 +3,7 @@
#include "../../TypeDef.h" #include "../../TypeDef.h"
#include "../PhysicalLayer/PhysicalLayer.h" #include "../PhysicalLayer/PhysicalLayer.h"
#include "../AFSK/AFSK.h"
#define ITA2_FIGS 0x1B #define ITA2_FIGS 0x1B
#define ITA2_LTRS 0x1F #define ITA2_LTRS 0x1F
@ -84,18 +85,25 @@ class ITA2String {
class RTTYClient { class RTTYClient {
public: public:
/*! /*!
\brief Default constructor. \brief Constructor for 2-FSK mode.
\param phy Pointer to the wireless module providing PhysicalLayer communication. \param phy Pointer to the wireless module providing PhysicalLayer communication.
*/ */
RTTYClient(PhysicalLayer* phy); RTTYClient(PhysicalLayer* phy);
/*!
\brief Constructor for AFSK mode.
\param audio Pointer to the AFSK instance providing audio.
*/
RTTYClient(AFSKClient* audio);
// basic methods // basic methods
/*! /*!
\brief Initialization method. \brief Initialization method.
\param base Base (space) RF frequency to be used in MHz. \param base Base (space) frequency to be used in MHz (in 2-FSK mode), or the space tone frequency in Hz (in AFSK mode)
\param shift Frequency shift between mark and space in Hz. \param shift Frequency shift between mark and space in Hz.
@ -147,10 +155,11 @@ class RTTYClient {
private: private:
#endif #endif
PhysicalLayer* _phy; PhysicalLayer* _phy;
AFSKClient* _audio;
uint8_t _encoding; uint8_t _encoding;
uint32_t _base; uint32_t _base, _baseHz;
uint32_t _shift; uint32_t _shift, _shiftHz;
uint32_t _bitDuration; uint32_t _bitDuration;
uint8_t _dataBits; uint8_t _dataBits;
uint8_t _stopBits; uint8_t _stopBits;
@ -160,6 +169,9 @@ class RTTYClient {
size_t printNumber(unsigned long, uint8_t); size_t printNumber(unsigned long, uint8_t);
size_t printFloat(double, uint8_t); size_t printFloat(double, uint8_t);
int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0);
int16_t standby();
}; };
#endif #endif