[LR11x0] Added GFSK modem support (#679)
This commit is contained in:
parent
4d1157e3a4
commit
6fa4aa3ebb
3 changed files with 698 additions and 35 deletions
153
examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino
Normal file
153
examples/LR11x0/LR11x0_GFSK_Modem/LR11x0_GFSK_Modem.ino
Normal file
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
RadioLib LR11x0 GFSK Modem Example
|
||||
|
||||
This example shows how to use GFSK modem in LR11x0 chips.
|
||||
|
||||
NOTE: The sketch below is just a guide on how to use
|
||||
GFSK modem, so this code should not be run directly!
|
||||
Instead, modify the other examples to use GFSK
|
||||
modem and use the appropriate configuration
|
||||
methods.
|
||||
|
||||
For default module settings, see the wiki page
|
||||
https://github.com/jgromes/RadioLib/wiki/Default-configuration#lr11x0---gfsk-modem
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// LR1110 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
LR1110 radio = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//LR1110 radio = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize LR1110 with default settings
|
||||
Serial.print(F("[LR1110] Initializing ... "));
|
||||
int state = radio.beginGFSK();
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true);
|
||||
}
|
||||
|
||||
// if needed, you can switch between any of the modems
|
||||
//
|
||||
// radio.begin() start LoRa modem (and disable GFSK)
|
||||
// radio.beginGFSK() start GFSK modem (and disable LoRa)
|
||||
|
||||
// the following settings can also
|
||||
// be modified at run-time
|
||||
state = radio.setFrequency(433.5);
|
||||
state = radio.setBitRate(100.0);
|
||||
state = radio.setFrequencyDeviation(10.0);
|
||||
state = radio.setRxBandwidth(250.0);
|
||||
state = radio.setOutputPower(10.0);
|
||||
state = radio.setDataShaping(RADIOLIB_SHAPING_1_0);
|
||||
uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67,
|
||||
0x89, 0xAB, 0xCD, 0xEF};
|
||||
state = radio.setSyncWord(syncWord, 8);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
Serial.print(F("Unable to set configuration, code "));
|
||||
Serial.println(state);
|
||||
while (true);
|
||||
}
|
||||
|
||||
// GFSK modem on LR11x0 can handle the sync word setting in bits, not just
|
||||
// whole bytes. The value used is left-justified.
|
||||
// This makes same result as radio.setSyncWord(syncWord, 8):
|
||||
state = radio.setSyncBits(syncWord, 64);
|
||||
// This will use 0x012 as sync word (12 bits only):
|
||||
state = radio.setSyncBits(syncWord, 12);
|
||||
|
||||
// GFSK modem allows advanced CRC configuration
|
||||
// Default is CCIT CRC16 (2 bytes, initial 0x1D0F, polynomial 0x1021, inverted)
|
||||
// Set CRC to IBM CRC (2 bytes, initial 0xFFFF, polynomial 0x8005, non-inverted)
|
||||
state = radio.setCRC(2, 0xFFFF, 0x8005, false);
|
||||
// set CRC length to 0 to disable CRC
|
||||
|
||||
#warning "This sketch is just an API guide! Read the note at line 6."
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// GFSK modem can use the same transmit/receive methods
|
||||
// as the LoRa modem, even their interrupt-driven versions
|
||||
|
||||
// transmit GFSK packet
|
||||
int state = radio.transmit("Hello World!");
|
||||
/*
|
||||
byte byteArr[] = {0x01, 0x23, 0x45, 0x67,
|
||||
0x89, 0xAB, 0xCD, 0xEF};
|
||||
int state = radio.transmit(byteArr, 8);
|
||||
*/
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("[LR1110] Packet transmitted successfully!"));
|
||||
} else if (state == RADIOLIB_ERR_PACKET_TOO_LONG) {
|
||||
Serial.println(F("[LR1110] Packet too long!"));
|
||||
} else if (state == RADIOLIB_ERR_TX_TIMEOUT) {
|
||||
Serial.println(F("[LR1110] Timed out while transmitting!"));
|
||||
} else {
|
||||
Serial.println(F("[LR1110] Failed to transmit packet, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
|
||||
// receive GFSK packet
|
||||
String str;
|
||||
state = radio.receive(str);
|
||||
/*
|
||||
byte byteArr[8];
|
||||
int state = radio.receive(byteArr, 8);
|
||||
*/
|
||||
if (state == RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("[LR1110] Received packet!"));
|
||||
Serial.print(F("[LR1110] Data:\t"));
|
||||
Serial.println(str);
|
||||
} else if (state == RADIOLIB_ERR_RX_TIMEOUT) {
|
||||
Serial.println(F("[LR1110] Timed out while waiting for packet!"));
|
||||
} else {
|
||||
Serial.print(F("[LR1110] Failed to receive packet, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
|
||||
// GFSK modem has built-in address filtering system
|
||||
// it can be enabled by setting node address, broadcast
|
||||
// address, or both
|
||||
//
|
||||
// to transmit packet to a particular address,
|
||||
// use the following methods:
|
||||
//
|
||||
// radio.transmit("Hello World!", address);
|
||||
// radio.startTransmit("Hello World!", address);
|
||||
|
||||
// set node address to 0x02
|
||||
state = radio.setNodeAddress(0x02);
|
||||
// set broadcast address to 0xFF
|
||||
state = radio.setBroadcastAddress(0xFF);
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("[LR1110] Unable to set address filter, code "));
|
||||
Serial.println(state);
|
||||
}
|
||||
|
||||
// address filtering can also be disabled
|
||||
// NOTE: calling this method will also erase previously set
|
||||
// node and broadcast address
|
||||
/*
|
||||
state = radio.disableAddressFiltering();
|
||||
if (state != RADIOLIB_ERR_NONE) {
|
||||
Serial.println(F("Unable to remove address filter, code "));
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -110,14 +110,47 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preamble
|
|||
int16_t state = standby();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// TODO implement GFSK
|
||||
(void)br;
|
||||
(void)freqDev;
|
||||
(void)rxBw;
|
||||
(void)preambleLength;
|
||||
(void)tcxoVoltage;
|
||||
// set TCXO control, if requested
|
||||
if(!this->XTAL && tcxoVoltage > 0.0) {
|
||||
state = setTCXO(tcxoVoltage);
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
|
||||
return(RADIOLIB_ERR_UNSUPPORTED);
|
||||
// configure settings not accessible by API
|
||||
state = config(RADIOLIB_LR11X0_PACKET_TYPE_GFSK);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// configure publicly accessible settings
|
||||
state = setBitRate(br);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setFrequencyDeviation(freqDev);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setRxBandwidth(rxBw);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setPreambleLength(preambleLength);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set publicly accessible settings that are not a part of begin method
|
||||
uint8_t sync[] = { 0x12, 0xAD };
|
||||
state = setSyncWord(sync, 2);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setDataShaping(RADIOLIB_SHAPING_NONE);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setEncoding(RADIOLIB_ENCODING_NRZ);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = variablePacketLengthMode(RADIOLIB_LR11X0_MAX_PACKET_LENGTH);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setCRC(2);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
return(RADIOLIB_ERR_NONE);
|
||||
}
|
||||
|
||||
int16_t LR11x0::reset() {
|
||||
|
@ -267,12 +300,12 @@ int16_t LR11x0::standby(uint8_t mode, bool wakeup) {
|
|||
// set RF switch (if present)
|
||||
this->mod->setRfSwitchState(Module::MODE_IDLE);
|
||||
|
||||
// TODO this will block BUSY forever
|
||||
(void)wakeup;
|
||||
/*if(wakeup) {
|
||||
// pull NSS low to wake up
|
||||
if(wakeup) {
|
||||
// pull NSS low for a while to wake up
|
||||
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelLow);
|
||||
}*/
|
||||
this->mod->hal->delay(1);
|
||||
this->mod->hal->digitalWrite(this->mod->getCs(), this->mod->hal->GpioLevelHigh);
|
||||
}
|
||||
|
||||
uint8_t buff[] = { mode };
|
||||
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_STANDBY, true, buff, 1));
|
||||
|
@ -577,6 +610,327 @@ int16_t LR11x0::setSyncWord(uint8_t syncWord) {
|
|||
return(setLoRaSyncWord(syncWord));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setBitRate(float br) {
|
||||
RADIOLIB_CHECK_RANGE(br, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
|
||||
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// set bit rate value
|
||||
// TODO implement fractional bit rate configuration
|
||||
this->bitRate = br * 1000.0;
|
||||
return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setFrequencyDeviation(float freqDev) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// set frequency deviation to lowest available setting (required for digimodes)
|
||||
float newFreqDev = freqDev;
|
||||
if(freqDev < 0.0) {
|
||||
newFreqDev = 0.6;
|
||||
}
|
||||
|
||||
RADIOLIB_CHECK_RANGE(newFreqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
|
||||
this->frequencyDev = freqDev * 1000.0;
|
||||
return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setRxBandwidth(float rxBw) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// check modulation parameters
|
||||
/*if(2 * this->frequencyDev + this->bitRate > rxBw * 1000.0) {
|
||||
return(RADIOLIB_ERR_INVALID_MODULATION_PARAMETERS);
|
||||
}*/
|
||||
|
||||
// check allowed receiver bandwidth values
|
||||
if(fabs(rxBw - 4.8) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_4_8;
|
||||
} else if(fabs(rxBw - 5.8) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_5_8;
|
||||
} else if(fabs(rxBw - 7.3) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_7_3;
|
||||
} else if(fabs(rxBw - 9.7) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_9_7;
|
||||
} else if(fabs(rxBw - 11.7) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_11_7;
|
||||
} else if(fabs(rxBw - 14.6) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_14_6;
|
||||
} else if(fabs(rxBw - 19.5) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_19_5;
|
||||
} else if(fabs(rxBw - 23.4) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_23_4;
|
||||
} else if(fabs(rxBw - 29.3) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_29_3;
|
||||
} else if(fabs(rxBw - 39.0) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_39_0;
|
||||
} else if(fabs(rxBw - 46.9) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_46_9;
|
||||
} else if(fabs(rxBw - 58.6) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_58_6;
|
||||
} else if(fabs(rxBw - 78.2) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_78_2;
|
||||
} else if(fabs(rxBw - 93.8) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_93_8;
|
||||
} else if(fabs(rxBw - 117.3) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_117_3;
|
||||
} else if(fabs(rxBw - 156.2) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_156_2;
|
||||
} else if(fabs(rxBw - 187.2) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_187_2;
|
||||
} else if(fabs(rxBw - 234.3) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_234_3;
|
||||
} else if(fabs(rxBw - 312.0) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_312_0;
|
||||
} else if(fabs(rxBw - 373.6) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_373_6;
|
||||
} else if(fabs(rxBw - 467.0) <= 0.001) {
|
||||
this->rxBandwidth = RADIOLIB_LR11X0_GFSK_RX_BW_467_0;
|
||||
} else {
|
||||
return(RADIOLIB_ERR_INVALID_RX_BANDWIDTH);
|
||||
}
|
||||
|
||||
// update modulation parameters
|
||||
return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setSyncWord(uint8_t* syncWord, size_t len) {
|
||||
if((!syncWord) || (!len) || (len > RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) {
|
||||
return(RADIOLIB_ERR_INVALID_SYNC_WORD);
|
||||
}
|
||||
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// update sync word length
|
||||
this->syncWordLength = len*8;
|
||||
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// sync word is passed most-significant byte first
|
||||
uint8_t fullSyncWord[RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN] = { 0 };
|
||||
memcpy(fullSyncWord, syncWord, len);
|
||||
return(setGfskSyncWord(fullSyncWord));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setSyncBits(uint8_t *syncWord, uint8_t bitsLen) {
|
||||
if((!syncWord) || (!bitsLen) || (bitsLen > 8*RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN)) {
|
||||
return(RADIOLIB_ERR_INVALID_SYNC_WORD);
|
||||
}
|
||||
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
uint8_t bytesLen = bitsLen / 8;
|
||||
if ((bitsLen % 8) != 0) {
|
||||
bytesLen++;
|
||||
}
|
||||
|
||||
return(setSyncWord(syncWord, bytesLen));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setNodeAddress(uint8_t nodeAddr) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// enable address filtering (node only)
|
||||
this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE;
|
||||
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set node address
|
||||
this->node = nodeAddr;
|
||||
return(setPacketAdrs(this->node, 0));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setBroadcastAddress(uint8_t broadAddr) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// enable address filtering (node and broadcast)
|
||||
this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_NODE_BROADCAST;
|
||||
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set node and broadcast address
|
||||
return(setPacketAdrs(this->node, broadAddr));
|
||||
}
|
||||
|
||||
int16_t LR11x0::disableAddressFiltering() {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// disable address filterin
|
||||
this->addrComp = RADIOLIB_LR11X0_GFSK_ADDR_FILTER_DISABLED;
|
||||
return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setDataShaping(uint8_t sh) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// set data shaping
|
||||
switch(sh) {
|
||||
case RADIOLIB_SHAPING_NONE:
|
||||
this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_NONE;
|
||||
break;
|
||||
case RADIOLIB_SHAPING_0_3:
|
||||
this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_3;
|
||||
break;
|
||||
case RADIOLIB_SHAPING_0_5:
|
||||
this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_5;
|
||||
break;
|
||||
case RADIOLIB_SHAPING_0_7:
|
||||
this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_0_7;
|
||||
break;
|
||||
case RADIOLIB_SHAPING_1_0:
|
||||
this->pulseShape = RADIOLIB_LR11X0_GFSK_SHAPING_GAUSSIAN_BT_1_0;
|
||||
break;
|
||||
default:
|
||||
return(RADIOLIB_ERR_INVALID_DATA_SHAPING);
|
||||
}
|
||||
|
||||
// update modulation parameters
|
||||
return(setModulationParamsGFSK(this->bitRate, this->pulseShape, this->rxBandwidth, this->frequencyDev));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setEncoding(uint8_t encoding) {
|
||||
return(setWhitening(encoding));
|
||||
}
|
||||
|
||||
int16_t LR11x0::fixedPacketLengthMode(uint8_t len) {
|
||||
return(setPacketMode(RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_FIXED, len));
|
||||
}
|
||||
|
||||
int16_t LR11x0::variablePacketLengthMode(uint8_t maxLen) {
|
||||
return(setPacketMode(RADIOLIB_LR11X0_GFSK_PACKET_LENGTH_VARIABLE, maxLen));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setWhitening(bool enabled, uint16_t initial) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
if(!enabled) {
|
||||
// disable whitening
|
||||
this->whitening = RADIOLIB_LR11X0_GFSK_WHITENING_DISABLED;
|
||||
|
||||
} else {
|
||||
// enable whitening
|
||||
this->whitening = RADIOLIB_LR11X0_GFSK_WHITENING_ENABLED;
|
||||
|
||||
// write initial whitening value
|
||||
state = setGfskWhitParams(initial);
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
|
||||
return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setDataRate(DataRate_t dr) {
|
||||
// select interpretation based on active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
// set the bit rate
|
||||
state = this->setBitRate(dr.fsk.bitRate);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set the frequency deviation
|
||||
state = this->setFrequencyDeviation(dr.fsk.freqDev);
|
||||
|
||||
} else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
|
||||
// set the spreading factor
|
||||
state = this->setSpreadingFactor(dr.lora.spreadingFactor);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set the bandwidth
|
||||
state = this->setBandwidth(dr.lora.bandwidth);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set the coding rate
|
||||
state = this->setCodingRate(dr.lora.codingRate);
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t LR11x0::checkDataRate(DataRate_t dr) {
|
||||
// select interpretation based on active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
RADIOLIB_CHECK_RANGE(dr.fsk.bitRate, 0.6, 300.0, RADIOLIB_ERR_INVALID_BIT_RATE);
|
||||
RADIOLIB_CHECK_RANGE(dr.fsk.freqDev, 0.6, 200.0, RADIOLIB_ERR_INVALID_FREQUENCY_DEVIATION);
|
||||
return(RADIOLIB_ERR_NONE);
|
||||
|
||||
} else if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
|
||||
RADIOLIB_CHECK_RANGE(dr.lora.spreadingFactor, 5, 12, RADIOLIB_ERR_INVALID_SPREADING_FACTOR);
|
||||
RADIOLIB_CHECK_RANGE(dr.lora.bandwidth, 0.0, 510.0, RADIOLIB_ERR_INVALID_BANDWIDTH);
|
||||
RADIOLIB_CHECK_RANGE(dr.lora.codingRate, 5, 8, RADIOLIB_ERR_INVALID_CODING_RATE);
|
||||
return(RADIOLIB_ERR_NONE);
|
||||
|
||||
}
|
||||
|
||||
return(RADIOLIB_ERR_UNKNOWN);
|
||||
}
|
||||
|
||||
int16_t LR11x0::setPreambleLength(size_t preambleLength) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
|
@ -585,6 +939,10 @@ int16_t LR11x0::setPreambleLength(size_t preambleLength) {
|
|||
if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
|
||||
this->preambleLengthLoRa = preambleLength;
|
||||
return(setPacketParamsLoRa(this->preambleLengthLoRa, this->headerType, this->implicitLen, this->crcTypeLoRa, (uint8_t)this->invertIQEnabled));
|
||||
} else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
this->preambleLengthGFSK = preambleLength;
|
||||
this->preambleDetLength = RADIOLIB_LR11X0_GFSK_PREAMBLE_DETECT_16_BITS;
|
||||
return(setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening));
|
||||
}
|
||||
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
|
@ -645,7 +1003,7 @@ int16_t LR11x0::setTCXO(float voltage, uint32_t delay) {
|
|||
return(setTcxoMode(tune, delayValue));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
|
||||
int16_t LR11x0::setCRC(uint8_t len, uint32_t initial, uint32_t polynomial, bool inverted) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
|
@ -653,18 +1011,40 @@ int16_t LR11x0::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool
|
|||
if(type == RADIOLIB_LR11X0_PACKET_TYPE_LORA) {
|
||||
// LoRa CRC doesn't allow to set CRC polynomial, initial value, or inversion
|
||||
this->crcTypeLoRa = len > 0 ? RADIOLIB_LR11X0_LORA_CRC_ENABLED : RADIOLIB_LR11X0_LORA_CRC_DISABLED;
|
||||
return(setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled));
|
||||
state = setPacketParamsLoRa(this->preambleLengthLoRa, this->crcTypeLoRa, this->implicitLen, this->headerType, (uint8_t)this->invertIQEnabled);
|
||||
|
||||
} else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
// TODO add GFSK support
|
||||
(void)initial;
|
||||
(void)polynomial;
|
||||
(void)inverted;
|
||||
return(RADIOLIB_ERR_UNSUPPORTED);
|
||||
// update packet parameters
|
||||
switch(len) {
|
||||
case 0:
|
||||
this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_DISABLED;
|
||||
break;
|
||||
case 1:
|
||||
if(inverted) {
|
||||
this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_1_BYTE_INV;
|
||||
} else {
|
||||
this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_1_BYTE;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if(inverted) {
|
||||
this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_2_BYTE_INV;
|
||||
} else {
|
||||
this->crcTypeGFSK = RADIOLIB_LR11X0_GFSK_CRC_2_BYTE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return(RADIOLIB_ERR_INVALID_CRC_CONFIGURATION);
|
||||
}
|
||||
|
||||
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, this->packetType, RADIOLIB_LR11X0_MAX_PACKET_LENGTH, this->crcTypeGFSK, this->whitening);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setGfskCrcParams(initial, polynomial);
|
||||
|
||||
}
|
||||
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t LR11x0::invertIQ(bool enable) {
|
||||
|
@ -793,7 +1173,7 @@ uint32_t LR11x0::getTimeOnAir(size_t len) {
|
|||
return(((uint32_t(1) << this->spreadingFactor) / this->bandwidthKhz) * N_symbol * 1000.0);
|
||||
|
||||
} else if(type == RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(((uint32_t)len * 8 * 1000) / this->bitRateKbps);
|
||||
return(((uint32_t)len * 8 * 1000000UL) / this->bitRate);
|
||||
|
||||
}
|
||||
|
||||
|
@ -911,6 +1291,24 @@ int16_t LR11x0::config(uint8_t modem) {
|
|||
return(state);
|
||||
}
|
||||
|
||||
int16_t LR11x0::setPacketMode(uint8_t mode, uint8_t len) {
|
||||
// check active modem
|
||||
uint8_t type = RADIOLIB_LR11X0_PACKET_TYPE_NONE;
|
||||
int16_t state = getPacketType(&type);
|
||||
RADIOLIB_ASSERT(state);
|
||||
if(type != RADIOLIB_LR11X0_PACKET_TYPE_GFSK) {
|
||||
return(RADIOLIB_ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// set requested packet mode
|
||||
state = setPacketParamsGFSK(this->preambleLengthGFSK, this->preambleDetLength, this->syncWordLength, this->addrComp, mode, len, this->crcTypeGFSK, this->whitening);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// update cached value
|
||||
this->packetType = mode;
|
||||
return(state);
|
||||
}
|
||||
|
||||
Module* LR11x0::getMod() {
|
||||
return(this->mod);
|
||||
}
|
||||
|
@ -1311,9 +1709,8 @@ int16_t LR11x0::getPacketStatusGFSK(float* rssiSync, float* rssiAvg, uint8_t* rx
|
|||
int16_t state = this->SPIcommand(RADIOLIB_LR11X0_CMD_GET_PACKET_STATUS, false, buff, sizeof(buff));
|
||||
|
||||
// pass the replies
|
||||
// TODO do the value conversion for RSSI (fixed point?)
|
||||
if(rssiSync) { *rssiSync = (float)buff[0]; }
|
||||
if(rssiAvg) { *rssiAvg = (float)buff[1]; }
|
||||
if(rssiSync) { *rssiSync = (float)buff[0] / -2.0f; }
|
||||
if(rssiAvg) { *rssiAvg = (float)buff[1] / -2.0f; }
|
||||
if(rxLen) { *rxLen = buff[2]; }
|
||||
if(stat) { *stat = buff[3]; }
|
||||
|
||||
|
@ -1334,7 +1731,7 @@ int16_t LR11x0::setGfskSyncWord(uint8_t* sync) {
|
|||
if(!sync) {
|
||||
return(RADIOLIB_ERR_MEMORY_ALLOCATION_FAILED);
|
||||
}
|
||||
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, false, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN));
|
||||
return(this->SPIcommand(RADIOLIB_LR11X0_CMD_SET_GFSK_SYNC_WORD, true, sync, RADIOLIB_LR11X0_GFSK_SYNC_WORD_LEN));
|
||||
}
|
||||
|
||||
int16_t LR11x0::setLoRaPublicNetwork(bool pub) {
|
||||
|
|
|
@ -752,8 +752,121 @@ class LR11x0: public PhysicalLayer {
|
|||
int16_t setSyncWord(uint8_t syncWord);
|
||||
|
||||
/*!
|
||||
\brief Sets preamble length for LoRa or FSK modem. Allowed values range from 1 to 65535.
|
||||
\param preambleLength Preamble length to be set in symbols (LoRa) or bits (FSK).
|
||||
\brief Sets GFSK bit rate. Allowed values range from 0.6 to 300.0 kbps.
|
||||
\param br FSK bit rate to be set in kbps.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setBitRate(float br);
|
||||
|
||||
/*!
|
||||
\brief Sets GFSK frequency deviation. Allowed values range from 0.0 to 200.0 kHz.
|
||||
\param freqDev GFSK frequency deviation to be set in kHz.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setFrequencyDeviation(float freqDev) override;
|
||||
|
||||
/*!
|
||||
\brief Sets GFSK receiver bandwidth. Allowed values are 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5,
|
||||
23.4, 29.3, 39.0, 46.9, 58.6, 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0 kHz.
|
||||
\param rxBw GFSK receiver bandwidth to be set in kHz.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setRxBandwidth(float rxBw);
|
||||
|
||||
/*!
|
||||
\brief Sets GFSK sync word in the form of array of up to 8 bytes.
|
||||
\param syncWord GFSK sync word to be set.
|
||||
\param len GFSK sync word length in bytes.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setSyncWord(uint8_t* syncWord, size_t len) override;
|
||||
|
||||
/*!
|
||||
\brief Sets GFSK sync word in the form of array of up to 8 bytes.
|
||||
\param syncWord GFSK sync word to be set.
|
||||
\param bitsLen GFSK sync word length in bits. If length is not divisible by 8,
|
||||
least significant bits of syncWord will be ignored.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setSyncBits(uint8_t *syncWord, uint8_t bitsLen);
|
||||
|
||||
/*!
|
||||
\brief Sets node address. Calling this method will also enable address filtering for node address only.
|
||||
\param nodeAddr Node address to be set.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setNodeAddress(uint8_t nodeAddr);
|
||||
|
||||
/*!
|
||||
\brief Sets broadcast address. Calling this method will also enable address
|
||||
filtering for node and broadcast address.
|
||||
\param broadAddr Node address to be set.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setBroadcastAddress(uint8_t broadAddr);
|
||||
|
||||
/*!
|
||||
\brief Disables address filtering. Calling this method will also erase previously set addresses.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t disableAddressFiltering();
|
||||
|
||||
/*!
|
||||
\brief Sets time-bandwidth product of Gaussian filter applied for shaping.
|
||||
Allowed values are RADIOLIB_SHAPING_0_3, RADIOLIB_SHAPING_0_5, RADIOLIB_SHAPING_0_7 or RADIOLIB_SHAPING_1_0.
|
||||
Set to RADIOLIB_SHAPING_NONE to disable data shaping.
|
||||
\param sh Time-bandwidth product of Gaussian filter to be set.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setDataShaping(uint8_t sh) override;
|
||||
|
||||
/*!
|
||||
\brief Sets transmission encoding. Available in GFSK mode only. Serves only as alias for PhysicalLayer compatibility.
|
||||
\param encoding Encoding to be used. Set to 0 for NRZ, and 2 for whitening.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setEncoding(uint8_t encoding) override;
|
||||
|
||||
/*!
|
||||
\brief Set modem in fixed packet length mode. Available in GFSK mode only.
|
||||
\param len Packet length.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t fixedPacketLengthMode(uint8_t len = RADIOLIB_LR11X0_MAX_PACKET_LENGTH);
|
||||
|
||||
/*!
|
||||
\brief Set modem in variable packet length mode. Available in GFSK mode only.
|
||||
\param maxLen Maximum packet length.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t variablePacketLengthMode(uint8_t maxLen = RADIOLIB_LR11X0_MAX_PACKET_LENGTH);
|
||||
|
||||
/*!
|
||||
\brief Sets GFSK whitening parameters.
|
||||
\param enabled True = Whitening enabled
|
||||
\param initial Initial value used for the whitening LFSR in GFSK mode.
|
||||
By default set to 0x01FF for compatibility with SX127x and LoRaWAN.
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setWhitening(bool enabled, uint16_t initial = 0x01FF);
|
||||
|
||||
/*!
|
||||
\brief Set data.
|
||||
\param dr Data rate struct. Interpretation depends on currently active modem (GFSK or LoRa).
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setDataRate(DataRate_t dr) override;
|
||||
|
||||
/*!
|
||||
\brief Check the data rate can be configured by this module.
|
||||
\param dr Data rate struct. Interpretation depends on currently active modem (GFSK or LoRa).
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t checkDataRate(DataRate_t dr) override;
|
||||
|
||||
/*!
|
||||
\brief Sets preamble length for LoRa or GFSK modem. Allowed values range from 1 to 65535.
|
||||
\param preambleLength Preamble length to be set in symbols (LoRa) or bits (GFSK).
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setPreambleLength(size_t preambleLength) override;
|
||||
|
@ -771,12 +884,12 @@ class LR11x0: public PhysicalLayer {
|
|||
/*!
|
||||
\brief Sets CRC configuration.
|
||||
\param len CRC length in bytes, Allowed values are 1 or 2, set to 0 to disable CRC.
|
||||
\param initial Initial CRC value. FSK only. Defaults to 0x1D0F (CCIT CRC).
|
||||
\param polynomial Polynomial for CRC calculation. FSK only. Defaults to 0x1021 (CCIT CRC).
|
||||
\param inverted Invert CRC bytes. FSK only. Defaults to true (CCIT CRC).
|
||||
\param initial Initial CRC value. GFSK only. Defaults to 0x1D0F (CCIT CRC).
|
||||
\param polynomial Polynomial for CRC calculation. GFSK only. Defaults to 0x1021 (CCIT CRC).
|
||||
\param inverted Invert CRC bytes. GFSK only. Defaults to true (CCIT CRC).
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t setCRC(uint8_t len, uint16_t initial = 0x1D0F, uint16_t polynomial = 0x1021, bool inverted = true);
|
||||
int16_t setCRC(uint8_t len, uint32_t initial = 0x00001D0FUL, uint32_t polynomial = 0x00001021UL, bool inverted = true);
|
||||
|
||||
/*!
|
||||
\brief Enable/disable inversion of the I and Q signals
|
||||
|
@ -995,9 +1108,8 @@ class LR11x0: public PhysicalLayer {
|
|||
bool invertIQEnabled = false;
|
||||
|
||||
// cached GFSK parameters
|
||||
float bitRateKbps = 0;
|
||||
uint8_t bitRate = 0;
|
||||
uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0;
|
||||
uint32_t bitRate = 0, frequencyDev = 0;
|
||||
uint8_t preambleDetLength = 0, rxBandwidth = 0, pulseShape = 0, crcTypeGFSK = 0, syncWordLength = 0, addrComp = 0, whitening = 0, packetType = 0, node = 0;
|
||||
uint16_t preambleLengthGFSK = 0;
|
||||
|
||||
float dataRateMeasured = 0;
|
||||
|
@ -1006,6 +1118,7 @@ class LR11x0: public PhysicalLayer {
|
|||
static int16_t SPIcheckStatus(Module* mod);
|
||||
bool findChip(uint8_t ver);
|
||||
int16_t config(uint8_t modem);
|
||||
int16_t setPacketMode(uint8_t mode, uint8_t len);
|
||||
|
||||
// common methods to avoid some copy-paste
|
||||
int16_t bleBeaconCommon(uint16_t cmd, uint8_t chan, uint8_t* payload, size_t len);
|
||||
|
|
Loading…
Add table
Reference in a new issue