[LR11x0] Added GFSK modem support (#679)

pull/1075/head
jgromes 2024-04-19 20:30:53 +02:00
rodzic 4d1157e3a4
commit 6fa4aa3ebb
3 zmienionych plików z 698 dodań i 35 usunięć

Wyświetl plik

@ -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 "));
}
*/
}

Wyświetl plik

@ -109,15 +109,48 @@ int16_t LR11x0::beginGFSK(float br, float freqDev, float rxBw, uint16_t preamble
// set mode to standby
int16_t state = standby();
RADIOLIB_ASSERT(state);
// TODO implement GFSK
(void)br;
(void)freqDev;
(void)rxBw;
(void)preambleLength;
(void)tcxoVoltage;
return(RADIOLIB_ERR_UNSUPPORTED);
// set TCXO control, if requested
if(!this->XTAL && tcxoVoltage > 0.0) {
state = setTCXO(tcxoVoltage);
RADIOLIB_ASSERT(state);
}
// 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) {

Wyświetl plik

@ -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);