[SX126x] Implemented LoRa receive method

pull/13/head
jgromes 2019-05-14 18:34:43 +02:00
rodzic 085d496b88
commit cfdd921984
3 zmienionych plików z 265 dodań i 54 usunięć

Wyświetl plik

@ -0,0 +1,91 @@
/*
RadioLib SX126x Receive Example
This example listens for LoRa transmissions using SX126x Lora modules.
To successfully receive data, the following settings have to be the same
on both transmitter and receiver:
- carrier frequency
- bandwidth
- spreading factor
- coding rate
- sync word
- preamble length
Other modules from SX126x family can also be used.
*/
// include the library
#include <RadioLib.h>
// SX1262 module is in slot A on the shield
SX1262 lora = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize SX1262 with default settings
Serial.print(F("[SX1262] Initializing ... "));
// carrier frequency: 434.0 MHz
// bandwidth: 125.0 kHz
// spreading factor: 9
// coding rate: 7
// sync word: 0x1424 (private network)
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
int state = lora.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
}
void loop() {
Serial.print(F("[SX1262] Waiting for incoming transmission ... "));
// you can receive data as an Arduino String
// NOTE: receive() is a blocking method!
// See example ReceiveInterrupt for details
// on non-blocking reception method.
String str;
int state = lora.receive(str);
// you can also receive data as byte array
/*
byte byteArr[8];
int state = lora.receive(byteArr, 8);
*/
if (state == ERR_NONE) {
// packet was successfully received
Serial.println(F("success!"));
// print the data of the packet
Serial.print("[SX1262] Data:\t\t");
Serial.println(str);
// print the RSSI (Received Signal Strength Indicator)
// of the last received packet
Serial.print("[SX1262] RSSI:\t\t");
Serial.print(lora.getRSSI());
Serial.println(" dBm");
// print the SNR (Signal-to-Noise Ratio)
// of the last received packet
Serial.print("[SX1262] SNR:\t\t");
Serial.print(lora.getSNR());
Serial.println(" dBm");
} else if (state == ERR_RX_TIMEOUT) {
// timeout occurred while waiting for a packet
Serial.println(F("timeout!"));
} else if (state == ERR_CRC_MISMATCH) {
// packet was received, but is malformed
Serial.println(F("CRC error!"));
}
}

Wyświetl plik

