[SX126x] Added FSK rx/tx, interrupt methods and CAD

This commit is contained in:
jgromes 2019-05-18 13:27:43 +02:00
parent b222883518
commit f0b9841cf6
14 changed files with 924 additions and 97 deletions

View file

@ -0,0 +1,61 @@
/*
RadioLib SX126x Channel Activity Detection Example
This example scans the current LoRa channel and detects
valid LoRa preambles. Preamble is the first part of
LoRa transmission, so this can be used to check
if the LoRa channel is free, or if you should start
receiving a message.
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
// CRC: enabled
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] Scanning channel for LoRa transmission ... "));
// start scanning current channel
int state = lora.scanChannel();
if (state == LORA_DETECTED) {
// LoRa preamble was detected
Serial.println(F(" detected!"));
} else if (state == CHANNEL_FREE) {
// no preamble was detected, channel is free
Serial.println(F(" channel is free!"));
}
// wait 100 ms before new scan
delay(100);
}

View file

@ -0,0 +1,143 @@
/*
RadioLib SX126x FSK Modem Example
This example shows how to use FSK modem in SX126x chips.
NOTE: The sketch below is just a guide on how to use
FSK modem, so this code should not be run directly!
Instead, modify the other examples to use FSK
modem and use the appropriate configuration
methods.
*/
// include the library
#include <RadioLib.h>
// SX1262 module is in slot A on the shield
SX1262 fsk = RadioShield.ModuleA;
void setup() {
Serial.begin(9600);
// initialize SX1262 FSK modem with default settings
Serial.print(F("[SX1262] Initializing ... "));
// carrier frequency: 434.0 MHz
// bit rate: 48.0 kbps
// frequency deviation: 50.0 kHz
// Rx bandwidth: 117.3 kHz
// output power: 14 dBm
// current limit: 60.0 mA
// preamble length: 16 bits
// data shaping: Gaussian, BT = 0.5
// sync word: 0x2D 0x01
// CRC: enabled, CRC16 (CCIT)
int state = fsk.beginFSK();
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 FSK modes
//
// lora.begin() start LoRa mode (and disable FSK)
// lora.beginFSK() start FSK mode (and disable LoRa)
// the following settings can also
// be modified at run-time
state = fsk.setFrequency(433.5);
state = fsk.setBitRate(100.0);
state = fsk.setFrequencyDeviation(10.0);
state = fsk.setRxBandwidth(250.0);
state = fsk.setOutputPower(10.0);
state = fsk.setCurrentLimit(100.0);
state = fsk.setDataShaping(1.0);
uint8_t syncWord[] = {0x01, 0x23, 0x45, 0x67,
0x89, 0xAB, 0xCD, 0xEF};
state = fsk.setSyncWord(syncWord, 8);
if (state != ERR_NONE) {
Serial.print(F("Unable to set configuration, code "));
Serial.println(state);
while (true);
}
// FSK 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 = fsk.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() {
// FSK modem can use the same transmit/receive methods
// as the LoRa modem, even their interrupt-driven versions
// transmit FSK packet
int state = fsk.transmit("Hello World!");
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
0x78, 0xAB, 0xCD, 0xEF};
int state = lora.transmit(byteArr, 8);
*/
if (state == ERR_NONE) {
Serial.println(F("[SX1262] Packet transmitted successfully!"));
} else if (state == ERR_PACKET_TOO_LONG) {
Serial.println(F("[SX1262] Packet too long!"));
} else if (state == ERR_TX_TIMEOUT) {
Serial.println(F("[SX1262] Timed out while transmitting!"));
} else {
Serial.println(F("[SX1262] Failed to transmit packet, code "));
Serial.println(state);
}
// receive FSK packet
String str;
state = fsk.receive(str);
/*
byte byteArr[8];
int state = lora.receive(byteArr, 8);
*/
if (state == ERR_NONE) {
Serial.println(F("[SX1262] Received packet!"));
Serial.print(F("[SX1262] Data:\t"));
Serial.println(str);
} else if (state == ERR_RX_TIMEOUT) {
Serial.println(F("[SX1262] Timed out while waiting for packet!"));
} else {
Serial.println(F("[SX1262] Failed to receive packet, code "));
Serial.println(state);
}
// FSK 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:
//
// fsk.transmit("Hello World!", address);
// fsk.startTransmit("Hello World!", address);
// set node address to 0x02
state = fsk.setNodeAddress(0x02);
// set broadcast address to 0xFF
state = fsk.setBroadcastAddress(0xFF);
if (state != ERR_NONE) {
Serial.println(F("[SX1262] 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 = fsk.disableAddressFiltering();
if (state != ERR_NONE) {
Serial.println(F("Unable to remove address filter, code "));
}
*/
}

View file

@ -33,6 +33,7 @@ void setup() {
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));

View file

@ -0,0 +1,141 @@
/*
RadioLib SX126x Receive with Inerrupts Example
This example listens for LoRa transmissions and tries to
receive them. Once a packet is received, an interrupt is
triggered. 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
Other modules from SX126x/RFM9x 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
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set the function that will be called
// when new packet is received
lora.setDio1Action(setFlag);
// start listening for LoRa packets
Serial.print(F("[SX1262] Starting to listen ... "));
state = lora.startReceive();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// if needed, 'listen' mode can be disabled by calling
// any of the following methods:
//
// lora.standby()
// lora.sleep()
// lora.transmit();
// lora.receive();
// lora.scanChannel();
}
// flag to indicate that a packet was received
volatile bool receivedFlag = false;
// disable interrupt when it's not needed
volatile bool enableInterrupt = true;
// this function is called when a complete packet
// is received by the module
// IMPORTANT: this function MUST be 'void' type
// and MUST NOT have any arguments!
void setFlag(void) {
// check if the interrupt is enabled
if(!enableInterrupt) {
return;
}
// we got a packet, set the flag
receivedFlag = true;
}
void loop() {
// check if the flag is set
if(receivedFlag) {
// disable the interrupt service routine while
// processing the data
enableInterrupt = false;
// reset flag
receivedFlag = false;
// you can read received data as an Arduino String
String str;
int state = lora.readData(str);
// you can also read received data as byte array
/*
byte byteArr[8];
int state = lora.receive(byteArr, 8);
*/
if (state == ERR_NONE) {
// packet was successfully received
Serial.println(F("[SX1262] Received packet!"));
// print data of the packet
Serial.print(F("[SX1262] Data:\t\t"));
Serial.println(str);
// print RSSI (Received Signal Strength Indicator)
Serial.print(F("[SX1262] RSSI:\t\t"));
Serial.print(lora.getRSSI());
Serial.println(" dBm");
// print SNR (Signal-to-Noise Ratio)
Serial.print(F("[SX1262] SNR:\t\t"));
Serial.print(lora.getSNR());
Serial.println(F(" dBm"));
} else if (state == ERR_CRC_MISMATCH) {
// packet was received, but is malformed
Serial.println(F("CRC error!"));
}
// we're ready to receive more packets,
// enable interrupt service routine
enableInterrupt = true;
}
}

