127 lines
2.8 KiB
C++
127 lines
2.8 KiB
C++
#include "RTTY.h"
|
|
|
|
#include <math.h>
|
|
|
|
#if !defined(RADIOLIB_EXCLUDE_RTTY)
|
|
|
|
RTTYClient::RTTYClient(PhysicalLayer* phy) {
|
|
phyLayer = phy;
|
|
lineFeed = "\r\n";
|
|
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
|
audioClient = nullptr;
|
|
#endif
|
|
}
|
|
|
|
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
|
RTTYClient::RTTYClient(AFSKClient* audio) {
|
|
phyLayer = audio->phyLayer;
|
|
lineFeed = "\r\n";
|
|
audioClient = audio;
|
|
}
|
|
#endif
|
|
|
|
int16_t RTTYClient::begin(float base, uint32_t shift, uint16_t rate, uint8_t enc, uint8_t stopBits) {
|
|
// save configuration
|
|
RadioLibPrint::encoding = enc;
|
|
stopBitsNum = stopBits;
|
|
baseFreqHz = base;
|
|
shiftFreqHz = shift;
|
|
|
|
// calculate duration of 1 bit
|
|
bitDuration = (uint32_t)1000000/rate;
|
|
|
|
// calculate module carrier frequency resolution
|
|
uint32_t step = round(phyLayer->getFreqStep());
|
|
|
|
// check minimum shift value
|
|
if(shift < step / 2) {
|
|
return(RADIOLIB_ERR_INVALID_RTTY_SHIFT);
|
|
}
|
|
|
|
// round shift to multiples of frequency step size
|
|
if(shift % step < (step / 2)) {
|
|
shiftFreq = shift / step;
|
|
} else {
|
|
shiftFreq = (shift / step) + 1;
|
|
}
|
|
|
|
// calculate 24-bit frequency
|
|
baseFreq = (base * 1000000.0) / phyLayer->getFreqStep();
|
|
|
|
// configure for direct mode
|
|
return(phyLayer->startDirect());
|
|
}
|
|
|
|
void RTTYClient::idle() {
|
|
mark();
|
|
}
|
|
|
|
size_t RTTYClient::write(uint8_t b) {
|
|
uint8_t dataBitsNum = 0;
|
|
switch(RadioLibPrint::encoding) {
|
|
case RADIOLIB_ASCII:
|
|
dataBitsNum = 7;
|
|
break;
|
|
case RADIOLIB_ASCII_EXTENDED:
|
|
dataBitsNum = 8;
|
|
break;
|
|
case RADIOLIB_ITA2:
|
|
dataBitsNum = 5;
|
|
break;
|
|
default:
|
|
return(0);
|
|
}
|
|
space();
|
|
|
|
uint16_t maxDataMask = 0x01 << (dataBitsNum - 1);
|
|
for(uint16_t mask = 0x01; mask <= maxDataMask; mask <<= 1) {
|
|
if(b & mask) {
|
|
mark();
|
|
} else {
|
|
space();
|
|
}
|
|
}
|
|
|
|
for(uint8_t i = 0; i < stopBitsNum; i++) {
|
|
mark();
|
|
}
|
|
|
|
return(1);
|
|
}
|
|
|
|
void RTTYClient::mark() {
|
|
Module* mod = phyLayer->getMod();
|
|
uint32_t start = mod->hal->micros();
|
|
transmitDirect(baseFreq + shiftFreq, baseFreqHz + shiftFreqHz);
|
|
mod->waitForMicroseconds(start, bitDuration);
|
|
}
|
|
|
|
void RTTYClient::space() {
|
|
Module* mod = phyLayer->getMod();
|
|
uint32_t start = mod->hal->micros();
|
|
transmitDirect(baseFreq, baseFreqHz);
|
|
mod->waitForMicroseconds(start, bitDuration);
|
|
}
|
|
|
|
int16_t RTTYClient::transmitDirect(uint32_t freq, uint32_t freqHz) {
|
|
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
|
if(audioClient != nullptr) {
|
|
return(audioClient->tone(freqHz));
|
|
}
|
|
#endif
|
|
return(phyLayer->transmitDirect(freq));
|
|
}
|
|
|
|
int16_t RTTYClient::standby() {
|
|
// ensure everything is stopped in interrupt timing mode
|
|
Module* mod = phyLayer->getMod();
|
|
mod->waitForMicroseconds(0, 0);
|
|
#if !defined(RADIOLIB_EXCLUDE_AFSK)
|
|
if(audioClient != nullptr) {
|
|
return(audioClient->noTone());
|
|
}
|
|
#endif
|
|
return(phyLayer->standby());
|
|
}
|
|
|
|
#endif
|