@ -63,14 +63,16 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// set mode to standby
int16_t state = standby();
// check packet length
if(len >= 256) {
return(ERR_PACKET_TOO_LONG);
}
uint32_t timeout = 0;
// get currently active modem
uint8_t modem = getPacketType();
if(modem == SX126X_PACKET_TYPE_LORA) {
// check packet length
if(len >= 256) {
return(ERR_PACKET_TOO_LONG);
}
// calculate timeout (150% of expected time-on-air)
float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
float sfCoeff1 = 4.25;
@ -84,59 +86,132 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
sfDivisor = 4*(_sf - 2);
}
float nSymbol = _preambleLength + sfCoeff1 + 8 + ceil(max(8.0 * len + (_crcType * 16.0) - 4.0 * _sf + sfCoeff2 + 20.0, 0.0) / sfDivisor) * (_cr + 4);
uint32_t timeout = (uint32_t)(symbolLength * nSymbol * 1.5);
DEBUG_PRINTLN(timeout);
// set DIO mapping
setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE);
timeout = (uint32_t)(symbolLength * nSymbol * 1500.0);
// set packet length
setPacketParams(_preambleLength, _crcType, len);
// set buffer pointers
setBufferBaseAddress();
// write packet to buffer
writeBuffer(data, len);
// clear interrupt flags
clearIrqStatus();
// start transmission
uint32_t timeoutValue = (uint32_t)((float)timeout / 0.015625);
setTx(timeoutValue);
//DEBUG_PRINTLN(digitalRead(_mod->getRx()));
// wait for BUSY to go low (= PA ramp up done)
while(digitalRead(_mod->getRx()));
// wait for packet transmission or timeout
uint32_t start = millis();
while(!digitalRead(_mod->getInt0())) {
if(millis() - start > timeout) {
clearIrqStatus();
return(ERR_TX_TIMEOUT);
}
}
uint32_t elapsed = millis() - start;
// update data rate
_dataRate = (len*8.0)/((float)elapsed/1000.0);
// clear interrupt flags
clearIrqStatus();
return(ERR_NONE);
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
} else {
return(ERR_UNKNOWN);
}
return(ERR_UNKNOWN);
DEBUG_PRINT(F("Timeout in "))
DEBUG_PRINT(timeout);
DEBUG_PRINTLN(F(" us"))
// set DIO mapping
setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE);
// set buffer pointers
setBufferBaseAddress();
// write packet to buffer
writeBuffer(data, len);
// clear interrupt flags
clearIrqStatus();
// start transmission
uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
setTx(timeoutValue);
// wait for BUSY to go low (= PA ramp up done)
while(digitalRead(_mod->getRx()));
// wait for packet transmission or timeout
uint32_t start = micros();
while(!digitalRead(_mod->getInt0())) {
if(micros() - start > timeout) {
clearIrqStatus();
return(ERR_TX_TIMEOUT);
}
}
uint32_t elapsed = micros() - start;
// update data rate
_dataRate = (len*8.0)/((float)elapsed/1000000.0);
// clear interrupt flags
clearIrqStatus();
return(ERR_NONE);
}
int16_t SX126x::receive(uint8_t* data, size_t len) {
// set mode to standby
int16_t state = standby();
uint32_t timeout = 0;
// get currently active modem
uint8_t modem = getPacketType();
if(modem == SX126X_PACKET_TYPE_LORA) {
// calculate timeout (100 LoRa symbols, the default for SX127x series)
float symbolLength = (float)(uint32_t(1) << _sf) / (float)_bwKhz;
timeout = (uint32_t)(symbolLength * 100.0 * 1000.0);
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
} else {
return(ERR_UNKNOWN);
}
DEBUG_PRINT(F("Timeout in "))
DEBUG_PRINT(timeout);
DEBUG_PRINTLN(F(" us"))
// set DIO mapping
setDioIrqParams(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_RX_DONE);
// set buffer pointers
setBufferBaseAddress();
// clear interrupt flags
clearIrqStatus();
// start reception
uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
setRx(timeoutValue);
// wait for packet reception or timeout
uint32_t start = micros();
while(!digitalRead(_mod->getInt0())) {
if(micros() - start > timeout) {
clearIrqStatus();
return(ERR_RX_TIMEOUT);
}
}
// check integrity CRC
uint16_t irq = getIrqStatus();
if((irq & SX126X_IRQ_CRC_ERR) || (irq & SX126X_IRQ_HEADER_ERR)) {
clearIrqStatus();
return(ERR_CRC_MISMATCH);
}
// get packet length
uint8_t rxBufStatus[2];
SPIreadCommand(SX126X_CMD_GET_RX_BUFFER_STATUS, rxBufStatus, 2);
size_t length = rxBufStatus[0];
// read packet data
if(len == 0) {
// argument 'len' equal to zero indicates String call, which means dynamically allocated data array
// dispose of the original and create a new one
delete[] data;
data = new uint8_t[length + 1];
}
readBuffer(data, length);
// add terminating null
data[length] = 0;
// clear interrupt flags
clearIrqStatus();
return(ERR_NONE);
}
int16_t SX126x::transmitDirect(uint32_t frf) {
@ -152,7 +227,8 @@ int16_t SX126x::transmitDirect(uint32_t frf) {
}
int16_t SX126x::receiveDirect() {
// SX126x is unable to ouput received data directly
return(ERR_UNKNOWN);
}
int16_t SX126x::sleep() {
@ -279,6 +355,30 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) {
return(ERR_NONE);
}
float SX126x::getRSSI() {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
return(ERR_WRONG_MODEM);
}
// get last packet RSSI from packet status
uint32_t packetStatus = getPacketStatus();
uint8_t rssiPkt = packetStatus & 0xFF;
return(-1.0 * rssiPkt/2.0);
}
float SX126x::getSNR() {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
return(ERR_WRONG_MODEM);
}
// get last packet SNR from packet status
uint32_t packetStatus = getPacketStatus();
uint8_t snrPkt = (packetStatus >> 8) & 0xFF;
return(snrPkt/4.0);
}
void SX126x::setTx(uint32_t timeout) {
uint8_t data[3] = {(uint8_t)((timeout >> 16) & 0xFF), (uint8_t)((timeout >> 8) & 0xFF), (uint8_t)(timeout & 0xFF)};
SPIwriteCommand(SX126X_CMD_SET_TX, data, 3);
@ -311,7 +411,17 @@ void SX126x::writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset) {
uint8_t* dat = new uint8_t[1 + numBytes];
dat[0] = offset;
memcpy(dat + 1, data, numBytes);
SPIwriteCommand(SX126X_CMD_WRITE_BUFFER, data, 1 + numBytes);
SPIwriteCommand(SX126X_CMD_WRITE_BUFFER, dat, 1 + numBytes);
delete[] dat;
}
void SX126x::readBuffer(uint8_t* data, uint8_t numBytes) {
// offset will be always set to 0 (one extra NOP is sent)
uint8_t* dat = new uint8_t[1 + numBytes];
dat[0] = SX126X_CMD_NOP;
memcpy(dat + 1, data, numBytes);
SPIreadCommand(SX126X_CMD_READ_BUFFER, dat, numBytes);
memcpy(data, dat + 1, numBytes);
delete[] dat;
}
@ -323,6 +433,12 @@ void SX126x::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2M
SPIwriteCommand(SX126X_CMD_SET_DIO_IRQ_PARAMS, data, 8);
}
uint16_t SX126x::getIrqStatus() {
uint8_t data[2];
SPIreadCommand(SX126X_CMD_GET_IRQ_STATUS, data, 2);
return(((uint16_t)(data[1]) << 8) | data[0]);
}
void SX126x::clearIrqStatus(uint16_t clearIrqParams) {
uint8_t data[2] = {(uint8_t)((clearIrqParams >> 8) & 0xFF), (uint8_t)(clearIrqParams & 0xFF)};
SPIwriteCommand(SX126X_CMD_CLEAR_IRQ_STATUS, data, 2);
@ -377,10 +493,10 @@ uint8_t SX126x::getStatus() {
return(data[0]);
}
uint8_t SX126x::getRssiInt() {
uint8_t data[1];
SPIreadCommand(SX126X_CMD_GET_RSSI_INST, data, 1);
return(data[0]);
uint32_t SX126x::getPacketStatus() {
uint8_t data[3];
SPIreadCommand(SX126X_CMD_GET_PACKET_STATUS, data, 3);
return((((uint32_t)data[2]) << 16) | (((uint32_t)data[1]) << 8) | (uint32_t)data[0]);
}
uint16_t SX126x::getDeviceErrors() {

Wyświetl plik

@ -340,6 +340,8 @@ class SX126x: public PhysicalLayer {
int16_t setPreambleLength(uint16_t preambleLength);
float getDataRate();
int16_t setFrequencyDeviation(float freqDev);
float getRSSI();
float getSNR();
protected:
// SX1276x SPI command implementations
@ -349,16 +351,18 @@ class SX126x: public PhysicalLayer {
void setPaConfig(uint8_t paDutyCycle, uint8_t deviceSel, uint8_t hpMax = SX126X_PA_CONFIG_HP_MAX, uint8_t paLut = SX126X_PA_CONFIG_PA_LUT);
void writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
void writeBuffer(uint8_t* data, uint8_t numBytes, uint8_t offset = 0x00);
void readBuffer(uint8_t* data, uint8_t numBytes);
void setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX126X_IRQ_NONE, uint16_t dio3Mask = SX126X_IRQ_NONE);
uint16_t getIrqStatus();
void clearIrqStatus(uint16_t clearIrqParams = 0xFFFF);
void setRfFrequency(uint32_t frf);
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 setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t payloadLength = 0xFF, uint8_t headerType = SX126X_LORA_HEADER_EXPLICIT, uint8_t invertIQ = SX126X_LORA_IQ_INVERTED);
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 setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
uint8_t getStatus();
uint8_t getRssiInt();
uint32_t getPacketStatus();
uint16_t getDeviceErrors();
void clearDeviceErrors();