View file

@ -0,0 +1,137 @@
/*
RadioLib SX126x Settings Example
This example shows how to change all the properties of LoRa transmission.
RadioLib currently supports the following settings:
- pins (SPI slave select, digital IO 0, digital IO 1)
- carrier frequency
- bandwidth
- spreading factor
- coding rate
- sync word
- output power during transmission
- CRC
- preamble length
Other modules from SX126x family can also be used.
*/
// include the library
#include <RadioLib.h>
// SX1268 module is in slot A on the shield
SX1268 loraSX1268 = RadioShield.ModuleA;
// SX1262 module is in slot B on the shield
SX1262 loraSX1262 = RadioShield.ModuleB;
void setup() {
Serial.begin(9600);
// initialize SX1268 with default settings
Serial.print(F("[SX1268] 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
// CRC: enabled
int state = loraSX1268.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// initialize the second LoRa instance with
// non-default settings
// this LoRa link will have high data rate,
// but lower range
Serial.print(F("[SX1262] Initializing ... "));
// carrier frequency: 915.0 MHz
// bandwidth: 500.0 kHz
// spreading factor: 6
// coding rate: 5
// sync word: 0x3444 (public network)
// output power: 2 dBm
// current limit: 50 mA
// preamble length: 20 symbols
// CRC: enabled
state = loraSX1262.begin(915.0, 500.0, 6, 5, 0x3444, 50, 20);
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// you can also change the settings at runtime
// and check if the configuration was changed successfully
// set carrier frequency to 433.5 MHz
if (loraSX1268.setFrequency(433.5) == ERR_INVALID_FREQUENCY) {
Serial.println(F("Selected frequency is invalid for this module!"));
while (true);
}
// set bandwidth to 250 kHz
if (loraSX1268.setBandwidth(250.0) == ERR_INVALID_BANDWIDTH) {
Serial.println(F("Selected bandwidth is invalid for this module!"));
while (true);
}
// set spreading factor to 10
if (loraSX1268.setSpreadingFactor(10) == ERR_INVALID_SPREADING_FACTOR) {
Serial.println(F("Selected spreading factor is invalid for this module!"));
while (true);
}
// set coding rate to 6
if (loraSX1268.setCodingRate(6) == ERR_INVALID_CODING_RATE) {
Serial.println(F("Selected coding rate is invalid for this module!"));
while (true);
}
// set LoRa sync word to 0x1234
if (loraSX1268.setSyncWord(0x1234) != ERR_NONE) {
Serial.println(F("Unable to set sync word!"));
while (true);
}
// set output power to 10 dBm (accepted range is -17 - 22 dBm)
if (loraSX1268.setOutputPower(10) == ERR_INVALID_OUTPUT_POWER) {
Serial.println(F("Selected output power is invalid for this module!"));
while (true);
}
// set over current protection limit to 80 mA (accepted range is 45 - 240 mA)
// NOTE: set value to 0 to disable overcurrent protection
if (loraSX1268.setCurrentLimit(80) == ERR_INVALID_CURRENT_LIMIT) {
Serial.println(F("Selected current limit is invalid for this module!"));
while (true);
}
// set LoRa preamble length to 15 symbols (accepted range is 0 - 65535)
if (loraSX1268.setPreambleLength(15) == ERR_INVALID_PREAMBLE_LENGTH) {
Serial.println(F("Selected preamble length is invalid for this module!"));
while (true);
}
// disable CRC
if (loraSX1268.setCRC(false) == ERR_INVALID_CRC) {
Serial.println(F("Selected CRC is invalid for this module!"));
while (true);
}
Serial.println(F("All settings succesfully changed!"));
}
void loop() {
// nothing here
}

View file

@ -29,6 +29,7 @@ void setup() {
// output power: 14 dBm
// current limit: 60 mA
// preamble length: 8 symbols
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));

View file

@ -0,0 +1,107 @@
/*
RadioLib SX126x Transmit with Inerrupts Example
This example transmits LoRa packets with one second delays
between them. Each packet contains up to 256 bytes
of data, in the form of:
- Arduino String
- null-terminated char array (C-string)
- arbitrary binary data (byte array)
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
// CRC: enabled
int state = lora.begin();
if (state == ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while (true);
}
// set the function that will be called
// when packet transmission is finished
lora.setDio1Action(setFlag);
// start transmitting the first packet
Serial.print(F("[SX1262] Sending first packet ... "));
// you can transmit C-string or Arduino string up to
// 256 characters long
state = lora.startTransmit("Hello World!");
// you can also transmit byte array up to 256 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
0x78, 0xAB, 0xCD, 0xEF};
state = lora.transmit(byteArr, 8);
*/
if (state != ERR_NONE) {
Serial.print(F("failed, code "));
Serial.println(state);
}
}
// flag to indicate that a packet was received
volatile bool transmittedFlag = false;
void setFlag(void) {
// packet transmission is finished, set the flag
transmittedFlag = true;
}
void loop() {
// check if the previous transmission finished
if(transmittedFlag) {
Serial.println(F("packet transmission finished!"));
// wait one second before next transmission
delay(1000);
// send another packet
Serial.print(F("[SX1262] Sending another packet ... "));
// you can transmit C-string or Arduino string up to
// 256 characters long
int state = lora.startTransmit("Hello World!");
// you can also transmit byte array up to 256 bytes long
/*
byte byteArr[] = {0x01, 0x23, 0x45, 0x56,
0x78, 0xAB, 0xCD, 0xEF};
int state = lora.startTransmit(byteArr, 8);
*/
// NOTE: when using interrupt-driven transmit method,
// it is not possible to automatically measure
// transmission data rate using getDataRate()
if (state != ERR_NONE) {
Serial.print(F("failed, code "));
Serial.println(state);
}
}
}

