187 lines
4.9 KiB
C++
187 lines
4.9 KiB
C++
#include "Morse.h"
|
|
|
|
#include <ctype.h>
|
|
|
|
#if !RADIOLIB_EXCLUDE_MORSE
|
|
|
|
MorseClient::MorseClient(PhysicalLayer* phy) {
|
|
phyLayer = phy;
|
|
lineFeed = "^";
|
|
#if !RADIOLIB_EXCLUDE_AFSK
|
|
audioClient = nullptr;
|
|
#endif
|
|
}
|
|
|
|
#if !RADIOLIB_EXCLUDE_AFSK
|
|
MorseClient::MorseClient(AFSKClient* audio) {
|
|
phyLayer = audio->phyLayer;
|
|
lineFeed = "^";
|
|
audioClient = audio;
|
|
}
|
|
#endif
|
|
|
|
int16_t MorseClient::begin(float base, uint8_t speed) {
|
|
// calculate 24-bit frequency
|
|
baseFreqHz = base;
|
|
baseFreq = (base * 1000000.0) / phyLayer->getFreqStep();
|
|
|
|
// 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(phyLayer->startDirect());
|
|
}
|
|
|
|
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_UNSUPPORTED);
|
|
}
|
|
|
|
#if !RADIOLIB_EXCLUDE_AFSK
|
|
int MorseClient::read(uint8_t* symbol, uint8_t* len, float low, float high) {
|
|
Module* mod = phyLayer->getMod();
|
|
|
|
// measure pulse duration in us
|
|
uint32_t duration = mod->hal->pulseIn(audioClient->outPin, mod->hal->GpioLevelLow, 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->hal->millis();
|
|
uint32_t pauseLen = mod->hal->millis() - pauseStart;
|
|
|
|
if((pauseLen >= low*(float)letterSpace) && (pauseLen <= high*(float)letterSpace)) {
|
|
return(RADIOLIB_MORSE_CHAR_COMPLETE);
|
|
} else if(pauseLen > wordSpace) {
|
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("\n<space>");
|
|
return(RADIOLIB_MORSE_WORD_COMPLETE);
|
|
}
|
|
|
|
} else if((signalCounter > 0) && (pauseCounter == 1)) {
|
|
// end of dot or dash
|
|
signalCounter = 0;
|
|
pauseStart = mod->hal->millis();
|
|
uint32_t signalLen = mod->hal->millis() - signalStart;
|
|
|
|
if((signalLen >= low*(float)dotLength) && (signalLen <= high*(float)dotLength)) {
|
|
RADIOLIB_DEBUG_PROTOCOL_PRINT(".");
|
|
(*symbol) |= (RADIOLIB_MORSE_DOT << (*len));
|
|
(*len)++;
|
|
} else if((signalLen >= low*(float)dashLength) && (signalLen <= high*(float)dashLength)) {
|
|
RADIOLIB_DEBUG_PROTOCOL_PRINT("-");
|
|
(*symbol) |= (RADIOLIB_MORSE_DASH << (*len));
|
|
(*len)++;
|
|
} else {
|
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("<len=%lums>", (long unsigned int)signalLen);
|
|
}
|
|
}
|
|
|
|
return(RADIOLIB_MORSE_INTER_SYMBOL);
|
|
}
|
|
#endif
|
|
|
|
size_t MorseClient::write(uint8_t b) {
|
|
Module* mod = phyLayer->getMod();
|
|
|
|
// check unprintable ASCII characters and boundaries
|
|
if((b < ' ') || (b == 0x60) || (b > 'z')) {
|
|
return(0);
|
|
}
|
|
|
|
// inter-word pause (space)
|
|
if(b == ' ') {
|
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("space");
|
|
standby();
|
|
mod->waitForMicroseconds(mod->hal->micros(), wordSpace*1000);
|
|
return(1);
|
|
}
|
|
|
|
// get morse code from lookup table
|
|
uint8_t code = RADIOLIB_NONVOLATILE_READ_BYTE(&MorseTable[(uint8_t)(toupper(b) - RADIOLIB_MORSE_ASCII_OFFSET)]);
|
|
|
|
// check unsupported characters
|
|
if(code == RADIOLIB_MORSE_UNSUPPORTED) {
|
|
return(0);
|
|
}
|
|
|
|
// iterate through codeword until guard bit is reached
|
|
while(code > RADIOLIB_MORSE_GUARDBIT) {
|
|
|
|
// send dot or dash
|
|
if (code & RADIOLIB_MORSE_DASH) {
|
|
RADIOLIB_DEBUG_PROTOCOL_PRINT("-");
|
|
transmitDirect(baseFreq, baseFreqHz);
|
|
mod->waitForMicroseconds(mod->hal->micros(), dashLength*1000);
|
|
} else {
|
|
RADIOLIB_DEBUG_PROTOCOL_PRINT(".");
|
|
transmitDirect(baseFreq, baseFreqHz);
|
|
mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000);
|
|
}
|
|
|
|
// symbol space
|
|
standby();
|
|
mod->waitForMicroseconds(mod->hal->micros(), dotLength*1000);
|
|
|
|
// move onto the next bit
|
|
code >>= 1;
|
|
}
|
|
|
|
// letter space
|
|
standby();
|
|
mod->waitForMicroseconds(mod->hal->micros(), letterSpace*1000 - dotLength*1000);
|
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN();
|
|
|
|
return(1);
|
|
}
|
|
|
|
int16_t MorseClient::transmitDirect(uint32_t freq, uint32_t freqHz) {
|
|
#if !RADIOLIB_EXCLUDE_AFSK
|
|
if(audioClient != nullptr) {
|
|
return(audioClient->tone(freqHz));
|
|
}
|
|
#endif
|
|
return(phyLayer->transmitDirect(freq));
|
|
}
|
|
|
|
int16_t MorseClient::standby() {
|
|
#if !RADIOLIB_EXCLUDE_AFSK
|
|
if(audioClient != nullptr) {
|
|
return(audioClient->noTone(true));
|
|
}
|
|
#endif
|
|
return(phyLayer->standby());
|
|
}
|
|
|
|
#endif
|