diff --git a/examples/AFSK/AFSK_No_Tone/AFSK_No_Tone.ino b/examples/AFSK/AFSK_No_Tone/AFSK_No_Tone.ino new file mode 100644 index 00000000..1635455e --- /dev/null +++ b/examples/AFSK/AFSK_No_Tone/AFSK_No_Tone.ino @@ -0,0 +1,87 @@ +/* + RadioLib AFSK Example + + This example shows hot to send audio FSK tones + using SX1278's FSK modem, on platforms that do + not support the tone() function. + + Other modules that can be used for AFSK: + - SX127x/RFM9x + - RF69 + - SX1231 + - CC1101 + - 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(5, 2, 9, 3); + +// create AFSK client instance using the FSK module +// enable tone emulation by setting the pin to +// "not connected" +AFSKClient audio(&radio, RADIOLIB_NC); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + + // when using one of the non-LoRa modules for AFSK + // (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 AFSK client + Serial.print(F("[AFSK] Initializing ... ")); + state = audio.begin(); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } +} + +void loop() { + // AFSKClient can be used to transmit tones, + // same as Arduino tone() function + + // 400 Hz tone + Serial.print(F("[AFSK] 400 Hz tone ... ")); + const size_t len = 64; + uint8_t bits[len] = { 0 }; + for(size_t i = 0; i < len; i++) { + bits[i] = 0xF0; + } + audio.emulateTone(400, bits, len); + Serial.println(F("done!")); + delay(1000); + + // AFSKClient can also be used to transmit HAM-friendly + // RTTY, Morse code, Hellschreiber, SSTV and AX.25. + // Details on how to use AFSK are in the example + // folders for each of the above modes. +} diff --git a/src/protocols/AFSK/AFSK.cpp b/src/protocols/AFSK/AFSK.cpp index 29c00448..b44b8057 100644 --- a/src/protocols/AFSK/AFSK.cpp +++ b/src/protocols/AFSK/AFSK.cpp @@ -6,6 +6,19 @@ AFSKClient::AFSKClient(PhysicalLayer* phy, RADIOLIB_PIN_TYPE pin): _pin(pin) { } int16_t AFSKClient::begin() { + if(_pin == RADIOLIB_NC) { + // set encoding to NRZ + int16_t state = _phy->setEncoding(RADIOLIB_ENCODING_NRZ); + RADIOLIB_ASSERT(state); + + // disable preamble + state = _phy->setPreambleLength(0); + RADIOLIB_ASSERT(state); + + // disable CRC + state = _phy->setCrcFiltering(false); + return(state); + } return(_phy->startDirect()); } @@ -34,4 +47,29 @@ int16_t AFSKClient::noTone(bool keepOn) { return(_phy->standby()); } +int16_t AFSKClient::tones(float baseFreq, uint8_t* bits, size_t len) { + // set fixed packet length mode + int16_t state = _phy->fixedPacketLengthMode(len); + RADIOLIB_ASSERT(state); + + float br = baseFreq; + if((br < 1200)) { + if(br < 1200/8) { + // this is too low to achieve by a single octet + // FIXME - if tones lower than 150 Hz are needed, multiple octets must be used + return(RADIOLIB_ERR_INVALID_FREQUENCY); + } + // this tone frequency is lower than what most modules can do + // but we can easily emulate tones in this range + br *= 8.0; + } + + // set the base frequency + state = _phy->setBitRate(br / 1000.0); + RADIOLIB_ASSERT(state); + + // transmit + return(_phy->transmit(bits, len)); +} + #endif diff --git a/src/protocols/AFSK/AFSK.h b/src/protocols/AFSK/AFSK.h index 72b45471..ce651d63 100644 --- a/src/protocols/AFSK/AFSK.h +++ b/src/protocols/AFSK/AFSK.h @@ -52,6 +52,8 @@ class AFSKClient { */ int16_t noTone(bool keepOn = false); + int16_t emulateTone(float baseFreq, uint8_t* bits, size_t len); + #if !defined(RADIOLIB_GODMODE) private: #endif diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.h b/src/protocols/PhysicalLayer/PhysicalLayer.h index 425dddc7..97245e22 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.h +++ b/src/protocols/PhysicalLayer/PhysicalLayer.h @@ -302,6 +302,11 @@ class PhysicalLayer { virtual Module* getMod() = 0; + virtual int16_t setPreambleLength(uint16_t preambleLength) = 0; + virtual int16_t setCrcFiltering(bool crcOn) = 0; + virtual int16_t fixedPacketLengthMode(uint8_t preambleLength) = 0; + virtual int16_t setBitRate(float br) = 0; + protected: void updateDirectBuffer(uint8_t bit);