[SX126x] Added RTTY support

This commit is contained in:
jgromes 2019-05-15 17:20:20 +02:00
parent cfdd921984
commit 606e841aca
5 changed files with 309 additions and 13 deletions

View file

@ -9,6 +9,7 @@
- RF69
- SX1231
- CC1101
- SX1262/68
*/
// include the library
@ -48,6 +49,7 @@ void setup() {
// SX127x - 61 Hz
// RF69 - 61 Hz
// CC1101 - 397 Hz
// SX126x - 1 Hz
Serial.print(F("[RTTY] Initializing ... "));
// low ("space") frequency: 434.0 MHz
// frequency shift: 183 Hz

View file

@ -31,6 +31,33 @@ int16_t SX1262::begin(float freq, float bw, uint8_t sf, uint8_t cr, uint16_t syn
return(state);
}
int16_t SX1262::beginFSK(float freq, float br, float freqDev, float rxBw, int8_t power, float currentLimit, uint16_t preambleLength, float dataShaping) {
// execute common part
int16_t state = SX126x::beginFSK(br, freqDev, rxBw, preambleLength, dataShaping);
if(state != ERR_NONE) {
return(state);
}
// configure publicly accessible settings
state = setFrequency(freq);
if(state != ERR_NONE) {
return(state);
}
state = setOutputPower(power);
if(state != ERR_NONE) {
return(state);
}
// OCP must be configured after PA
state = SX126x::setCurrentLimit(currentLimit);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
int16_t SX1262::setFrequency(float freq) {
// check frequency range
if((freq < 150.0) || (freq > 960.0)) {

View file

@ -16,6 +16,7 @@ class SX1262: public SX126x {
// basic methods
int16_t begin(float freq = 434.0, float bw = 125.0, uint8_t sf = 9, uint8_t cr = 7, uint16_t syncWord = SX126X_SYNC_WORD_PRIVATE, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8);
int16_t beginFSK(float freq = 434.0, float br = 48.0, float freqDev = 50.0, float rxBw = 117.3, int8_t power = 14, float currentLimit = 60.0, uint16_t preambleLength = 8, float dataShaping = 0.5);
// configuration methods
int16_t setFrequency(float freq);

View file

@ -13,7 +13,7 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
_bwKhz = bw;
_sf = sf;
// initialize dummy configuration variables
// initialize configuration variables (will be overwritten during public settings configuration)
_bw = SX126X_LORA_BW_125_0;
_cr = SX126X_LORA_CR_4_7;
_ldro = 0x00;
@ -59,9 +59,69 @@ int16_t SX126x::begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint1
return(state);
}
int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float dataShaping) {
// set module properties
_mod->init(USE_SPI, INT_BOTH);
pinMode(_mod->getRx(), INPUT);
// initialize configuration variables (will be overwritten during public settings configuration)
_br = 21333;
_freqDev = 52429;
_rxBw = SX126X_GFSK_RX_BW_117_3;
_pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5;
_crcTypeFSK = SX126X_GFSK_CRC_1_BYTE;
_preambleLengthFSK = preambleLength;
// get status and errors
getStatus();
getDeviceErrors();
// set mode to standby
standby();
// configure settings not accessible by API
configFSK();
// configure publicly accessible settings
int16_t state = setBitRate(br);
if(state != ERR_NONE) {
return(state);
}
state = setFrequencyDeviation(freqDev);
if(state != ERR_NONE) {
return(state);
}
state = setRxBandwidth(rxBw);
if(state != ERR_NONE) {
return(state);
}
state = setDataShaping(dataShaping);
if(state != ERR_NONE) {
return(state);
}
state = setPreambleLength(preambleLength);
if(state != ERR_NONE) {
return(state);
}
// set default sync word 0x2D01 - not a beginFSK attribute
uint8_t sync[] = {0x2D, 0x01};
_syncWordLength = 2;
state = setSyncWord(sync, _syncWordLength);
if(state != ERR_NONE) {
return(state);
}
return(state);
}
int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = standby();
standby();
// check packet length
if(len >= 256) {
@ -74,7 +134,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
uint8_t modem = getPacketType();
if(modem == SX126X_PACKET_TYPE_LORA) {
// calculate timeout (150% of expected time-on-air)
float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
float symbolLength = (float)((uint32_t)(1) << _sf) / (float)_bwKhz;
float sfCoeff1 = 4.25;
float sfCoeff2 = 8.0;
if(_sf == 5 || _sf == 6) {
@ -141,7 +201,7 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
int16_t SX126x::receive(uint8_t* data, size_t len) {
// set mode to standby
int16_t state = standby();
standby();
uint32_t timeout = 0;
@ -340,9 +400,164 @@ int16_t SX126x::setCurrentLimit(float currentLimit) {
}
int16_t SX126x::setPreambleLength(uint16_t preambleLength) {
// update packet parameters
uint8_t modem = getPacketType();
if(modem == SX126X_PACKET_TYPE_LORA) {
_preambleLength = preambleLength;
setPacketParams(_preambleLength, _crcType);
return(ERR_NONE);
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
_preambleLengthFSK = preambleLength;
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength);
return(ERR_NONE);
}
return(ERR_UNKNOWN);
}
int16_t SX126x::setFrequencyDeviation(float freqDev) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// check alowed frequency deviation values
if(!(freqDev <= 200.0)) {
return(ERR_INVALID_FREQUENCY_DEVIATION);
}
// calculate raw frequency deviation value
_freqDev = (uint32_t)((freqDev * 1000.0) / ((SX126X_CRYSTAL_FREQ * 1000000.0) / (float)((uint32_t)(1) << 25)));
// update modulation parameters
setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev);
return(ERR_NONE);
}
int16_t SX126x::setBitRate(float br) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// check alowed bit rate values
if(!((br >= 0.6) && (br <= 300.0))) {
return(ERR_INVALID_BIT_RATE);
}
// calculate raw bit rate value
_br = (uint32_t)((SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0));
// update modulation parameters
setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev);
return(ERR_NONE);
}
int16_t SX126x::setRxBandwidth(float rxBw) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// check alowed receiver bandwidth values
if(abs(rxBw - 4.8) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_4_8;
} else if(abs(rxBw - 5.8) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_5_8;
} else if(abs(rxBw - 7.3) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_7_3;
} else if(abs(rxBw - 9.7) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_9_7;
} else if(abs(rxBw - 11.7) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_11_7;
} else if(abs(rxBw - 14.6) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_14_6;
} else if(abs(rxBw - 19.5) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_19_5;
} else if(abs(rxBw - 23.4) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_23_4;
} else if(abs(rxBw - 29.3) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_29_3;
} else if(abs(rxBw - 39.0) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_39_0;
} else if(abs(rxBw - 46.9) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_46_9;
} else if(abs(rxBw - 58.6) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_58_6;
} else if(abs(rxBw - 78.2) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_78_2;
} else if(abs(rxBw - 93.8) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_93_8;
} else if(abs(rxBw - 117.3) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_117_3;
} else if(abs(rxBw - 156.2) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_156_2;
} else if(abs(rxBw - 187.2) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_187_2;
} else if(abs(rxBw - 234.3) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_234_3;
} else if(abs(rxBw - 312.0) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_312_0;
} else if(abs(rxBw - 373.6) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_373_6;
} else if(abs(rxBw - 467.0) <= 0.001) {
_rxBw = SX126X_GFSK_RX_BW_467_0;
} else {
return(ERR_INVALID_RX_BANDWIDTH);
}
// update modulation parameters
setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev);
return(ERR_NONE);
}
int16_t SX126x::setDataShaping(float sh) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// check allowed values
if(abs(sh - 0.0) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_NONE;
} else if(abs(sh - 0.3) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_GAUSS_0_3;
} else if(abs(sh - 0.5) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5;
} else if(abs(sh - 0.7) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_GAUSS_0_7;
} else if(abs(sh - 1.0) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_GAUSS_1;
} else {
return(ERR_INVALID_DATA_SHAPING);
}
// update modulation parameters
setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev);
return(ERR_NONE);
}
int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// check sync word Length
if(len > 8) {
return(ERR_INVALID_SYNC_WORD);
}
// write sync word
writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, len);
// update packet parameters
_syncWordLength = len;
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength);
return(ERR_NONE);
}
@ -350,11 +565,6 @@ float SX126x::getDataRate() {
return(_dataRate);
}
int16_t SX126x::setFrequencyDeviation(float freqDev) {
return(ERR_NONE);
}
float SX126x::getRSSI() {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
@ -477,11 +687,25 @@ void SX126x::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldr
SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 4);
}
void SX126x::setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev) {
uint8_t data[8] = {(uint8_t)((br >> 16) & 0xFF), (uint8_t)((br >> 8) & 0xFF), (uint8_t)(br & 0xFF),
pulseShape, rxBw,
(uint8_t)((freqDev >> 16) & 0xFF), (uint8_t)((freqDev >> 8) & 0xFF), (uint8_t)(freqDev & 0xFF)};
SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 8);
}
void SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength, uint8_t headerType, uint8_t invertIQ) {
uint8_t data[6] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF), headerType, payloadLength, crcType, invertIQ};
SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 6);
}
void SX126x::setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t payloadLength, uint8_t packetType, uint8_t addrComp, uint8_t preambleDetectorLength, uint8_t whitening) {
uint8_t data[9] = {(uint8_t)((preambleLength >> 8) & 0xFF), (uint8_t)(preambleLength & 0xFF),
preambleDetectorLength, syncWordLength, addrComp,
packetType, payloadLength, crcType, whitening};
SPIwriteCommand(SX126X_CMD_SET_MODULATION_PARAMS, data, 9);
}
void SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
uint8_t data[2] = {txBaseAddress, rxBaseAddress};
SPIwriteCommand(SX126X_CMD_SET_BUFFER_BASE_ADDRESS, data, 2);
@ -582,6 +806,36 @@ int16_t SX126x::config() {
return(ERR_NONE);
}
int16_t SX126x::configFSK() {
// set DIO2 as IRQ
uint8_t* data = new uint8_t[1];
data[0] = SX126X_DIO2_AS_IRQ;
SPIwriteCommand(SX126X_DIO2_AS_RF_SWITCH, data, 1);
// set regulator mode
data[0] = SX126X_REGULATOR_DC_DC;
SPIwriteCommand(SX126X_CMD_SET_REGULATOR_MODE, data, 1);
// reset buffer base address
setBufferBaseAddress();
// set FSK mode
data[0] = SX126X_PACKET_TYPE_GFSK;
SPIwriteCommand(SX126X_CMD_SET_PACKET_TYPE, data, 1);
// set Rx/Tx fallback mode to STDBY_RC
data[0] = SX126X_RX_TX_FALLBACK_MODE_STDBY_RC;
SPIwriteCommand(SX126X_CMD_SET_RX_TX_FALLBACK_MODE, data, 1);
// clear IRQ
clearIrqStatus();
setDioIrqParams(SX126X_IRQ_NONE, SX126X_IRQ_NONE);
delete[] data;
return(ERR_NONE);
}
void SX126x::SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy) {
SX126x::SPItransfer(cmd, true, data, NULL, numBytes, waitForBusy);
}

