This is a copy of the community maintained fork of the open firmware which powers RNode devices. This version will have support for the hardware made by Mees Electronics.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1486 lines
38 KiB

7 years ago
// Copyright (c) Sandeep Mistry. All rights reserved.
// Licensed under the MIT license.
// Modifications and additions copyright 2023 by Mark Qvist
// Obviously still under the MIT license.
7 years ago
#include "LoRa.h"
#include "Modem.h"
7 years ago
#define MCU_1284P 0x91
#define MCU_2560 0x92
#define MCU_ESP32 0x81
#define MCU_NRF52 0x71
#if defined(__AVR_ATmega1284P__)
#define PLATFORM PLATFORM_AVR
#define MCU_VARIANT MCU_1284P
#elif defined(__AVR_ATmega2560__)
#define PLATFORM PLATFORM_AVR
#define MCU_VARIANT MCU_2560
#elif defined(ESP32)
#define PLATFORM PLATFORM_ESP32
#define MCU_VARIANT MCU_ESP32
#elif defined(nRF52)
#define PLATFORM PLATFORM_NRF52
#define MCU_VARIANT MCU_NRF52
#endif
#ifndef MCU_VARIANT
#error No MCU variant defined, cannot compile
#endif
#if MCU_VARIANT == MCU_ESP32
#include "soc/rtc_wdt.h"
#define ISR_VECT IRAM_ATTR
#else
#define ISR_VECT
#endif
#if MODEM == SX1262
#define OP_FIFO_WRITE 0x0E
#define OP_FIFO_READ 0x1E
#define OP_RF_FREQ 0x86
#define OP_SLEEP 0x84
#define OP_STANDBY 0x80
#define OP_TX 0x83
#define OP_RX 0x82
#define OP_PA_CONFIG 0x95
#define OP_SET_IRQ_FLAGS 0x08 // also provides info such as
// preamble detection, etc for
// knowing when it's safe to switch
// antenna modes
#define OP_CLEAR_IRQ_STATUS 0x02
#define OP_GET_IRQ_STATUS 0x12
#define OP_RX_BUFFER_STATUS 0x13
#define OP_PACKET_STATUS 0x14 // get snr & rssi of last packet
#define OP_CURRENT_RSSI 0x15
#define OP_MODULATION_PARAMS 0x8B // bw, sf, cr, etc.
#define OP_PACKET_PARAMS 0x8C // crc, preamble, payload length, etc.
#define OP_STATUS 0xC0
#define OP_TX_PARAMS 0x8E // set dbm, etc
#define OP_PACKET_TYPE 0x8A
#define OP_BUFFER_BASE_ADDR 0x8F
#define OP_READ_REGISTER 0x1D
#define OP_WRITE_REGISTER 0x0D
#define OP_DIO3_TCXO_CTRL 0x97
#define OP_DIO2_RF_CTRL 0x9D
#define OP_CALIBRATE 0x89
#define REG_OCP 0x08E7
#define REG_LNA 0x08AC // no agc in sx1262
#define REG_SYNC_WORD_MSB 0x0740
#define REG_SYNC_WORD_LSB 0x0741
#define REG_PAYLOAD_LENGTH 0x0702 // https://github.com/beegee-tokyo/SX126x-Arduino/blob/master/src/radio/sx126x/sx126x.h#L98
#define REG_RANDOM_GEN 0x0819
#define MODE_LONG_RANGE_MODE 0x01
#define MODE_TCXO_3_3V 0x07
#define IRQ_TX_DONE_MASK 0x01
#define IRQ_RX_DONE_MASK 0x02
#define IRQ_PREAMBLE_DET_MASK 0x04
#define IRQ_HEADER_DET_MASK 0x10
#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x40
#define XTAL_FREQ (double)32000000
#define FREQ_DIV (double)pow(2.0, 25.0)
#define FREQ_STEP (double)(XTAL_FREQ / FREQ_DIV)
int fifo_tx_addr_ptr = 0;
int fifo_rx_addr_ptr = 0;
uint8_t packet[256] = {0};
#elif MODEM == SX1276 || MODEM == SX1278
// Registers
#define REG_FIFO 0x00
#define REG_OP_MODE 0x01
#define REG_FRF_MSB 0x06
#define REG_FRF_MID 0x07
#define REG_FRF_LSB 0x08
#define REG_PA_CONFIG 0x09
#define REG_OCP 0x0b
#define REG_LNA 0x0c
#define REG_FIFO_ADDR_PTR 0x0d
#define REG_FIFO_TX_BASE_ADDR 0x0e
#define REG_FIFO_RX_BASE_ADDR 0x0f
#define REG_FIFO_RX_CURRENT_ADDR 0x10
#define REG_IRQ_FLAGS 0x12
#define REG_RX_NB_BYTES 0x13
#define REG_MODEM_STAT 0x18
#define REG_PKT_SNR_VALUE 0x19
#define REG_PKT_RSSI_VALUE 0x1a
#define REG_RSSI_VALUE 0x1b
#define REG_MODEM_CONFIG_1 0x1d
#define REG_MODEM_CONFIG_2 0x1e
#define REG_PREAMBLE_MSB 0x20
#define REG_PREAMBLE_LSB 0x21
#define REG_PAYLOAD_LENGTH 0x22
#define REG_MODEM_CONFIG_3 0x26
#define REG_FREQ_ERROR_MSB 0x28
#define REG_FREQ_ERROR_MID 0x29
#define REG_FREQ_ERROR_LSB 0x2a
#define REG_RSSI_WIDEBAND 0x2c
#define REG_DETECTION_OPTIMIZE 0x31
#define REG_HIGH_BW_OPTIMIZE_1 0x36
#define REG_DETECTION_THRESHOLD 0x37
#define REG_SYNC_WORD 0x39
#define REG_HIGH_BW_OPTIMIZE_2 0x3a
#define REG_DIO_MAPPING_1 0x40
#define REG_VERSION 0x42
#define REG_TCXO 0x4b
#define REG_PA_DAC 0x4d
// Modes
#define MODE_LONG_RANGE_MODE 0x80
#define MODE_SLEEP 0x00
#define MODE_STDBY 0x01
#define MODE_TX 0x03
#define MODE_RX_CONTINUOUS 0x05
#define MODE_RX_SINGLE 0x06
// PA config
#define PA_BOOST 0x80
// IRQ masks
#define IRQ_TX_DONE_MASK 0x08
#define IRQ_PAYLOAD_CRC_ERROR_MASK 0x20
#define IRQ_RX_DONE_MASK 0x40
#endif
7 years ago
#define MAX_PKT_LENGTH 255
extern SPIClass spiModem;
bool lora_preinit_done = false;
7 years ago
LoRaClass::LoRaClass() :
_spiSettings(8E6, MSBFIRST, SPI_MODE0),
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN), _rxen(LORA_DEFAULT_RXEN_PIN), _busy(LORA_DEFAULT_BUSY_PIN),
7 years ago
_frequency(0),
_txp(0),
_sf(0x07),
_bw(0x04),
_cr(0x01),
_ldro(0x00),
7 years ago
_packetIndex(0),
_preambleLength(18),
7 years ago
_implicitHeaderMode(0),
_payloadLength(255),
_crcMode(1),
7 years ago
_onReceive(NULL)
{
// overide Stream timeout value
setTimeout(0);
}
bool LoRaClass::preInit() {
7 years ago
// setup pins
pinMode(_ss, OUTPUT);
// set SS high
digitalWrite(_ss, HIGH);
spiModem.begin();
// check version (retry for up to 2 seconds)
#if MODEM == SX1276 || MODEM == SX1278
uint8_t version;
long start = millis();
while (((millis() - start) < 2000) && (millis() >= start)) {
version = readRegister(REG_VERSION);
if (version == 0x12) {
break;
}
delay(100);
}
if (version != 0x12) {
return false;
}
lora_preinit_done = true;
return true;
#elif MODEM == SX1262
long start = millis();
uint8_t syncmsb;
uint8_t synclsb;
while (((millis() - start) < 2000) && (millis() >= start)) {
syncmsb = readRegister(REG_SYNC_WORD_MSB);
synclsb = readRegister(REG_SYNC_WORD_LSB);
if ( uint16_t(syncmsb << 8 | synclsb) == 0x1424 || uint16_t(syncmsb << 8 | synclsb) == 0x4434) {
break;
}
delay(100);
}
if ( uint16_t(syncmsb << 8 | synclsb) != 0x1424 && uint16_t(syncmsb << 8 | synclsb) != 0x4434) {
return false;
}
lora_preinit_done = true;
return true;
#else
return false;
#endif
}
7 years ago
#if MODEM == SX1276 || MODEM == SX1278
uint8_t ISR_VECT LoRaClass::readRegister(uint8_t address)
{
return singleTransfer(address & 0x7f, 0x00);
}
void LoRaClass::writeRegister(uint8_t address, uint8_t value)
{
singleTransfer(address | 0x80, value);
}
uint8_t ISR_VECT LoRaClass::singleTransfer(uint8_t address, uint8_t value)
{
uint8_t response;
digitalWrite(_ss, LOW);
spiModem.beginTransaction(_spiSettings);
spiModem.transfer(address);
response = spiModem.transfer(value);
spiModem.endTransaction();
digitalWrite(_ss, HIGH);
return response;
}
#elif MODEM == SX1262
uint8_t ISR_VECT LoRaClass::readRegister(uint16_t address)
{
return singleTransfer(OP_READ_REGISTER, address, 0x00);
}
void LoRaClass::writeRegister(uint16_t address, uint8_t value)
{
singleTransfer(OP_WRITE_REGISTER, address, value);
}
uint8_t ISR_VECT LoRaClass::singleTransfer(uint8_t opcode, uint16_t address, uint8_t value)
{
waitOnBusy();
uint8_t response;
digitalWrite(_ss, LOW);
spiModem.beginTransaction(_spiSettings);
spiModem.transfer(opcode);
spiModem.transfer((address & 0xFF00) >> 8);
spiModem.transfer(address & 0x00FF);
if (opcode == OP_READ_REGISTER) {
spiModem.transfer(0x00);
}
response = spiModem.transfer(value);
spiModem.endTransaction();
digitalWrite(_ss, HIGH);
return response;
}
void LoRaClass::enableAntenna()
{
uint8_t byte = 0x01;
// enable dio2 rf switch
executeOpcode(OP_DIO2_RF_CTRL, &byte, 1);
digitalWrite(_rxen, HIGH);
}
void LoRaClass::disableAntenna()
{
digitalWrite(_rxen, LOW);
}
void LoRaClass::loraMode() {
// enable lora mode on the SX1262 chip
uint8_t mode = MODE_LONG_RANGE_MODE;
executeOpcode(OP_PACKET_TYPE, &mode, 1);
}
void LoRaClass::waitOnBusy() {
if (_busy != -1) {
while (digitalRead(_busy) == HIGH)
{
// do nothing
}
}
}
void LoRaClass::executeOpcode(uint8_t opcode, uint8_t *buffer, uint8_t size)
{
waitOnBusy();
digitalWrite(_ss, LOW);
spiModem.beginTransaction(_spiSettings);
spiModem.transfer(opcode);
for (int i = 0; i < size; i++)
{
spiModem.transfer(buffer[i]);
}
spiModem.endTransaction();
digitalWrite(_ss, HIGH);
}
void LoRaClass::executeOpcodeRead(uint8_t opcode, uint8_t *buffer, uint8_t size)
{
waitOnBusy();
digitalWrite(_ss, LOW);
spiModem.beginTransaction(_spiSettings);
spiModem.transfer(opcode);
spiModem.transfer(0x00);
for (int i = 0; i < size; i++)
{
buffer[i] = spiModem.transfer(0x00);
}
spiModem.endTransaction();
digitalWrite(_ss, HIGH);
}
void LoRaClass::writeBuffer(const uint8_t* buffer, size_t size)
{
waitOnBusy();
digitalWrite(_ss, LOW);
spiModem.beginTransaction(_spiSettings);
spiModem.transfer(OP_FIFO_WRITE);
spiModem.transfer(fifo_tx_addr_ptr);
for (int i = 0; i < size; i++)
{
spiModem.transfer(buffer[i]);
fifo_tx_addr_ptr++;
}
spiModem.endTransaction();
digitalWrite(_ss, HIGH);
}
void LoRaClass::readBuffer(uint8_t* buffer, size_t size)
{
waitOnBusy();
digitalWrite(_ss, LOW);
spiModem.beginTransaction(_spiSettings);
spiModem.transfer(OP_FIFO_READ);
spiModem.transfer(fifo_rx_addr_ptr);
spiModem.transfer(0x00);
for (int i = 0; i < size; i++)
{
buffer[i] = spiModem.transfer(0x00);
}
spiModem.endTransaction();
digitalWrite(_ss, HIGH);
}
void LoRaClass::setModulationParams(uint8_t sf, uint8_t bw, uint8_t cr, int ldro) {
// because there is no access to these registers on the sx1262, we have
// to set all these parameters at once or not at all.
uint8_t buf[8];
buf[0] = sf;
buf[1] = bw;
buf[2] = cr;
// low data rate toggle
buf[3] = ldro;
// unused params in LoRa mode
buf[4] = 0x00;
buf[5] = 0x00;
buf[6] = 0x00;
buf[7] = 0x00;
executeOpcode(OP_MODULATION_PARAMS, buf, 8);
}
void LoRaClass::setPacketParams(long preamble, uint8_t headermode, uint8_t length, uint8_t crc) {
// because there is no access to these registers on the sx1262, we have
// to set all these parameters at once or not at all.
uint8_t buf[9];
buf[0] = uint8_t((preamble & 0xFF00) >> 8);
buf[1] = uint8_t((preamble & 0x00FF));
buf[2] = headermode;
buf[3] = length;
buf[4] = crc;
// standard IQ setting (no inversion)
buf[5] = 0x00;
// unused params
buf[6] = 0x00;
buf[7] = 0x00;
buf[8] = 0x00;
executeOpcode(OP_PACKET_PARAMS, buf, 9);
}
#endif
int LoRaClass::begin(long frequency)
{
7 years ago
if (_reset != -1) {
pinMode(_reset, OUTPUT);
// perform reset
digitalWrite(_reset, LOW);
delay(10);
digitalWrite(_reset, HIGH);
delay(10);
}
if (_busy != -1) {
pinMode(_busy, INPUT);
}
if (!lora_preinit_done) {
if (!preInit()) {
return false;
}
7 years ago
}
#if MODEM == SX1276 || MODEM == SX1278
// put in sleep mode
sleep();
7 years ago
// set frequency
setFrequency(frequency);
7 years ago
// set base addresses
writeRegister(REG_FIFO_TX_BASE_ADDR, 0);
writeRegister(REG_FIFO_RX_BASE_ADDR, 0);
7 years ago
// set LNA boost
writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03);
7 years ago
// set auto AGC
writeRegister(REG_MODEM_CONFIG_3, 0x04);
7 years ago
// set output power to 2 dBm
setTxPower(2);
7 years ago
// put in standby mode
idle();
#elif MODEM == SX1262
//#if HAS_TCXO
// turn TCXO on
enableTCXO();
//#endif
loraMode();
idle();
// cannot access registers in sleep mode on sx1262, set to idle instead
if (_rxen != -1) {
pinMode(_rxen, OUTPUT);
enableAntenna();
}
// calibrate RC64k, RC13M, PLL, ADC and image
uint8_t calibrate = 0x7F;
executeOpcode(OP_CALIBRATE, &calibrate, 1);
setFrequency(frequency);
// set output power to 2 dBm
setTxPower(2);
// set LNA boost
writeRegister(REG_LNA, 0x96);
// set base addresses
uint8_t basebuf[2] = {0};
executeOpcode(OP_BUFFER_BASE_ADDR, basebuf, 2);
setModulationParams(_sf, _bw, _cr, _ldro);
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
return 1;
}
void LoRaClass::end()
{
// put in sleep mode
sleep();
// stop spiModem
spiModem.end();
lora_preinit_done = false;
7 years ago
}
int LoRaClass::beginPacket(int implicitHeader)
{
// put in standby mode
idle();
if (implicitHeader) {
implicitHeaderMode();
} else {
explicitHeaderMode();
}
#if MODEM == SX1276 || MODEM == SX1278
// reset FIFO address and paload length
writeRegister(REG_FIFO_ADDR_PTR, 0);
writeRegister(REG_PAYLOAD_LENGTH, 0);
#elif MODEM == SX1262
_payloadLength = 0;
fifo_tx_addr_ptr = 0;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
return 1;
}
int LoRaClass::endPacket()
{
#if MODEM == SX1276 || MODEM == SX1278
// put in TX mode
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_TX);
// wait for TX done
while ((readRegister(REG_IRQ_FLAGS) & IRQ_TX_DONE_MASK) == 0) {
yield();
}
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
#elif MODEM == SX1262
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
// put in single TX mode
uint8_t timeout[3] = {0};
executeOpcode(OP_TX, timeout, 3);
uint8_t buf[2];
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS, buf, 2);
// wait for TX done
while ((buf[1] & IRQ_TX_DONE_MASK) == 0) {
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS, buf, 2);
yield();
}
// clear IRQ's
uint8_t mask[2];
mask[0] = 0x00;
mask[1] = IRQ_TX_DONE_MASK;
executeOpcode(OP_CLEAR_IRQ_STATUS, mask, 2);
#endif
7 years ago
return 1;
}
int LoRaClass::parsePacket(int size)
{
int packetLength = 0;
#if MODEM == SX1276 || MODEM == SX1278
int irqFlags = readRegister(REG_IRQ_FLAGS);
#elif MODEM == SX1262
uint8_t buf[2];
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_GET_IRQ_STATUS, buf, 2);
#endif
7 years ago
if (size > 0) {
implicitHeaderMode();
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_PAYLOAD_LENGTH, size & 0xff);
#elif MODEM == SX1262
// tell radio payload length
_payloadLength = size;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
} else {
explicitHeaderMode();
}
#if MODEM == SX1276 || MODEM == SX1278
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, irqFlags);
if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
#elif MODEM == SX1262
uint8_t irqBufFlags[2];
irqBufFlags[0] = buf[0];
irqBufFlags[1] = buf[1];
executeOpcode(OP_CLEAR_IRQ_STATUS, irqBufFlags, 2);
if ((buf[0] & IRQ_RX_DONE_MASK) && (buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
#endif
// received a packet
_packetIndex = 0;
#if MODEM == SX1276 || MODEM == SX1278
// read packet length
if (_implicitHeaderMode) {
packetLength = readRegister(REG_PAYLOAD_LENGTH);
} else {
packetLength = readRegister(REG_RX_NB_BYTES);
}
#elif MODEM == SX1262
buf[0] = 0x00;
buf[1] = 0x00;
executeOpcodeRead(OP_RX_BUFFER_STATUS, buf, 2);
packetLength = buf[0];
#endif
#if MODEM == SX1276 || MODEM == SX1278
// set FIFO address to current RX address
writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));
#endif
7 years ago
// put in standby mode
idle();
#if MODEM == SX1276 || MODEM == SX1278
} else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) {
// not currently in RX mode
7 years ago
// reset FIFO address
writeRegister(REG_FIFO_ADDR_PTR, 0);
7 years ago
// put in single RX mode
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE);
}
#elif MODEM == SX1262
} else {
uint8_t status;
status = 0x00;
executeOpcodeRead(OP_STATUS, &status, 1);
if ((status >> 4 & 0x7) != 0x5) {
// not currently in RX mode
// put in single RX mode
uint8_t buf[3] = {0};
executeOpcode(OP_RX, buf, 3);
}
7 years ago
}
#endif
7 years ago
return packetLength;
}
uint8_t LoRaClass::modemStatus() {
#if MODEM == SX1276 || MODEM == SX1278
return readRegister(REG_MODEM_STAT);
#elif MODEM == SX1262
// imitate the register status from the sx1276 / 78
uint8_t buf[2] = {0};
executeOpcodeRead(OP_GET_IRQ_STATUS, buf, 2);
uint8_t clearbuf[2] = {0};
uint8_t byte = 0x00;
if (buf[1] & IRQ_PREAMBLE_DET_MASK != 0) {
byte = byte | 0x01 | 0x04;
// clear register after reading
clearbuf[1] = IRQ_PREAMBLE_DET_MASK;
}
if (buf[1] & IRQ_HEADER_DET_MASK != 0) {
byte = byte | 0x02 | 0x04;
// clear register after reading
clearbuf[1] = clearbuf[1] | IRQ_HEADER_DET_MASK;
}
executeOpcode(OP_CLEAR_IRQ_STATUS, clearbuf, 2);
return byte;
#endif
}
uint8_t LoRaClass::currentRssiRaw() {
#if MODEM == SX1276 || MODEM == SX1278
uint8_t rssi = readRegister(REG_RSSI_VALUE);
return rssi;
#elif MODEM == SX1262
uint8_t byte = 0;
executeOpcodeRead(OP_CURRENT_RSSI, &byte, 1);
return byte;
#endif
}
int ISR_VECT LoRaClass::currentRssi() {
#if MODEM == SX1276 || MODEM == SX1278
int rssi = (int)readRegister(REG_RSSI_VALUE) - RSSI_OFFSET;
if (_frequency < 820E6) rssi -= 7;
return rssi;
#elif MODEM == SX1262
uint8_t byte = 0;
executeOpcodeRead(OP_CURRENT_RSSI, &byte, 1);
int rssi = -(int(byte)) / 2;
return rssi;
#endif
}
uint8_t LoRaClass::packetRssiRaw() {
#if MODEM == SX1276 || MODEM == SX1278
uint8_t pkt_rssi_value = readRegister(REG_PKT_RSSI_VALUE);
return pkt_rssi_value;
#elif MODEM == SX1262
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS, buf, 3);
return buf[2];
#endif
}
int ISR_VECT LoRaClass::packetRssi() {
#if MODEM == SX1276 || MODEM == SX1278
int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE) - RSSI_OFFSET;
int pkt_snr = packetSnr();
if (_frequency < 820E6) pkt_rssi -= 7;
if (pkt_snr < 0) {
pkt_rssi += pkt_snr;
} else {
// Slope correction is (16/15)*pkt_rssi,
// this estimation looses one floating point
// operation, and should be precise enough.
pkt_rssi = (int)(1.066 * pkt_rssi);
}
return pkt_rssi;
#elif MODEM == SX1262
// may need more calculations here
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS, buf, 3);
int pkt_rssi = -(int(buf[2])) / 2;
return pkt_rssi;
#endif
7 years ago
}
uint8_t ISR_VECT LoRaClass::packetSnrRaw() {
#if MODEM == SX1276 || MODEM == SX1278
return readRegister(REG_PKT_SNR_VALUE);
#elif MODEM == SX1262
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS, buf, 3);
return buf[1];
#endif
}
float ISR_VECT LoRaClass::packetSnr() {
#if MODEM == SX1276 || MODEM == SX1278
return ((int8_t)readRegister(REG_PKT_SNR_VALUE)) * 0.25;
#elif MODEM == SX1262
uint8_t buf[3] = {0};
executeOpcodeRead(OP_PACKET_STATUS, buf, 3);
return float(buf[1]) / 4.0;
#endif
7 years ago
}
long LoRaClass::packetFrequencyError()
{
int32_t freqError = 0;
#if MODEM == SX1276 || MODEM == SX1278
freqError = static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MSB) & B111);
freqError <<= 8L;
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MID));
freqError <<= 8L;
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_LSB));
if (readRegister(REG_FREQ_ERROR_MSB) & B1000) { // Sign bit is on
freqError -= 524288; // B1000'0000'0000'0000'0000
}
7 years ago
const float fXtal = 32E6; // FXOSC: crystal oscillator (XTAL) frequency (2.5. Chip Specification, p. 14)
const float fError = ((static_cast<float>(freqError) * (1L << 24)) / fXtal) * (getSignalBandwidth() / 500000.0f); // p. 37
7 years ago
return static_cast<long>(fError);
#elif MODEM == SX1262
// todo: implement this, no idea how to check it on the sx1262
const float fError = 0.0;
return static_cast<long>(fError);
#endif
7 years ago
}
size_t LoRaClass::write(uint8_t byte)
{
return write(&byte, sizeof(byte));
}
size_t LoRaClass::write(const uint8_t *buffer, size_t size)
{
#if MODEM == SX1276 || MODEM == SX1278
int currentLength = readRegister(REG_PAYLOAD_LENGTH);
// check size
if ((currentLength + size) > MAX_PKT_LENGTH) {
size = MAX_PKT_LENGTH - currentLength;
}
#elif MODEM == SX1262
if ((_payloadLength + size) > MAX_PKT_LENGTH) {
size = MAX_PKT_LENGTH - _payloadLength;
}
#endif
7 years ago
// write data
#if MODEM == SX1276 || MODEM == SX1278
for (size_t i = 0; i < size; i++) {
writeRegister(REG_FIFO, buffer[i]);
}
7 years ago
// update length
writeRegister(REG_PAYLOAD_LENGTH, currentLength + size);
#elif MODEM == SX1262
writeBuffer(buffer, size);
_payloadLength = _payloadLength + size;
#endif
7 years ago
return size;
}
int ISR_VECT LoRaClass::available()
7 years ago
{
#if MODEM == SX1276 || MODEM == SX1278
return (readRegister(REG_RX_NB_BYTES) - _packetIndex);
#elif MODEM == SX1262
uint8_t buf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS, buf, 2);
return buf[0] - _packetIndex;
#endif
7 years ago
}
int ISR_VECT LoRaClass::read()
7 years ago
{
if (!available()) {
return -1;
}
#if MODEM == SX1276 || MODEM == SX1278
_packetIndex++;
return readRegister(REG_FIFO);
#elif MODEM == SX1262
// if received new packet
if (_packetIndex == 0) {
uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS, rxbuf, 2);
int size = rxbuf[0];
fifo_rx_addr_ptr = rxbuf[1];
readBuffer(packet, size);
}
uint8_t byte = packet[_packetIndex];
_packetIndex++;
return byte;
#endif
7 years ago
}
int LoRaClass::peek()
{
if (!available()) {
return -1;
}
#if MODEM == SX1276 || MODEM == SX1278
// store current FIFO address
int currentAddress = readRegister(REG_FIFO_ADDR_PTR);
// read
uint8_t b = readRegister(REG_FIFO);
7 years ago
// restore FIFO address
writeRegister(REG_FIFO_ADDR_PTR, currentAddress);
7 years ago
#elif MODEM == SX1262
// if received new packet
if (_packetIndex == 0) {
uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS, rxbuf, 2);
int size = rxbuf[0];
fifo_rx_addr_ptr = rxbuf[1];
7 years ago
readBuffer(packet, size);
}
uint8_t b = packet[_packetIndex];
#endif
7 years ago
return b;
}
void LoRaClass::flush()
{
}
void LoRaClass::onReceive(void(*callback)(int))
{
_onReceive = callback;
if (callback) {
pinMode(_dio0, INPUT);
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_DIO_MAPPING_1, 0x00);
#elif MODEM == SX1262
// set preamble and header detection irqs, plus dio0 mask
uint8_t buf[8];
// set irq masks, enable all
buf[0] = 0xFF;
buf[1] = 0xFF;
// set dio0 masks
buf[2] = 0x00;
buf[3] = IRQ_RX_DONE_MASK;
// set dio1 masks
buf[4] = 0x00;
buf[5] = 0x00;
// set dio2 masks
buf[6] = 0x00;
buf[7] = 0x00;
executeOpcode(OP_SET_IRQ_FLAGS, buf, 8);
#endif
7 years ago
#ifdef SPI_HAS_NOTUSINGINTERRUPT
spiModem.usingInterrupt(digitalPinToInterrupt(_dio0));
7 years ago
#endif
attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING);
} else {
detachInterrupt(digitalPinToInterrupt(_dio0));
#ifdef SPI_HAS_NOTUSINGINTERRUPT
spiModem.notUsingInterrupt(digitalPinToInterrupt(_dio0));
7 years ago
#endif
}
}
void LoRaClass::receive(int size)
{
if (size > 0) {
implicitHeaderMode();
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_PAYLOAD_LENGTH, size & 0xff);
#elif MODEM == SX1262
// tell radio payload length
_payloadLength = size;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
} else {
explicitHeaderMode();
}
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS);
#elif MODEM == SX1262
uint8_t mode[3] = {0xFF, 0xFF, 0xFF}; // continuous mode
executeOpcode(OP_RX, mode, 3);
#endif
7 years ago
}
void LoRaClass::idle()
{
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY);
#elif MODEM == SX1262
//#if HAS_TCXO
// STDBY_XOSC
uint8_t byte = 0x01;
//#else
// // STDBY_RC
// uint8_t byte = 0x00;
//#endif
executeOpcode(OP_STANDBY, &byte, 1);
#endif
7 years ago
}
void LoRaClass::sleep()
{
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP);
#elif MODEM == SX1262
if (_rxen != -1) {
disableAntenna();
}
uint8_t byte = 0x00;
executeOpcode(OP_SLEEP, &byte, 1);
#endif
7 years ago
}
void LoRaClass::enableTCXO() {
#if MODEM == SX1276 || MODEM == SX1278
uint8_t tcxo_reg = readRegister(REG_TCXO);
writeRegister(REG_TCXO, tcxo_reg | 0x10);
#elif MODEM == SX1262
// only tested for RAK4630, voltage may be different on other platforms
uint8_t buf[4] = {MODE_TCXO_3_3V, 0x00, 0x00, 0xFF};
executeOpcode(OP_DIO3_TCXO_CTRL, buf, 4);
#endif
}
void LoRaClass::disableTCXO() {
#if MODEM == SX1276 || MODEM == SX1278
uint8_t tcxo_reg = readRegister(REG_TCXO);
writeRegister(REG_TCXO, tcxo_reg & 0xEF);
#elif MODEM == SX1262
// currently cannot disable on SX1262?
#endif
}
void LoRaClass::setTxPower(int level, int outputPin) {
#if MODEM == SX1276 || MODEM == SX1278
if (PA_OUTPUT_RFO_PIN == outputPin) {
// RFO
if (level < 0) {
level = 0;
} else if (level > 14) {
level = 14;
}
writeRegister(REG_PA_DAC, 0x84);
writeRegister(REG_PA_CONFIG, 0x70 | level);
} else {
// PA BOOST
if (level < 2) {
level = 2;
} else if (level > 17) {
level = 17;
}
writeRegister(REG_PA_DAC, 0x84);
writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2));
}
#elif MODEM == SX1262
// currently no low power mode for SX1262 implemented, assuming PA boost
// WORKAROUND - Better Resistance of the SX1262 Tx to Antenna Mismatch, see DS_SX1261-2_V1.2 datasheet chapter 15.2
// RegTxClampConfig = @address 0x08D8
writeRegister(0x08D8, readRegister(0x08D8) | (0x0F << 1));
uint8_t pa_buf[4];
pa_buf[0] = 0x04;
pa_buf[1] = 0x07;
pa_buf[2] = 0x00;
pa_buf[3] = 0x01;
executeOpcode(OP_PA_CONFIG, pa_buf, 4); // set pa_config for high power
if (level > 22) {
level = 22;
}
else if (level < -9) {
level = -9;
7 years ago
}
writeRegister(REG_OCP, 0x38); // 160mA limit, overcurrent protection
uint8_t tx_buf[2];
7 years ago
tx_buf[0] = level;
tx_buf[1] = 0x02; // ramping time - 40 microseconds
executeOpcode(OP_TX_PARAMS, tx_buf, 2);
_txp = level;
#endif
7 years ago
}
uint8_t LoRaClass::getTxPower() {
#if MODEM == SX1276 || MODEM == SX1278
byte txp = readRegister(REG_PA_CONFIG);
return txp;
#elif MODEM == SX1262
return _txp;
#endif
}
void LoRaClass::setFrequency(long frequency) {
7 years ago
_frequency = frequency;
#if MODEM == SX1276 || MODEM == SX1278
uint32_t frf = ((uint64_t)frequency << 19) / 32000000;
7 years ago
writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16));
writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8));
writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0));
optimizeModemSensitivity();
#elif MODEM == SX1262
uint8_t buf[4];
uint32_t freq = (uint32_t)((double)frequency / (double)FREQ_STEP);
buf[0] = ((freq >> 24) & 0xFF);
buf[1] = ((freq >> 16) & 0xFF);
buf[2] = ((freq >> 8) & 0xFF);
buf[3] = (freq & 0xFF);
executeOpcode(OP_RF_FREQ, buf, 4);
#endif
7 years ago
}
uint32_t LoRaClass::getFrequency() {
#if MODEM == SX1276 || MODEM == SX1278
uint8_t msb = readRegister(REG_FRF_MSB);
uint8_t mid = readRegister(REG_FRF_MID);
uint8_t lsb = readRegister(REG_FRF_LSB);
7 years ago
uint32_t frf = ((uint32_t)msb << 16) | ((uint32_t)mid << 8) | (uint32_t)lsb;
uint64_t frm = (uint64_t)frf*32000000;
uint32_t frequency = (frm >> 19);
#elif MODEM == SX1262
// we can't read the frequency on the sx1262
uint32_t frequency = _frequency;
#endif
7 years ago
return frequency;
}
void LoRaClass::setSpreadingFactor(int sf)
{
if (sf < 6) {
sf = 6;
} else if (sf > 12) {
sf = 12;
}
#if MODEM == SX1276 || MODEM == SX1278
if (sf == 6) {
writeRegister(REG_DETECTION_OPTIMIZE, 0xc5);
writeRegister(REG_DETECTION_THRESHOLD, 0x0c);
} else {
writeRegister(REG_DETECTION_OPTIMIZE, 0xc3);
writeRegister(REG_DETECTION_THRESHOLD, 0x0a);
}
writeRegister(REG_MODEM_CONFIG_2, (readRegister(REG_MODEM_CONFIG_2) & 0x0f) | ((sf << 4) & 0xf0));
#elif MODEM == SX1262
setModulationParams(sf, _bw, _cr, _ldro);
#endif
handleLowDataRate();
7 years ago
}
long LoRaClass::getSignalBandwidth()
{
#if MODEM == SX1276 || MODEM == SX1278
byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4);
switch (bw) {
case 0: return 7.8E3;
case 1: return 10.4E3;
case 2: return 15.6E3;
case 3: return 20.8E3;
case 4: return 31.25E3;
case 5: return 41.7E3;
case 6: return 62.5E3;
case 7: return 125E3;
case 8: return 250E3;
case 9: return 500E3;
}
#elif MODEM == SX1262
int bw = _bw;
switch (bw) {
case 0x00: return 7.8E3;
case 0x01: return 15.6E3;
case 0x02: return 31.25E3;
case 0x03: return 62.5E3;
case 0x04: return 125E3;
case 0x05: return 250E3;
case 0x06: return 500E3;
case 0x08: return 10.4E3;
case 0x09: return 20.8E3;
case 0x0A: return 41.7E3;
}
#endif
return 0;
7 years ago
}
void LoRaClass::handleLowDataRate(){
#if MODEM == SX1276 || MODEM == SX1278
int sf = (readRegister(REG_MODEM_CONFIG_2) >> 4);
if ( long( (1<<sf) / (getSignalBandwidth()/1000)) > 16) {
// set auto AGC and LowDataRateOptimize
writeRegister(REG_MODEM_CONFIG_3, (1<<3)|(1<<2));
} else {
// set auto AGC
writeRegister(REG_MODEM_CONFIG_3, (1<<2));
}
#elif MODEM == SX1262
_ldro = 1;
setModulationParams(_sf, _bw, _cr, _ldro);
#endif
}
void LoRaClass::optimizeModemSensitivity(){
#if MODEM == SX1276 || MODEM == SX1278
byte bw = (readRegister(REG_MODEM_CONFIG_1) >> 4);
uint32_t freq = getFrequency();
if (bw == 9 && (410E6 <= freq) && (freq <= 525E6)) {
writeRegister(REG_HIGH_BW_OPTIMIZE_1, 0x02);
writeRegister(REG_HIGH_BW_OPTIMIZE_2, 0x7f);
} else if (bw == 9 && (820E6 <= freq) && (freq <= 1020E6)) {
writeRegister(REG_HIGH_BW_OPTIMIZE_1, 0x02);
writeRegister(REG_HIGH_BW_OPTIMIZE_2, 0x64);
} else {
writeRegister(REG_HIGH_BW_OPTIMIZE_1, 0x03);
}
#elif MODEM == SX1262
// todo: check if there's anything the sx1262 can do here
#endif
}
7 years ago
void LoRaClass::setSignalBandwidth(long sbw)
{
#if MODEM == SX1276 || MODEM == SX1278
int bw;
if (sbw <= 7.8E3) {
bw = 0;
} else if (sbw <= 10.4E3) {
bw = 1;
} else if (sbw <= 15.6E3) {
bw = 2;
} else if (sbw <= 20.8E3) {
bw = 3;
} else if (sbw <= 31.25E3) {
bw = 4;
} else if (sbw <= 41.7E3) {
bw = 5;
} else if (sbw <= 62.5E3) {
bw = 6;
} else if (sbw <= 125E3) {
bw = 7;
} else if (sbw <= 250E3) {
bw = 8;
} else /*if (sbw <= 250E3)*/ {
bw = 9;
}
writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0x0f) | (bw << 4));
#elif MODEM == SX1262
uint8_t bw;
if (sbw <= 7.8E3) {
bw = 0x00;
} else if (sbw <= 10.4E3) {
bw = 0x08;
} else if (sbw <= 15.6E3) {
bw = 0x01;
} else if (sbw <= 20.8E3) {
bw = 0x09;
} else if (sbw <= 31.25E3) {
bw = 0x02;
} else if (sbw <= 41.7E3) {
bw = 0x0A;
} else if (sbw <= 62.5E3) {
bw = 0x03;
} else if (sbw <= 125E3) {
bw = 0x04;
} else if (sbw <= 250E3) {
bw = 0x05;
} else /*if (sbw <= 250E3)*/ {
bw = 0x06;
}
setModulationParams(_sf, bw, _cr, _ldro);
#endif
7 years ago
handleLowDataRate();
optimizeModemSensitivity();
7 years ago
}
void LoRaClass::setCodingRate4(int denominator)
{
if (denominator < 5) {
denominator = 5;
} else if (denominator > 8) {
denominator = 8;
}
int cr = denominator - 4;
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1));
#elif MODEM == SX1262
setModulationParams(_sf, _bw, cr, _ldro);
#endif
7 years ago
}
void LoRaClass::setPreambleLength(long length)
{
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8));
writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0));
#elif MODEM == SX1262
setPacketParams(length, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
}
void LoRaClass::setSyncWord(int sw)
{
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_SYNC_WORD, sw);
#elif MODEM == SX1262
writeRegister(REG_SYNC_WORD_MSB, sw & 0xFF00);
writeRegister(REG_SYNC_WORD_LSB, sw & 0x00FF);
#endif
7 years ago
}
void LoRaClass::enableCrc()
{
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04);
#elif MODEM == SX1262
_crcMode = 1;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
}
void LoRaClass::disableCrc()
{
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb);
#elif MODEM == SX1262
_crcMode = 0;
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
}
byte LoRaClass::random()
{
#if MODEM == SX1276 || MODEM == SX1278
return readRegister(REG_RSSI_WIDEBAND);
#elif MODEM == SX1262
return readRegister(REG_RANDOM_GEN);
#endif
7 years ago
}
void LoRaClass::setPins(int ss, int reset, int dio0, int rxen, int busy)
7 years ago
{
_ss = ss;
_reset = reset;
_dio0 = dio0;
_rxen = rxen;
_busy = busy;
7 years ago
}
void LoRaClass::setSPIFrequency(uint32_t frequency)
{
_spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0);
}
void LoRaClass::dumpRegisters(Stream& out)
{
for (int i = 0; i < 128; i++) {
out.print("0x");
out.print(i, HEX);
out.print(": 0x");
out.println(readRegister(i), HEX);
}
}
void LoRaClass::explicitHeaderMode()
{
_implicitHeaderMode = 0;
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe);
#elif MODEM == SX1262
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
}
void LoRaClass::implicitHeaderMode()
{
_implicitHeaderMode = 1;
#if MODEM == SX1276 || MODEM == SX1278
writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01);
#elif MODEM == SX1262
setPacketParams(_preambleLength, _implicitHeaderMode, _payloadLength, _crcMode);
#endif
7 years ago
}
void ISR_VECT LoRaClass::handleDio0Rise()
7 years ago
{
#if MODEM == SX1276 || MODEM == SX1278
int irqFlags = readRegister(REG_IRQ_FLAGS);
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, irqFlags);
if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
#elif MODEM == SX1262
uint8_t buf[2];
7 years ago
buf[0] = 0x00;
buf[1] = 0x00;
7 years ago
executeOpcodeRead(OP_GET_IRQ_STATUS, buf, 2);
executeOpcode(OP_CLEAR_IRQ_STATUS, buf, 2);
if ((buf[1] & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
#endif
// received a packet
_packetIndex = 0;
7 years ago
// read packet length
#if MODEM == SX1276 || MODEM == SX1278
7 years ago
int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES);
// set FIFO address to current RX address
writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));
#elif MODEM == SX1262
uint8_t rxbuf[2] = {0};
executeOpcodeRead(OP_RX_BUFFER_STATUS, rxbuf, 2);
int packetLength = rxbuf[0];
#endif
if (_onReceive) {
_onReceive(packetLength);
}
7 years ago
#if MODEM == SX1276 || MODEM == SX1278
7 years ago
// reset FIFO address
writeRegister(REG_FIFO_ADDR_PTR, 0);
#endif
7 years ago
}
}
void ISR_VECT LoRaClass::onDio0Rise()
7 years ago
{
LoRa.handleDio0Rise();
}
LoRaClass LoRa;