View file

@ -197,3 +197,6 @@ ERR_INVALID_RTTY_SHIFT LITERAL1
ERR_UNSUPPORTED_ENCODING LITERAL1
ERR_INVALID_NUM_BROAD_ADDRS LITERAL1
ERR_INVALID_CRC LITERAL1
LORA_DETECTED LITERAL1

View file

@ -13,7 +13,9 @@
#include "modules/RFM96.h"
#include "modules/RFM97.h"
#include "modules/SX1231.h"
#include "modules/SX1261.h"
#include "modules/SX1262.h"
#include "modules/SX1268.h"
#include "modules/SX1272.h"
#include "modules/SX1273.h"
#include "modules/SX1276.h"

View file

@ -108,4 +108,8 @@
// CC1101-specific status codes
#define ERR_INVALID_NUM_BROAD_ADDRS -601
// SX126x-specific status codes
#define ERR_INVALID_CRC -701
#define LORA_DETECTED -702
#endif

16
src/modules/SX1261.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef _RADIOLIB_SX1261_H
#define _RADIOLIB_SX1261_H
#include "TypeDef.h"
#include "Module.h"
#include "SX126x.h"
#include "SX1262.h"
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
// TODO: implement SX1261 class
using SX1261 = SX1262;
#endif

16
src/modules/SX1268.h Normal file
View file