View file

@ -219,7 +219,7 @@
#define SX126X_GFSK_RX_BW_117_3 0x0B // 7 0 117.3 kHz
#define SX126X_GFSK_RX_BW_156_2 0x1A // 7 0 156.2 kHz
#define SX126X_GFSK_RX_BW_187_2 0x12 // 7 0 187.2 kHz
#define SX126X_GFSK_RX_BW_232_3 0x0A // 7 0 232.3 kHz
#define SX126X_GFSK_RX_BW_234_3 0x0A // 7 0 234.3 kHz
#define SX126X_GFSK_RX_BW_312_0 0x19 // 7 0 312.0 kHz
#define SX126X_GFSK_RX_BW_373_6 0x11 // 7 0 373.6 kHz
#define SX126X_GFSK_RX_BW_467_0 0x09 // 7 0 467.0 kHz
@ -324,6 +324,7 @@ class SX126x: public PhysicalLayer {
// basic methods
int16_t begin(float bw, uint8_t sf, uint8_t cr, uint16_t syncWord, uint16_t preambleLength);
int16_t beginFSK(float br, float freqDev, float rxBw, uint16_t preambleLength, float dataShaping);
int16_t transmit(uint8_t* data, size_t len, uint8_t addr = 0);
int16_t receive(uint8_t* data, size_t len);
int16_t transmitDirect(uint32_t frf = 0);
@ -338,8 +339,12 @@ class SX126x: public PhysicalLayer {
int16_t setSyncWord(uint16_t syncWord);
int16_t setCurrentLimit(float currentLimit);
int16_t setPreambleLength(uint16_t preambleLength);
float getDataRate();
int16_t setFrequencyDeviation(float freqDev);
int16_t setBitRate(float br);
int16_t setRxBandwidth(float rxBw);
int16_t setDataShaping(float sh);
int16_t setSyncWord(uint8_t* syncWord, uint8_t len);
float getDataRate();
float getRSSI();
float getSNR();
@ -359,7 +364,9 @@ class SX126x: public PhysicalLayer {
uint8_t getPacketType();
void setTxParams(uint8_t power, uint8_t rampTime = SX126X_PA_RAMP_200U);
void setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, uint8_t ldro = 0xFF);
void setModulationParamsFSK(uint32_t br, uint8_t pulseShape, uint8_t rxBw, uint32_t freqDev);
void setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength = 0xFF, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_STANDARD);
void setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t payloadLength = 0xFF, uint8_t packetType = SX126X_GFSK_PACKET_VARIABLE, uint8_t addrComp = SX126X_GFSK_ADDRESS_FILT_OFF, uint8_t preambleDetectorLength = SX126X_GFSK_PREAMBLE_DETECT_8, uint8_t whitening = SX126X_GFSK_WHITENING_ON);
void setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
uint8_t getStatus();
uint32_t getPacketStatus();
@ -375,9 +382,14 @@ class SX126x: public PhysicalLayer {
uint16_t _preambleLength;
float _bwKhz;
uint32_t _br, _freqDev;
uint8_t _rxBw, _pulseShape, _crcTypeFSK, _syncWordLength;
uint16_t _preambleLengthFSK;
float _dataRate;
int16_t config();
int16_t configFSK();
// common low-level SPI interface
void SPIwriteCommand(uint8_t cmd, uint8_t* data, uint8_t numBytes, bool waitForBusy = true);