[SX128x] Added FLRC modem support

This commit is contained in:
jgromes 2020-04-12 11:05:16 +02:00
parent 5c0c7f32c3
commit ff3225cd19
5 changed files with 304 additions and 46 deletions

View file

@ -0,0 +1,114 @@
/*
RadioLib SX128x FLRC Modem Example
This example shows how to use FLRC modem in SX128x chips.
NOTE: The sketch below is just a guide on how to use
FLRC modem, so this code should not be run directly!
Instead, modify the other examples to use FLRC
modem and use the appropriate configuration
methods.
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// SX1280 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// NRST pin: 3
// BUSY pin: 9
SX1280 flrc = new Module(10, 2, 3, 9);
// or using RadioShield
// https://github.com/jgromes/RadioShield
//SX1280 flrc = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize SX1280 with default settings
Serial.print(F("[SX1280] Initializing ... "));
// carrier frequency: 2400.0 MHz
// bit rate: 650 kbps
// coding rate: 3
// output power: 10 dBm
// preamble length: 16 bits
// data shaping: Gaussian, BT = 0.5
// sync word: 0x2D 0x01 0x4B 0x1D
// CRC: enabled
int state = flrc.beginFLRC();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// if needed, you can switch between LoRa and FLRC modes
//
// flrc.begin() start LoRa mode (and disable FLRC)
// lora.beginFLRC() start FLRC mode (and disable LoRa)
// the following settings can also
// be modified at run-time
state = flrc.setFrequency(2410.5);
state = flrc.setBitRate(200);
state = flrc.setCodingRate(2);
state = flrc.setOutputPower(5);
state = flrc.setDataShaping(1.0);
uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67};
state = flrc.setSyncWord(syncWord, 4);
if (state != ERR_NONE) {
Serial.print(F("Unable to set configuration, code "));
Serial.println(state);
while (true);
}
#warning "This sketch is just an API guide! Read the note at line 6."
}
void loop() {
// FLRC modem can use the same transmit/receive methods
// as the LoRa modem, even their interrupt-driven versions
// transmit FLRC packet
int state = flrc.transmit("Hello World!");
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
int state = flrc.transmit(byteArr, 8);
*/
if (state == ERR_NONE) {
Serial.println(F("[SX1280] Packet transmitted successfully!"));
} else if (state == ERR_PACKET_TOO_LONG) {
Serial.println(F("[SX1280] Packet too long!"));
} else if (state == ERR_TX_TIMEOUT) {
Serial.println(F("[SX1280] Timed out while transmitting!"));
} else {
Serial.println(F("[SX1280] Failed to transmit packet, code "));
Serial.println(state);
}
// receive GFSK packet
String str;
state = flrc.receive(str);
/*
byte byteArr[8];
int state = flrc.receive(byteArr, 8);
*/
if (state == ERR_NONE) {
Serial.println(F("[SX1280] Received packet!"));
Serial.print(F("[SX1280] Data:\t"));
Serial.println(str);
} else if (state == ERR_RX_TIMEOUT) {
Serial.println(F("[SX1280] Timed out while waiting for packet!"));
} else {
Serial.print(F("[SX1280] Failed to receive packet, code "));
Serial.println(state);
}
}

View file

