diff --git a/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino new file mode 100644 index 00000000..62b9f7fe --- /dev/null +++ b/examples/Morse/Morse_Receive_AM/Morse_Receive_AM.ino @@ -0,0 +1,112 @@ +/* + RadioLib SX127x Morse Receive AM Example + + This example receives Morse code message using + SX1278's FSK modem. The signal is expected to be + modulated as OOK, to be demodulated in AM mode. + + Other modules that can be used for Morse Code + with AFSK modulation: + - 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 + +// SX1278 has the following connections: +// NSS pin: 10 +// DIO0 pin: 2 +// RESET pin: 9 +// DIO1 pin: 3 +SX1278 radio = new Module(10, 2, 9, 3); + +// or using RadioShield +// https://github.com/jgromes/RadioShield +//SX1278 radio = RadioShield.ModuleA; + +// create AFSK client instance using the FSK module +// pin 5 is connected to SX1278 DIO2 +AFSKClient audio(&radio, 5); + +// create Morse client instance using the AFSK instance +MorseClient morse(&audio); + +void setup() { + Serial.begin(9600); + + // initialize SX1278 with default settings + Serial.print(F("[SX1278] Initializing ... ")); + int state = radio.beginFSK(); + if (state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true); + } + + // when using one of the non-LoRa modules for Morse code + // (RF69, CC1101, Si4432 etc.), use the basic begin() method + // int state = radio.begin(); + + // initialize Morse client + Serial.print(F("[Morse] Initializing ... ")); + // AFSK tone frequency: 400 Hz + // speed: 20 words per minute + state = morse.begin(400); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // after that, set mode to OOK to emulate AM modulation + Serial.print(F("[SX1278] Switching to OOK ... ")); + state = radio.setOOK(true); + if(state == RADIOLIB_ERR_NONE) { + Serial.println(F("success!")); + } else { + Serial.print(F("failed, code ")); + Serial.println(state); + while(true); + } + + // start direct mode reception + radio.receiveDirect(); +} + +// save symbol and length between loops +byte symbol = 0; +byte len = 0; + +void loop() { + // try to read a new symbol + int state = morse.read(&symbol, &len); + + // check if we have a complete character + if(state == RADIOLIB_MORSE_CHAR_COMPLETE) { + // decode and print + Serial.print(MorseClient::decode(symbol, len)); + + // reset the symbol buffer + symbol = 0; + len = 0; + + } else if(state == RADIOLIB_MORSE_WORD_COMPLETE) { + // inter-word space, interpret that as a new line + Serial.println(); + + } +} diff --git a/keywords.txt b/keywords.txt index 30d7eb7e..8c3a0a33 100644 --- a/keywords.txt +++ b/keywords.txt @@ -254,6 +254,10 @@ RADIOLIB_ENCODING_WHITENING LITERAL1 RADIOLIB_BUILTIN_MODULE LITERAL1 +RADIOLIB_MORSE_INTER_SYMBOL LITERAL1 +RADIOLIB_MORSE_CHAR_COMPLETE LITERAL1 +RADIOLIB_MORSE_WORD_COMPLETE LITERAL1 + RADIOLIB_ERR_NONE LITERAL1 RADIOLIB_ERR_UNKNOWN LITERAL1 diff --git a/src/BuildOpt.h b/src/BuildOpt.h index e58f93df..d122254c 100644 --- a/src/BuildOpt.h +++ b/src/BuildOpt.h @@ -59,7 +59,7 @@ // Arduino API callbacks // the following are signatures of Arduino API functions of the custom platform // for example, pinMode on Arduino Uno is defined as void pinMode(uint8_t pin, uint8_t mode) - // all fo the callbacks below are taken from Arduino Uno + // all of the callbacks below are taken from Arduino Uno #define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, uint8_t mode) #define RADIOLIB_CB_ARGS_DIGITAL_WRITE (void, digitalWrite, uint8_t pin, uint8_t value) #define RADIOLIB_CB_ARGS_DIGITAL_READ (int, digitalRead, uint8_t pin) @@ -72,6 +72,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -137,6 +138,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -171,6 +173,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -209,6 +212,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -246,6 +250,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t us) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -283,6 +288,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -317,6 +323,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, pin_size_t pin, uint8_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -352,6 +359,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t usec) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -386,6 +394,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t usec) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -420,6 +429,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32_t dwUs) #define RADIOLIB_CB_ARGS_MILLIS (uint64_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint64_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t pin, uint32_t state, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -454,6 +464,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -491,6 +502,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -529,6 +541,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -567,6 +580,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -601,6 +615,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint32 us) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint32_t ulPin, uint32_t ulState, uint32_t ulTimeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -635,6 +650,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -673,6 +689,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, pin_size_t pin, PinStatus state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -706,6 +723,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, uint16 microseconds) #define RADIOLIB_CB_ARGS_MILLIS (uint32_t, millis, void) #define RADIOLIB_CB_ARGS_MICROS (uint32_t, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (uint32_t, pulseIn, uint8_t pin_name, uint8_t mode, uint32_t timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -762,6 +780,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -816,6 +835,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, long unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) @@ -851,6 +871,7 @@ #define RADIOLIB_CB_ARGS_DELAY_MICROSECONDS (void, delayMicroseconds, unsigned int us) #define RADIOLIB_CB_ARGS_MILLIS (unsigned long, millis, void) #define RADIOLIB_CB_ARGS_MICROS (unsigned long, micros, void) + #define RADIOLIB_CB_ARGS_PULSE_IN (unsigned long, pulseIn, uint8_t pin, uint8_t state, unsigned long timeout) #define RADIOLIB_CB_ARGS_SPI_BEGIN (void, SPIbegin, void) #define RADIOLIB_CB_ARGS_SPI_BEGIN_TRANSACTION (void, SPIbeginTransaction, void) #define RADIOLIB_CB_ARGS_SPI_TRANSFER (uint8_t, SPItransfer, uint8_t b) diff --git a/src/Module.cpp b/src/Module.cpp index eb20ff7b..bc09de8f 100644 --- a/src/Module.cpp +++ b/src/Module.cpp @@ -373,6 +373,13 @@ uint32_t Module::micros() { return(cb_micros()); } +uint32_t Module::pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint32_t timeout) { + if(cb_pulseIn == nullptr) { + return(0); + } + return(cb_pulseIn(pin, state, timeout)); +} + void Module::begin() { if(cb_SPIbegin == nullptr) { return; diff --git a/src/Module.h b/src/Module.h index 93ddf159..5148ace0 100644 --- a/src/Module.h +++ b/src/Module.h @@ -333,6 +333,11 @@ class Module { */ uint32_t micros(); + /*! + \brief Arduino core pulseIn override. + */ + uint32_t pulseIn(RADIOLIB_PIN_TYPE pin, RADIOLIB_PIN_STATUS state, uint32_t timeout); + /*! \brief Arduino core SPI begin override. */ @@ -408,6 +413,7 @@ class Module { RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_DELAY_MICROSECONDS); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MILLIS); RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_MICROS); + RADIOLIB_GENERATE_CALLBACK(RADIOLIB_CB_ARGS_PULSE_IN); #if defined(RADIOLIB_BUILD_ARDUINO) RADIOLIB_GENERATE_CALLBACK_SPI(RADIOLIB_CB_ARGS_SPI_BEGIN); diff --git a/src/protocols/Morse/Morse.cpp b/src/protocols/Morse/Morse.cpp index d3dd40f6..65f1a11d 100644 --- a/src/protocols/Morse/Morse.cpp +++ b/src/protocols/Morse/Morse.cpp @@ -20,8 +20,14 @@ int16_t MorseClient::begin(float base, uint8_t speed) { _baseHz = base; _base = (base * 1000000.0) / _phy->getFreqStep(); - // calculate dot length (assumes PARIS as typical word) + // calculate tone period for decoding + _basePeriod = (1000000.0f/base)/2.0f; + + // calculate symbol lengths (assumes PARIS as typical word) _dotLength = 1200 / speed; + _dashLength = 3*_dotLength; + _letterSpace = 3*_dotLength; + _wordSpace = 4*_dotLength; // configure for direct mode return(_phy->startDirect()); @@ -31,6 +37,78 @@ size_t MorseClient::startSignal() { return(MorseClient::write('_')); } +char MorseClient::decode(uint8_t symbol, uint8_t len) { + // add the guard bit + symbol |= (RADIOLIB_MORSE_DASH << len); + + // iterate over the table + for(uint8_t i = 0; i < sizeof(MorseTable); i++) { + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[i]); + if(code == symbol) { + // match, return the index + ASCII offset + return((char)(i + RADIOLIB_MORSE_ASCII_OFFSET)); + } + } + + // nothing found + return(RADIOLIB_MORSE_UNSUPORTED); +} + +#if !defined(RADIOLIB_EXCLUDE_AFSK) +int MorseClient::read(byte* symbol, byte* len, float low, float high) { + Module* mod = _phy->getMod(); + + // measure pulse duration in us + uint32_t duration = mod->pulseIn(_audio->_pin, LOW, 4*_basePeriod); + + // decide if this is a signal, or pause + if((duration > low*_basePeriod) && (duration < high*_basePeriod)) { + // this is a signal + signalCounter++; + } else if(duration == 0) { + // this is a pause + pauseCounter++; + } + + // update everything + if((pauseCounter > 0) && (signalCounter == 1)) { + // start of dot or dash + pauseCounter = 0; + signalStart = mod->millis(); + uint32_t pauseLen = mod->millis() - pauseStart; + + if((pauseLen >= low*(float)_letterSpace) && (pauseLen <= high*(float)_letterSpace)) { + return(RADIOLIB_MORSE_CHAR_COMPLETE); + } else if(pauseLen > _wordSpace) { + RADIOLIB_DEBUG_PRINTLN("\n"); + return(RADIOLIB_MORSE_WORD_COMPLETE); + } + + } else if((signalCounter > 0) && (pauseCounter == 1)) { + // end of dot or dash + signalCounter = 0; + pauseStart = mod->millis(); + uint32_t signalLen = mod->millis() - signalStart; + + if((signalLen >= low*(float)_dotLength) && (signalLen <= high*(float)_dotLength)) { + RADIOLIB_DEBUG_PRINT('.'); + (*symbol) |= (RADIOLIB_MORSE_DOT << (*len)); + (*len)++; + } else if((signalLen >= low*(float)_dashLength) && (signalLen <= high*(float)_dashLength)) { + RADIOLIB_DEBUG_PRINT('-'); + (*symbol) |= (RADIOLIB_MORSE_DASH << (*len)); + (*len)++; + } else { + RADIOLIB_DEBUG_PRINT(""); + } + } + + return(RADIOLIB_MORSE_INTER_SYMBOL); +} +#endif + size_t MorseClient::write(const char* str) { if(str == NULL) { return(0); @@ -59,12 +137,12 @@ size_t MorseClient::write(uint8_t b) { if(b == ' ') { RADIOLIB_DEBUG_PRINTLN(F("space")); standby(); - mod->delay(4 * _dotLength); + mod->delay(_wordSpace); return(1); } // get morse code from lookup table - uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - 32)]); + uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - RADIOLIB_MORSE_ASCII_OFFSET)]); // check unsupported characters if(code == RADIOLIB_MORSE_UNSUPORTED) { @@ -78,7 +156,7 @@ size_t MorseClient::write(uint8_t b) { if (code & RADIOLIB_MORSE_DASH) { RADIOLIB_DEBUG_PRINT('-'); transmitDirect(_base, _baseHz); - mod->delay(3 * _dotLength); + mod->delay(_dashLength); } else { RADIOLIB_DEBUG_PRINT('.'); transmitDirect(_base, _baseHz); @@ -95,7 +173,7 @@ size_t MorseClient::write(uint8_t b) { // letter space standby(); - mod->delay(2 * _dotLength); + mod->delay(_letterSpace - _dotLength); RADIOLIB_DEBUG_PRINTLN(); return(1); diff --git a/src/protocols/Morse/Morse.h b/src/protocols/Morse/Morse.h index 66ead3b9..bfa72b52 100644 --- a/src/protocols/Morse/Morse.h +++ b/src/protocols/Morse/Morse.h @@ -9,6 +9,10 @@ #define RADIOLIB_MORSE_DASH 0b1 #define RADIOLIB_MORSE_GUARDBIT 0b1 #define RADIOLIB_MORSE_UNSUPORTED 0xFF +#define RADIOLIB_MORSE_ASCII_OFFSET 32 +#define RADIOLIB_MORSE_INTER_SYMBOL 0x00 +#define RADIOLIB_MORSE_CHAR_COMPLETE 0x01 +#define RADIOLIB_MORSE_WORD_COMPLETE 0x02 // Morse character table: - using codes defined in ITU-R M.1677-1 // - Morse code representation is saved LSb first, using additional bit as guard @@ -124,6 +128,34 @@ class MorseClient { */ size_t startSignal(); + /*! + \brief Decode Morse symbol to ASCII. + + \param symbol Morse code symbol, respresented as outlined in MorseTable. + + \param len Symbol length (number of dots and dashes). + + \returns ASCII character matching the symbol, or 0xFF if no match is found. + */ + static char decode(uint8_t symbol, uint8_t len); + + /*! + \brief Read Morse tone on input pin. + + \param symbol Pointer to the symbol buffer. + + \param len Pointer to the length counter. + + \param low Low threshold for decision limit (dot length, pause length etc.), defaults to 0.75. + + \param high High threshold for decision limit (dot length, pause length etc.), defaults to 1.25. + + \returns 0 if not enough symbols were decoded, 1 if inter-character space was detected, 2 if inter-word space was detected. + */ + #if !defined(RADIOLIB_EXCLUDE_AFSK) + int read(byte* symbol, byte* len, float low = 0.75f, float high = 1.25f); + #endif + size_t write(const char* str); size_t write(uint8_t* buff, size_t len); size_t write(uint8_t b); @@ -160,7 +192,17 @@ class MorseClient { #endif uint32_t _base = 0, _baseHz = 0; + float _basePeriod = 0.0f; uint16_t _dotLength = 0; + uint16_t _dashLength = 0; + uint16_t _letterSpace = 0; + uint16_t _wordSpace = 0; + + // variables to keep decoding state + uint32_t signalCounter = 0; + uint32_t signalStart = 0; + uint32_t pauseCounter = 0; + uint32_t pauseStart = 0; size_t printNumber(unsigned long, uint8_t); size_t printFloat(double, uint8_t); diff --git a/src/protocols/PhysicalLayer/PhysicalLayer.cpp b/src/protocols/PhysicalLayer/PhysicalLayer.cpp index 98c8778c..f0e62cd0 100644 --- a/src/protocols/PhysicalLayer/PhysicalLayer.cpp +++ b/src/protocols/PhysicalLayer/PhysicalLayer.cpp @@ -248,5 +248,5 @@ void PhysicalLayer::updateDirectBuffer(uint8_t bit) { } int16_t PhysicalLayer::setDIOMapping(RADIOLIB_PIN_TYPE pin, uint8_t value) { - return(RADIOLIB_ERR_UNSUPPORTED); + return(RADIOLIB_ERR_UNSUPPORTED); }