@ -0,0 +1,16 @@
#ifndef _RADIOLIB_SX1268_H
#define _RADIOLIB_SX1268_H
#include "TypeDef.h"
#include "Module.h"
#include "SX126x.h"
#include "SX1262.h"
//SX126X_CMD_SET_PA_CONFIG
#define SX126X_PA_CONFIG_SX1261 0x01
#define SX126X_PA_CONFIG_SX1262 0x00
// TODO: implement SX1268 class
using SX1268 = SX1262;
#endif

View file

@ -65,12 +65,13 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
pinMode(_mod->getRx(), INPUT);
// initialize configuration variables (will be overwritten during public settings configuration)
_br = 21333;
_freqDev = 52429;
_br = 21333; // 48.0 kbps
_freqDev = 52428; // 50.0 kHz
_rxBw = SX126X_GFSK_RX_BW_117_3;
_pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5;
_crcTypeFSK = SX126X_GFSK_CRC_1_BYTE;
_crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV; // CCIT CRC configuration
_preambleLengthFSK = preambleLength;
_addrComp = SX126X_GFSK_ADDRESS_FILT_OFF;
// get status and errors
getStatus();
@ -110,8 +111,7 @@ int16_t SX126x::beginFSK(float br, float freqDev, float rxBw, uint16_t preambleL
// set default sync word 0x2D01 - not a beginFSK attribute
uint8_t sync[] = {0x2D, 0x01};
_syncWordLength = 2;
state = setSyncWord(sync, _syncWordLength);
state = setSyncWord(sync, 2);
if(state != ERR_NONE) {
return(state);
}
@ -148,37 +148,22 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
float nSymbol = _preambleLength + sfCoeff1 + 8 + ceil(max(8.0 * len + (_crcType * 16.0) - 4.0 * _sf + sfCoeff2 + 20.0, 0.0) / sfDivisor) * (_cr + 4);
timeout = (uint32_t)(symbolLength * nSymbol * 1500.0);
// set packet length
setPacketParams(_preambleLength, _crcType, len);
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
// calculate timeout (500% of expected time-on-air)
float brBps = ((float)(SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br;
timeout = (uint32_t)(((len * 8.0) / brBps) * 1000000.0 * 5.0);
} else {
return(ERR_UNKNOWN);
}
DEBUG_PRINT(F("Timeout in "))
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();
DEBUG_PRINTLN(F(" us"));
// 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()));
startTransmit(data, len, addr);
// wait for packet transmission or timeout
uint32_t start = micros();
@ -196,6 +181,9 @@ int16_t SX126x::transmit(uint8_t* data, size_t len, uint8_t addr) {
// clear interrupt flags
clearIrqStatus();
// set mode to standby to disable transmitter
standby();
return(ERR_NONE);
}
@ -213,27 +201,25 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
timeout = (uint32_t)(symbolLength * 100.0 * 1000.0);
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
// calculate timeout (500 % of expected time-one-air)
size_t maxLen = len;
if(len == 0) {
maxLen = 0xFF;
}
float brBps = ((float)(SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / (float)_br;
timeout = (uint32_t)(((maxLen * 8.0) / brBps) * 1000000.0 * 5.0);
} else {
return(ERR_UNKNOWN);
}
DEBUG_PRINT(F("Timeout in "))
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();
DEBUG_PRINTLN(F(" us"));
// start reception
uint32_t timeoutValue = (uint32_t)((float)timeout / 15.625);
setRx(timeoutValue);
startReceive(timeoutValue);
// wait for packet reception or timeout
uint32_t start = micros();
@ -244,6 +230,132 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
}
}
// read the received data
return(readData(data, len));
}
int16_t SX126x::transmitDirect(uint32_t frf) {
// user requested to start transmitting immediately (required for RTTY)
if(frf != 0) {
setRfFrequency(frf);
}
// start transmitting
uint8_t data[] = {SX126X_CMD_NOP};
SPIwriteCommand(SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1);
return(ERR_NONE);
}
int16_t SX126x::receiveDirect() {
// SX126x is unable to ouput received data directly
return(ERR_UNKNOWN);
}
int16_t SX126x::scanChannel() {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
return(ERR_WRONG_MODEM);
}
// set mode to standby
standby();
// set DIO pin mapping
setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED);
// clear interrupt flags
clearIrqStatus();
// set mode to CAD
setCad();
// wait for channel activity detected or timeout
while(!digitalRead(_mod->getInt0())) {
if(digitalRead(_mod->getInt1())) {
clearIrqStatus();
return(LORA_DETECTED);
}
}
// clear interrupt flags
clearIrqStatus();
return(CHANNEL_FREE);
}
int16_t SX126x::sleep() {
uint8_t data[] = {SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF};
SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1);
// wait for SX126x to safely enter sleep mode
delayMicroseconds(500);
return(ERR_NONE);
}
int16_t SX126x::standby(uint8_t mode) {
uint8_t data[] = {mode};
SPIwriteCommand(SX126X_CMD_SET_STANDBY, data, 1);
return(ERR_NONE);
}
void SX126x::setDio1Action(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt0()), func, RISING);
}
void SX126x::setDio2Action(void (*func)(void)) {
attachInterrupt(digitalPinToInterrupt(_mod->getInt1()), func, RISING);
}
int16_t SX126x::startTransmit(uint8_t* data, size_t len, uint8_t addr) {
// set packet Length
uint8_t modem = getPacketType();
if(modem == SX126X_PACKET_TYPE_LORA) {
setPacketParams(_preambleLength, _crcType, len);
} else if(modem == SX126X_PACKET_TYPE_LORA) {
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp, len);
} else {
return(ERR_UNKNOWN);
}
// 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
setTx(0x000000);
// wait for BUSY to go low (= PA ramp up done)
while(digitalRead(_mod->getRx()));
return(ERR_NONE);
}
int16_t SX126x::startReceive(uint32_t timeout) {
// set DIO mapping
setDioIrqParams(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_RX_DONE);
// set buffer pointers
setBufferBaseAddress();
// clear interrupt flags
clearIrqStatus();
// set mode to receive
setRx(timeout);
return(ERR_NONE);
}
int16_t SX126x::readData(uint8_t* data, size_t len) {
// check integrity CRC
uint16_t irq = getIrqStatus();
if((irq & SX126X_IRQ_CRC_ERR) || (irq & SX126X_IRQ_HEADER_ERR)) {
@ -274,39 +386,6 @@ int16_t SX126x::receive(uint8_t* data, size_t len) {
return(ERR_NONE);
}
int16_t SX126x::transmitDirect(uint32_t frf) {
// user requested to start transmitting immediately (required for RTTY)
if(frf != 0) {
setRfFrequency(frf);
}
// start transmitting
uint8_t data[] = {SX126X_CMD_NOP};
SPIwriteCommand(SX126X_CMD_SET_TX_CONTINUOUS_WAVE, data, 1);
return(ERR_NONE);
}
int16_t SX126x::receiveDirect() {
// SX126x is unable to ouput received data directly
return(ERR_UNKNOWN);
}
int16_t SX126x::sleep() {
uint8_t data[] = {SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF};
SPIwriteCommand(SX126X_CMD_SET_SLEEP, data, 1);
// wait for SX126x to safely enter sleep mode
delayMicroseconds(500);
return(ERR_NONE);
}
int16_t SX126x::standby(uint8_t mode) {
uint8_t data[] = {mode};
SPIwriteCommand(SX126X_CMD_SET_STANDBY, data, 1);
return(ERR_NONE);
}
int16_t SX126x::setBandwidth(float bw) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
@ -407,7 +486,7 @@ int16_t SX126x::setPreambleLength(uint16_t preambleLength) {
return(ERR_NONE);
} else if(modem == SX126X_PACKET_TYPE_GFSK) {
_preambleLengthFSK = preambleLength;
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength);
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
return(ERR_NONE);
}
@ -426,7 +505,8 @@ int16_t SX126x::setFrequencyDeviation(float freqDev) {
}
// calculate raw frequency deviation value
_freqDev = (uint32_t)((freqDev * 1000.0) / ((SX126X_CRYSTAL_FREQ * 1000000.0) / (float)((uint32_t)(1) << 25)));
//_freqDev = (uint32_t)((freqDev * 1000.0) / ((SX126X_CRYSTAL_FREQ * 1000000.0) / (float)((uint32_t)(1) << 25)));
_freqDev = (uint32_t)(((freqDev * 1000.0) * (float)((uint32_t)(1) << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0));
// update modulation parameters
setModulationParamsFSK(_br, _pulseShape, _rxBw, _freqDev);
@ -520,15 +600,16 @@ int16_t SX126x::setDataShaping(float sh) {
}
// check allowed values
sh *= 10.0;
if(abs(sh - 0.0) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_NONE;
} else if(abs(sh - 0.3) <= 0.001) {
} else if(abs(sh - 3.0) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_GAUSS_0_3;
} else if(abs(sh - 0.5) <= 0.001) {
} else if(abs(sh - 5.0) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5;
} else if(abs(sh - 0.7) <= 0.001) {
} else if(abs(sh - 7.0) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_GAUSS_0_7;
} else if(abs(sh - 1.0) <= 0.001) {
} else if(abs(sh - 10.0) <= 0.001) {
_pulseShape = SX126X_GFSK_FILTER_GAUSS_1;
} else {
return(ERR_INVALID_DATA_SHAPING);
@ -555,8 +636,112 @@ int16_t SX126x::setSyncWord(uint8_t* syncWord, uint8_t len) {
writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, len);
// update packet parameters
_syncWordLength = len;
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength);
_syncWordLength = len * 8;
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
return(ERR_NONE);
}
int16_t SX126x::setNodeAddress(uint8_t nodeAddr) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// enable address filtering (node only)
_addrComp = SX126X_GFSK_ADDRESS_FILT_NODE;
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
// set node address
writeRegister(SX126X_REG_NODE_ADDRESS, &nodeAddr, 1);
return(ERR_NONE);
}
int16_t SX126x::setBroadcastAddress(uint8_t broadAddr) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// enable address filtering (node and broadcast)
_addrComp = SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST;
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
// set broadcast address
writeRegister(SX126X_REG_BROADCAST_ADDRESS, &broadAddr, 1);
return(ERR_NONE);
}
int16_t SX126x::disableAddressFiltering() {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// disable address filtering
_addrComp = SX126X_GFSK_ADDRESS_FILT_OFF;
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
return(ERR_NONE);
}
int16_t SX126x::setCRC(bool enableCRC) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_LORA) {
return(ERR_WRONG_MODEM);
}
// update packet parameters
if(enableCRC) {
_crcType = SX126X_LORA_CRC_ON;
} else {
_crcType = SX126X_LORA_CRC_OFF;
}
setPacketParams(_preambleLength, _crcType);
return(ERR_NONE);
}
int16_t SX126x::setCRC(uint8_t len, uint16_t initial, uint16_t polynomial, bool inverted) {
// check active modem
if(getPacketType() != SX126X_PACKET_TYPE_GFSK) {
return(ERR_WRONG_MODEM);
}
// update packet parameters
switch(len) {
case 0:
_crcTypeFSK = SX126X_GFSK_CRC_OFF;
break;
case 1:
if(inverted) {
_crcTypeFSK = SX126X_GFSK_CRC_1_BYTE_INV;
} else {
_crcTypeFSK = SX126X_GFSK_CRC_1_BYTE;
}
break;
case 2:
if(inverted) {
_crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV;
} else {
_crcTypeFSK = SX126X_GFSK_CRC_2_BYTE;
}
break;
default:
return(ERR_INVALID_CRC);
}
setPacketParamsFSK(_preambleLengthFSK, _crcTypeFSK, _syncWordLength, _addrComp);
// write initial CRC value
uint8_t data[2] = {(uint8_t)((initial >> 8) & 0xFF), (uint8_t)(initial & 0xFF)};
writeRegister(SX126X_REG_CRC_INITIAL_MSB, data, 2);
// write CRC polynomial value
data[0] = (uint8_t)((polynomial >> 8) & 0xFF);
data[1] = (uint8_t)(polynomial & 0xFF);
writeRegister(SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2);
return(ERR_NONE);
}
@ -566,11 +751,6 @@ float SX126x::getDataRate() {
}
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;
@ -630,7 +810,7 @@ void SX126x::readBuffer(uint8_t* data, uint8_t numBytes) {
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);
SPIreadCommand(SX126X_CMD_READ_BUFFER, dat, 1 + numBytes);
memcpy(data, dat + 1, numBytes);
delete[] dat;
}
@ -699,11 +879,11 @@ void SX126x::setPacketParams(uint16_t preambleLength, uint8_t crcType, uint8_t p
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) {
void SX126x::setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t payloadLength, uint8_t packetType, 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);
SPIwriteCommand(SX126X_CMD_SET_PACKET_PARAMS, data, 9);
}
void SX126x::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) {
@ -768,7 +948,7 @@ int16_t SX126x::config() {
// 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);
SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
// set regulator mode
data[0] = SX126X_REGULATOR_DC_DC;
@ -810,7 +990,7 @@ 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);
SPIwriteCommand(SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL, data, 1);
// set regulator mode
data[0] = SX126X_REGULATOR_DC_DC;

View file

@ -318,6 +318,8 @@ class SX126x: public PhysicalLayer {
// introduce PhysicalLayer overloads
using PhysicalLayer::transmit;
using PhysicalLayer::receive;
using PhysicalLayer::startTransmit;
using PhysicalLayer::readData;
// constructor
SX126x(Module* mod);
@ -329,9 +331,17 @@ class SX126x: public PhysicalLayer {
int16_t receive(uint8_t* data, size_t len);
int16_t transmitDirect(uint32_t frf = 0);
int16_t receiveDirect();
int16_t scanChannel();
int16_t sleep();
int16_t standby(uint8_t mode = SX126X_STANDBY_RC);
// interrupt methods
void setDio1Action(void (*func)(void));
void setDio2Action(void (*func)(void));
int16_t startTransmit(uint8_t* data, size_t len, uint8_t addr = 0);
int16_t startReceive(uint32_t timeout = 0xFFFFFF);
int16_t readData(uint8_t* data, size_t len);
// configuration methods
int16_t setBandwidth(float bw);
int16_t setSpreadingFactor(uint8_t sf);
@ -344,6 +354,11 @@ class SX126x: public PhysicalLayer {
int16_t setRxBandwidth(float rxBw);
int16_t setDataShaping(float sh);
int16_t setSyncWord(uint8_t* syncWord, uint8_t len);
int16_t setNodeAddress(uint8_t nodeAddr);
int16_t setBroadcastAddress(uint8_t broadAddr);
int16_t disableAddressFiltering();
int16_t setCRC(bool enableCRC);
int16_t setCRC(uint8_t len, uint16_t initial = 0x1D0F, uint16_t polynomial = 0x1021, bool inverted = true);
float getDataRate();
float getRSSI();
float getSNR();
@ -359,14 +374,14 @@ class SX126x: public PhysicalLayer {
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 clearIrqStatus(uint16_t clearIrqParams = SX126X_IRQ_ALL);
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 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 setPacketParamsFSK(uint16_t preambleLength, uint8_t crcType, uint8_t syncWordLength, uint8_t addrComp, uint8_t payloadLength = 0xFF, uint8_t packetType = SX126X_GFSK_PACKET_VARIABLE, uint8_t preambleDetectorLength = SX126X_GFSK_PREAMBLE_DETECT_16, uint8_t whitening = SX126X_GFSK_WHITENING_ON);
void setBufferBaseAddress(uint8_t txBaseAddress = 0x00, uint8_t rxBaseAddress = 0x00);
uint8_t getStatus();
uint32_t getPacketStatus();
@ -383,7 +398,7 @@ class SX126x: public PhysicalLayer {
float _bwKhz;
uint32_t _br, _freqDev;
uint8_t _rxBw, _pulseShape, _crcTypeFSK, _syncWordLength;
uint8_t _rxBw, _pulseShape, _crcTypeFSK, _syncWordLength, _addrComp;
uint16_t _preambleLengthFSK;
float _dataRate;