@ -37,7 +37,6 @@ void setup() {
// frequency deviation: 400.0 kHz
// output power: 10 dBm
// preamble length: 16 bits
// coding rate: 7
// data shaping: Gaussian, BT = 0.5
// sync word: 0x2D 0x01
// CRC: enabled, CRC16 (CCIT)

View file

@ -214,6 +214,11 @@ getPictureHeight KEYWORD2
# SX128x
beginGFSK KEYWORD2
beginFLRC KEYWORD2
beginBLE KEYWORD2
range KEYWORD2
startRanging KEYWORD2
getRangingResult KEYWORD2
#######################################
# Constants (LITERAL1)

View file

@ -114,6 +114,64 @@ int16_t SX128x::beginGFSK(float freq, uint16_t br, float freqDev, int8_t power,
return(state);
}
int16_t SX128x::beginFLRC(float freq, uint16_t br, uint8_t cr, int8_t power, uint16_t preambleLength, float dataShaping) {
// set module properties
_mod->init(RADIOLIB_USE_SPI);
Module::pinMode(_mod->getIrq(), INPUT);
Module::pinMode(_mod->getGpio(), INPUT);
// initialize FLRC modulation variables
_brKbps = br;
_br = SX128X_FLRC_BR_0_650_BW_0_6;
_crFLRC = SX128X_FLRC_CR_3_4;
_shaping = SX128X_FLRC_BT_0_5;
// initialize FLRC packet variables
_preambleLengthGFSK = preambleLength;
_syncWordLen = 2;
_syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_1;
_crcGFSK = SX128X_GFSK_FLRC_CRC_2_BYTE;
_whitening = SX128X_GFSK_BLE_WHITENING_OFF;
// reset the module and verify startup
int16_t state = reset();
RADIOLIB_ASSERT(state);
// set mode to standby
state = standby();
RADIOLIB_ASSERT(state);
// configure settings not accessible by API
state = config(SX128X_PACKET_TYPE_FLRC);
RADIOLIB_ASSERT(state);
// configure publicly accessible settings
state = setFrequency(freq);
RADIOLIB_ASSERT(state);
state = setBitRate(br);
RADIOLIB_ASSERT(state);
state = setCodingRate(cr);
RADIOLIB_ASSERT(state);
state = setOutputPower(power);
RADIOLIB_ASSERT(state);
state = setPreambleLength(preambleLength);
RADIOLIB_ASSERT(state);
state = setDataShaping(dataShaping);
RADIOLIB_ASSERT(state);
// set publicly accessible settings that are not a part of begin method
uint8_t sync[] = { 0x2D, 0x01, 0x4B, 0x1D};
state = setSyncWord(sync, 4);
RADIOLIB_ASSERT(state);
return(state);
}
int16_t SX128x::reset(bool verify) {
// run the reset sequence - same as SX126x, as SX128x docs don't seem to mention this
Module::pinMode(_mod->getRst(), OUTPUT);
@ -336,7 +394,7 @@ int16_t SX128x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
uint8_t modem = getPacketType();
if(modem == SX128X_PACKET_TYPE_LORA) {
state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, len, _crcLoRa);
} else if(modem == SX128X_PACKET_TYPE_GFSK) {
} else if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_FLRC)) {
state = setPacketParamsGFSK(_preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening, len);
} else {
return(ERR_WRONG_MODEM);
@ -406,6 +464,11 @@ int16_t SX128x::startReceive(uint16_t timeout) {
}
int16_t SX128x::readData(uint8_t* data, size_t len) {
// check active modem
if(getPacketType() == SX128X_PACKET_TYPE_RANGING) {
return(ERR_WRONG_MODEM);
}
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
@ -511,19 +574,29 @@ int16_t SX128x::setSpreadingFactor(uint8_t sf) {
int16_t SX128x::setCodingRate(uint8_t cr, bool longInterleaving) {
// check active modem
uint8_t modem = getPacketType();
if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) {
return(ERR_WRONG_MODEM);
// LoRa/ranging
if((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING)) {
RADIOLIB_CHECK_RANGE(cr, 5, 8, ERR_INVALID_CODING_RATE);
// update modulation parameters
if(longInterleaving && (modem == SX128X_PACKET_TYPE_LORA)) {
_cr = cr;
} else {
_cr = cr - 4;
}
return(setModulationParams(_sf, _bw, _cr));
// FLRC
} else if(modem == SX128X_PACKET_TYPE_FLRC) {
RADIOLIB_CHECK_RANGE(cr, 2, 4, ERR_INVALID_CODING_RATE);
// update modulation parameters
_crFLRC = (cr - 2) * 2;
return(setModulationParams(_br, _crFLRC, _shaping));
}
RADIOLIB_CHECK_RANGE(cr, 5, 8, ERR_INVALID_CODING_RATE);
// update modulation parameters
if(longInterleaving && (modem == SX128X_PACKET_TYPE_LORA)) {
_cr = cr;
} else {
_cr = cr - 4;
}
return(setModulationParams(_sf, _bw, _cr));
return(ERR_WRONG_MODEM);
}
int16_t SX128x::setOutputPower(int8_t power) {
@ -583,33 +656,58 @@ int16_t SX128x::setPreambleLength(uint32_t preambleLength) {
int16_t SX128x::setBitRate(uint16_t br) {
// check active modem
uint8_t modem = getPacketType();
if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) {
return(ERR_WRONG_MODEM);
// GFSK/BLE
if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE)) {
if(br == 125) {
_br = SX128X_BLE_GFSK_BR_0_125_BW_0_3;
} else if(br == 250) {
_br = SX128X_BLE_GFSK_BR_0_250_BW_0_6;
} else if(br == 400) {
_br = SX128X_BLE_GFSK_BR_0_400_BW_1_2;
} else if(br == 500) {
_br = SX128X_BLE_GFSK_BR_0_500_BW_1_2;
} else if(br == 800) {
_br = SX128X_BLE_GFSK_BR_0_800_BW_2_4;
} else if(br == 1000) {
_br = SX128X_BLE_GFSK_BR_1_000_BW_2_4;
} else if(br == 1600) {
_br = SX128X_BLE_GFSK_BR_1_600_BW_2_4;
} else if(br == 2000) {
_br = SX128X_BLE_GFSK_BR_2_000_BW_2_4;
} else {
return(ERR_INVALID_BIT_RATE);
}
// update modulation parameters
_brKbps = br;
return(setModulationParams(_br, _modIndex, _shaping));
// FLRC
} else if(modem == SX128X_PACKET_TYPE_FLRC) {
if(br == 260) {
_br = SX128X_FLRC_BR_0_260_BW_0_3;
} else if(br == 325) {
_br = SX128X_FLRC_BR_0_325_BW_0_3;
} else if(br == 520) {
_br = SX128X_FLRC_BR_0_520_BW_0_6;
} else if(br == 650) {
_br = SX128X_FLRC_BR_0_650_BW_0_6;
} else if(br == 1000) {
_br = SX128X_FLRC_BR_1_000_BW_1_2;
} else if(br == 1300) {
_br = SX128X_FLRC_BR_1_300_BW_1_2;
} else {
return(ERR_INVALID_BIT_RATE);
}
// update modulation parameters
_brKbps = br;
return(setModulationParams(_br, _crFLRC, _shaping));
}
if(br == 125) {
_br = SX128X_BLE_GFSK_BR_0_125_BW_0_3;
} else if(br == 250) {
_br = SX128X_BLE_GFSK_BR_0_250_BW_0_6;
} else if(br == 400) {
_br = SX128X_BLE_GFSK_BR_0_400_BW_1_2;
} else if(br == 500) {
_br = SX128X_BLE_GFSK_BR_0_500_BW_1_2;
} else if(br == 800) {
_br = SX128X_BLE_GFSK_BR_0_800_BW_2_4;
} else if(br == 1000) {
_br = SX128X_BLE_GFSK_BR_1_000_BW_2_4;
} else if(br == 1600) {
_br = SX128X_BLE_GFSK_BR_1_600_BW_2_4;
} else if(br == 2000) {
_br = SX128X_BLE_GFSK_BR_2_000_BW_2_4;
} else {
return(ERR_INVALID_BIT_RATE);
}
// update modulation parameters
_brKbps = br;
return(setModulationParams(_br, _modIndex, _shaping));
return(ERR_WRONG_MODEM);
}
int16_t SX128x::setFrequencyDeviation(float freqDev) {
@ -642,7 +740,7 @@ int16_t SX128x::setFrequencyDeviation(float freqDev) {
int16_t SX128x::setDataShaping(float dataShaping) {
// check active modem
uint8_t modem = getPacketType();
if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE))) {
if(!((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE) || (modem == SX128X_PACKET_TYPE_FLRC))) {
return(ERR_WRONG_MODEM);
}
@ -659,7 +757,11 @@ int16_t SX128x::setDataShaping(float dataShaping) {
}
// update modulation parameters
return(setModulationParams(_br, _modIndex, _shaping));
if((modem == SX128X_PACKET_TYPE_GFSK) || (modem == SX128X_PACKET_TYPE_BLE)) {
return(setModulationParams(_br, _modIndex, _shaping));
} else {
return(setModulationParams(_br, _crFLRC, _shaping));
}
}
int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) {
@ -669,8 +771,25 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) {
return(ERR_WRONG_MODEM);
}
if(len > 5) {
return(ERR_INVALID_SYNC_WORD);
if(modem == SX128X_PACKET_TYPE_GFSK) {
// GFSK can use up to 5 bytes as sync word
if(len > 5) {
return(ERR_INVALID_SYNC_WORD);
}
// calculate sync word length parameter value
if(len > 0) {
_syncWordLen = (len - 1)*2;
}
} else {
// FLRC requires 32-bit sync word
if(!((len == 0) || (len == 4))) {
return(ERR_INVALID_SYNC_WORD);
}
// save sync word length parameter value
_syncWordLen = len;
}
// reverse sync word byte order
@ -684,7 +803,6 @@ int16_t SX128x::setSyncWord(uint8_t* syncWord, uint8_t len) {
RADIOLIB_ASSERT(state);
// update packet parameters
_syncWordLen = len;
if(_syncWordLen == 0) {
_syncWordMatch = SX128X_GFSK_FLRC_SYNC_WORD_OFF;
} else {

View file

@ -384,6 +384,25 @@ class SX128x: public PhysicalLayer {
*/
int16_t beginGFSK(float freq = 2400.0, uint16_t br = 800, float freqDev = 400.0, int8_t power = 10, uint16_t preambleLength = 16, float dataShaping = 0.5);
/*!
\brief Initialization method for FLRC modem.
\param freq Carrier frequency in MHz. Defaults to 2400.0 MHz.
\param br FLRC bit rate in kbps. Defaults to 650 kbps.
\param cr FLRC coding rate. Defaults to 3 (coding rate 3/4).
\param power Output power in dBm. Defaults to 10 dBm.
\parma preambleLength FLRC preamble length in bits. Defaults to 16 bits.
\param dataShaping Time-bandwidth product of the Gaussian filter to be used for shaping. Defaults to 0.5.
\returns \ref status_codes
*/
int16_t beginFLRC(float freq = 2400.0, uint16_t br = 650, uint8_t cr = 3, int8_t power = 10, uint16_t preambleLength = 16, float dataShaping = 0.5);
/*!
\brief Reset method. Will reset the chip to the default state using RST pin.
@ -576,9 +595,9 @@ class SX128x: public PhysicalLayer {
int16_t setPreambleLength(uint32_t preambleLength);
/*!
\brief Sets FSK bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, 1600 and 2000 kbps.
\brief Sets FSK or FLRC bit rate. Allowed values are 125, 250, 400, 500, 800, 1000, 1600 and 2000 kbps (for FSK modem) or 260, 325, 520, 650, 1000 and 1300 (for FLRC modem).
\param br FSK bit rate to be set in kbps.
\param br FSK/FLRC bit rate to be set in kbps.
\returns \ref status_codes
*/
@ -603,7 +622,7 @@ class SX128x: public PhysicalLayer {
int16_t setDataShaping(float dataShaping);
/*!
\brief Sets sync word in the form of array of up to 8 bytes.
\brief Sets FSK/FLRC sync word in the form of array of up to 5 bytes (FSK). For FLRC modem, the sync word must be exactly 4 bytes long
\param syncWord Sync word to be set.
@ -737,6 +756,9 @@ class SX128x: public PhysicalLayer {
uint8_t _br, _modIndex, _shaping;
uint8_t _preambleLengthGFSK, _syncWordLen, _syncWordMatch, _crcGFSK, _whitening;
// cached FLRC parameters
uint8_t _crFLRC;
// cached BLE parameters
uint8_t _connectionState, _crcBLE, _bleTestPayload;