diff --git a/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino new file mode 100644 index 00000000..d836821e --- /dev/null +++ b/examples/RTTY/RTTY_Transmit_AFSK/RTTY_Transmit_AFSK.ino @@ -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 + +// 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); +} diff --git a/src/protocols/RTTY/RTTY.cpp b/src/protocols/RTTY/RTTY.cpp index 085d3794..1a96d5e2 100644 --- a/src/protocols/RTTY/RTTY.cpp +++ b/src/protocols/RTTY/RTTY.cpp @@ -106,12 +106,20 @@ uint16_t ITA2String::getBits(char c) { RTTYClient::RTTYClient(PhysicalLayer* 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) { // save configuration _encoding = encoding; _stopBits = stopBits; + _baseHz = base; + _shiftHz = shift; switch(encoding) { 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 _base = (base * 1000000.0) / _phy->getFreqStep(); - // set module frequency deviation to 0 - int16_t state = _phy->setFrequencyDeviation(0); + // set module frequency deviation to 0 if using FSK + int16_t state = ERR_NONE; + if(_audio == nullptr) { + state = _phy->setFrequencyDeviation(0); + } return(state); } void RTTYClient::idle() { - _phy->transmitDirect(); - + transmitDirect(); mark(); } @@ -190,7 +200,7 @@ size_t RTTYClient::write(uint8_t b) { mark(); } - _phy->standby(); + standby(); return(1); } @@ -391,7 +401,7 @@ size_t RTTYClient::println(double d, int digits) { void RTTYClient::mark() { uint32_t start = micros(); - _phy->transmitDirect(_base + _shift); + transmitDirect(_base + _shift, _baseHz + _shiftHz); while(micros() - start < _bitDuration) { yield(); } @@ -399,7 +409,7 @@ void RTTYClient::mark() { void RTTYClient::space() { uint32_t start = micros(); - _phy->transmitDirect(_base); + transmitDirect(_base, _baseHz); while(micros() - start < _bitDuration) { yield(); } @@ -505,3 +515,19 @@ size_t RTTYClient::printFloat(double number, uint8_t digits) { 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()); + } +} diff --git a/src/protocols/RTTY/RTTY.h b/src/protocols/RTTY/RTTY.h index 5c22568c..1e6120c1 100644 --- a/src/protocols/RTTY/RTTY.h +++ b/src/protocols/RTTY/RTTY.h @@ -3,6 +3,7 @@ #include "../../TypeDef.h" #include "../PhysicalLayer/PhysicalLayer.h" +#include "../AFSK/AFSK.h" #define ITA2_FIGS 0x1B #define ITA2_LTRS 0x1F @@ -84,18 +85,25 @@ class ITA2String { class RTTYClient { public: /*! - \brief Default constructor. + \brief Constructor for 2-FSK mode. \param phy Pointer to the wireless module providing PhysicalLayer communication. */ RTTYClient(PhysicalLayer* phy); + /*! + \brief Constructor for AFSK mode. + + \param audio Pointer to the AFSK instance providing audio. + */ + RTTYClient(AFSKClient* audio); + // basic methods /*! \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. @@ -147,10 +155,11 @@ class RTTYClient { private: #endif PhysicalLayer* _phy; + AFSKClient* _audio; uint8_t _encoding; - uint32_t _base; - uint32_t _shift; + uint32_t _base, _baseHz; + uint32_t _shift, _shiftHz; uint32_t _bitDuration; uint8_t _dataBits; uint8_t _stopBits; @@ -160,6 +169,9 @@ class RTTYClient { size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); + + int16_t transmitDirect(uint32_t freq = 0, uint32_t freqHz = 0); + int16_t standby(); }; #endif