RNode_Firmware/LoRa.cpp

869 lines
21 KiB
C++
Raw Normal View History

2018-04-05 12:10:42 -04:00
// Copyright (c) Sandeep Mistry. All rights reserved.
2018-04-26 09:52:43 -04:00
// Licensed under the MIT license.
// Modifications and additions copyright 2018 by Mark Qvist
// Obviously still under the MIT license.
2018-04-05 12:10:42 -04:00
2018-12-01 13:31:51 -05:00
#include "LoRa.h"
2018-04-05 12:10:42 -04:00
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_C
// We need sleep() to use instead of yield()
#include <unistd.h>
// And we need to use the filesystem and IOCTLs instead of an SPI global
#include <fcntl.h>
2022-02-13 18:40:30 -05:00
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
// And to have memset
#include <cstring>
2022-02-13 18:19:33 -05:00
// And we need to be able to report errors
#include <stdio.h>
#include <errno.h>
// And we need IO formatting functions for the C++-stream dumpRegisters()
#include <iomanip>
#endif
2022-01-14 14:56:10 -05:00
#if MCU_VARIANT == MCU_ESP32
#include "soc/rtc_wdt.h"
#define ISR_VECT IRAM_ATTR
#else
#define ISR_VECT
#endif
2018-06-18 16:30:24 -04:00
// Registers
2018-04-05 12:10:42 -04:00
#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
2022-02-17 12:26:49 -05:00
#define REG_PA_RAMP 0x0a
#define REG_OCP 0x0b
2018-04-05 12:10:42 -04:00
#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
2022-02-17 12:26:49 -05:00
#define REG_IRQ_FLAGS_MASK 0x11
2018-04-05 12:10:42 -04:00
#define REG_IRQ_FLAGS 0x12
#define REG_RX_NB_BYTES 0x13
2018-04-26 09:52:43 -04:00
#define REG_MODEM_STAT 0x18
2018-04-05 12:10:42 -04:00
#define REG_PKT_SNR_VALUE 0x19
#define REG_PKT_RSSI_VALUE 0x1a
#define REG_MODEM_CONFIG_1 0x1d
#define REG_MODEM_CONFIG_2 0x1e
2022-02-17 12:26:49 -05:00
#define REG_SYMB_TIMEOUT_LSB 0x1f
2018-04-05 12:10:42 -04:00
#define REG_PREAMBLE_MSB 0x20
#define REG_PREAMBLE_LSB 0x21
#define REG_PAYLOAD_LENGTH 0x22
2022-02-17 12:26:49 -05:00
#define REG_PAYLOAD_MAX_LENGTH 0x23
#define REG_HOP_PERIOD 0x24
2018-04-05 12:10:42 -04:00
#define REG_MODEM_CONFIG_3 0x26
2022-02-17 12:26:49 -05:00
#define REG_PPM_CORRECTION 0x27
2018-04-05 12:10:42 -04:00
#define REG_FREQ_ERROR_MSB 0x28
#define REG_FREQ_ERROR_MID 0x29
#define REG_FREQ_ERROR_LSB 0x2a
#define REG_RSSI_WIDEBAND 0x2c
2022-02-17 12:26:49 -05:00
#define REG_IF_FREQ_2 0x2f
#define REG_IF_FREQ_1 0x30
2018-04-05 12:10:42 -04:00
#define REG_DETECTION_OPTIMIZE 0x31
2022-02-17 12:26:49 -05:00
#define REG_INVERT_IQ 0x33
#define REG_HIGH_BW_OPTIMIZE_1 0x36
2018-04-05 12:10:42 -04:00
#define REG_DETECTION_THRESHOLD 0x37
#define REG_SYNC_WORD 0x39
2022-02-17 12:26:49 -05:00
#define REG_HIGH_BW_OPTIMIZE_2 0x3a
#define REG_INVERT_IQ_2 0x3b
2018-04-05 12:10:42 -04:00
#define REG_DIO_MAPPING_1 0x40
#define REG_VERSION 0x42
2022-02-21 13:48:53 -05:00
#define REG_TXCO 0x4B
#define REG_PA_DAC 0x4D
2022-02-21 15:26:14 -05:00
// These registers have different values in high and low frequency modes (flag 0x08 in mode)
// We always stay in high frequency mode (flag is 0)
2022-02-21 13:48:53 -05:00
#define REG_AGC_REF 0x61
#define REG_AGC_THRESHOLD_1 0x62
#define REG_AGC_THRESHOLD_2 0x63
#define REG_AGC_THRESHOLD_3 0x64
#define REG_PLL 0x70
2018-04-05 12:10:42 -04:00
2018-06-18 16:30:24 -04:00
// Modes
2018-04-05 12:10:42 -04:00
#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
#define MAX_PKT_LENGTH 255
LoRaClass::LoRaClass() :
_spiSettings(8E6, MSBFIRST, SPI_MODE0),
_ss(LORA_DEFAULT_SS_PIN), _reset(LORA_DEFAULT_RESET_PIN), _dio0(LORA_DEFAULT_DIO0_PIN),
_frequency(0),
_packetIndex(0),
_implicitHeaderMode(0),
_onReceive(NULL),
_spiBegun(false)
2018-04-05 12:10:42 -04:00
{
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_ARDUINO
2018-04-05 12:10:42 -04:00
// overide Stream timeout value
setTimeout(0);
2022-02-13 18:19:33 -05:00
#elif LIBRARY_TYPE == LIBRARY_C
_fd = 0;
#endif
2018-04-05 12:10:42 -04:00
}
int LoRaClass::begin(long frequency)
{
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_ARDUINO
// setup pins
pinMode(_ss, OUTPUT);
// set SS high
digitalWrite(_ss, HIGH);
#endif
2018-04-05 12:10:42 -04:00
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_ARDUINO
2018-04-05 12:10:42 -04:00
// start SPI
SPI.begin();
2022-02-13 18:19:33 -05:00
#elif LIBRARY_TYPE == LIBRARY_C
2022-02-15 22:00:13 -05:00
const char* spi_filename = "/dev/spidev0.0";
// We need to be re-entrant for restart
2022-02-15 22:00:13 -05:00
if (_fd <= 0) {
std::cerr << "Opening SPI device " << spi_filename << std::endl;
_fd = open(spi_filename, O_RDWR);
if (_fd <= 0) {
perror("could not open SPI device");
exit(1);
}
} else {
std::cerr << "Skipping LoRa SPI reinitialization" << std::endl;
2022-02-13 18:19:33 -05:00
}
#endif
_spiBegun = true;
2022-02-13 18:19:33 -05:00
2022-02-21 13:48:53 -05:00
if (!resetModem()) {
2018-04-05 12:10:42 -04:00
return 0;
}
// set frequency
setFrequency(frequency);
// set base addresses
writeRegister(REG_FIFO_TX_BASE_ADDR, 0);
writeRegister(REG_FIFO_RX_BASE_ADDR, 0);
// set LNA boost
writeRegister(REG_LNA, readRegister(REG_LNA) | 0x03);
// set auto AGC
writeRegister(REG_MODEM_CONFIG_3, 0x04);
2018-06-27 04:24:51 -04:00
// set output power to 2 dBm
2018-06-18 16:30:24 -04:00
setTxPower(2);
2018-04-05 12:10:42 -04:00
// put in standby mode
idle();
return 1;
}
void LoRaClass::end()
{
// We need to be safe to call when the main loop is shutting down because
// it's in a bad state, even if we ourselves haven't been begun yet. We can't
// safely talk to the modem if the SPI link isn't begun, though.
if (_spiBegun) {
// put in sleep mode
this->sleep();
}
2018-04-05 12:10:42 -04:00
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_ARDUINO
2018-04-05 12:10:42 -04:00
// stop SPI
SPI.end();
2022-02-13 18:19:33 -05:00
#elif LIBRARY_TYPE == LIBRARY_C
2022-02-17 11:05:44 -05:00
// Don't do anything. We need to keep things open for restart.
2022-02-13 18:19:33 -05:00
#endif
_spiBegun = false;
2018-04-05 12:10:42 -04:00
}
int LoRaClass::beginPacket(int implicitHeader)
{
// put in standby mode
idle();
if (implicitHeader) {
implicitHeaderMode();
} else {
explicitHeaderMode();
}
// reset FIFO address and paload length
writeRegister(REG_FIFO_ADDR_PTR, 0);
writeRegister(REG_PAYLOAD_LENGTH, 0);
return 1;
}
int LoRaClass::endPacket()
{
// 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) {
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_ARDUINO
2018-04-05 12:10:42 -04:00
yield();
2022-02-13 18:19:33 -05:00
#elif LIBRARY_TYPE == LIBRARY_C
2022-02-13 20:20:21 -05:00
::sleep(0);
2022-02-13 18:19:33 -05:00
#endif
2018-04-05 12:10:42 -04:00
}
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, IRQ_TX_DONE_MASK);
return 1;
}
int LoRaClass::parsePacket(int size)
{
int packetLength = 0;
int irqFlags = readRegister(REG_IRQ_FLAGS);
if (size > 0) {
implicitHeaderMode();
writeRegister(REG_PAYLOAD_LENGTH, size & 0xff);
} else {
explicitHeaderMode();
}
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, irqFlags);
if ((irqFlags & IRQ_RX_DONE_MASK) && (irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
// received a packet
_packetIndex = 0;
// read packet length
if (_implicitHeaderMode) {
packetLength = readRegister(REG_PAYLOAD_LENGTH);
} else {
packetLength = readRegister(REG_RX_NB_BYTES);
}
// set FIFO address to current RX address
writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));
// put in standby mode
idle();
} else if (readRegister(REG_OP_MODE) != (MODE_LONG_RANGE_MODE | MODE_RX_SINGLE)) {
// not currently in RX mode
// reset FIFO address
writeRegister(REG_FIFO_ADDR_PTR, 0);
// put in single RX mode
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_SINGLE);
}
return packetLength;
}
2018-04-26 09:52:43 -04:00
uint8_t LoRaClass::modemStatus() {
return readRegister(REG_MODEM_STAT);
}
2018-06-27 08:08:16 -04:00
uint8_t LoRaClass::packetRssiRaw() {
uint8_t pkt_rssi_value = readRegister(REG_PKT_RSSI_VALUE);
return pkt_rssi_value;
}
2022-01-14 15:41:10 -05:00
int ISR_VECT LoRaClass::packetRssi() {
int pkt_rssi = (int)readRegister(REG_PKT_RSSI_VALUE) - RSSI_OFFSET;
int pkt_snr = packetSnr();
2018-06-27 08:08:16 -04:00
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);
}
2018-06-27 08:08:16 -04:00
return pkt_rssi;
2018-04-05 12:10:42 -04:00
}
2022-01-14 15:41:10 -05:00
uint8_t ISR_VECT LoRaClass::packetSnrRaw() {
2020-05-21 06:41:39 -04:00
return readRegister(REG_PKT_SNR_VALUE);
}
2022-01-14 15:41:10 -05:00
float ISR_VECT LoRaClass::packetSnr() {
2018-04-05 12:10:42 -04:00
return ((int8_t)readRegister(REG_PKT_SNR_VALUE)) * 0.25;
}
long LoRaClass::packetFrequencyError()
{
int32_t freqError = 0;
2022-02-13 18:19:33 -05:00
freqError = static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MSB) & 0b111);
2018-04-05 12:10:42 -04:00
freqError <<= 8L;
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_MID));
freqError <<= 8L;
freqError += static_cast<int32_t>(readRegister(REG_FREQ_ERROR_LSB));
2022-02-13 18:19:33 -05:00
if (readRegister(REG_FREQ_ERROR_MSB) & 0b1000) { // Sign bit is on
2018-04-05 12:10:42 -04:00
freqError -= 524288; // B1000'0000'0000'0000'0000
}
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
return static_cast<long>(fError);
}
size_t LoRaClass::write(uint8_t byte)
{
return write(&byte, sizeof(byte));
}
size_t LoRaClass::write(const uint8_t *buffer, size_t size)
{
int currentLength = readRegister(REG_PAYLOAD_LENGTH);
// check size
if ((currentLength + size) > MAX_PKT_LENGTH) {
size = MAX_PKT_LENGTH - currentLength;
}
// write data
for (size_t i = 0; i < size; i++) {
writeRegister(REG_FIFO, buffer[i]);
}
// update length
writeRegister(REG_PAYLOAD_LENGTH, currentLength + size);
return size;
}
2022-01-14 15:41:10 -05:00
int ISR_VECT LoRaClass::available()
2018-04-05 12:10:42 -04:00
{
return (readRegister(REG_RX_NB_BYTES) - _packetIndex);
}
2022-01-14 15:41:10 -05:00
int ISR_VECT LoRaClass::read()
2018-04-05 12:10:42 -04:00
{
if (!available()) {
return -1;
}
_packetIndex++;
return readRegister(REG_FIFO);
}
int LoRaClass::peek()
{
if (!available()) {
return -1;
}
// store current FIFO address
int currentAddress = readRegister(REG_FIFO_ADDR_PTR);
// read
uint8_t b = readRegister(REG_FIFO);
// restore FIFO address
writeRegister(REG_FIFO_ADDR_PTR, currentAddress);
return b;
}
void LoRaClass::flush()
{
}
2022-02-16 21:02:49 -05:00
void LoRaClass::pollReceive()
{
int irqFlags = readRegister(REG_IRQ_FLAGS);
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, irqFlags);
if ((irqFlags & IRQ_RX_DONE_MASK) && !(irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK)) {
// received a packet
handleRx();
}
}
2018-04-05 12:10:42 -04:00
void LoRaClass::onReceive(void(*callback)(int))
{
_onReceive = callback;
if (callback) {
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_ARDUINO
2018-04-05 12:10:42 -04:00
pinMode(_dio0, INPUT);
2022-02-13 18:19:33 -05:00
#endif
2018-04-05 12:10:42 -04:00
writeRegister(REG_DIO_MAPPING_1, 0x00);
2022-02-16 21:02:49 -05:00
#if MCU_VARIANT != MCU_LINUX && LIBRARY_TYPE == LIBRARY_ARDUINO
2018-04-05 12:10:42 -04:00
#ifdef SPI_HAS_NOTUSINGINTERRUPT
SPI.usingInterrupt(digitalPinToInterrupt(_dio0));
#endif
attachInterrupt(digitalPinToInterrupt(_dio0), LoRaClass::onDio0Rise, RISING);
2022-02-13 18:19:33 -05:00
#endif
2018-04-05 12:10:42 -04:00
} else {
2022-02-16 21:02:49 -05:00
#if MCU_VARIANT != MCU_LINUX && LIBRARY_TYPE == LIBRARY_ARDUINO
2018-04-05 12:10:42 -04:00
detachInterrupt(digitalPinToInterrupt(_dio0));
#ifdef SPI_HAS_NOTUSINGINTERRUPT
SPI.notUsingInterrupt(digitalPinToInterrupt(_dio0));
2022-02-13 18:19:33 -05:00
#endif
2018-04-05 12:10:42 -04:00
#endif
}
}
void LoRaClass::receive(int size)
{
if (size > 0) {
implicitHeaderMode();
writeRegister(REG_PAYLOAD_LENGTH, size & 0xff);
} else {
explicitHeaderMode();
}
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_RX_CONTINUOUS);
}
void LoRaClass::idle()
{
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_STDBY);
}
void LoRaClass::sleep()
{
writeRegister(REG_OP_MODE, MODE_LONG_RANGE_MODE | MODE_SLEEP);
}
2020-05-29 08:58:10 -04:00
void LoRaClass::setTxPower(int level, int outputPin) {
2018-04-05 12:10:42 -04:00
if (PA_OUTPUT_RFO_PIN == outputPin) {
// RFO
if (level < 0) {
level = 0;
} else if (level > 14) {
level = 14;
}
writeRegister(REG_PA_CONFIG, 0x70 | level);
2020-05-29 08:58:10 -04:00
2018-04-05 12:10:42 -04:00
} else {
// PA BOOST
if (level < 2) {
level = 2;
} else if (level > 17) {
level = 17;
}
writeRegister(REG_PA_CONFIG, PA_BOOST | (level - 2));
}
}
2018-06-20 10:32:30 -04:00
void LoRaClass::setFrequency(long frequency) {
2018-04-05 12:10:42 -04:00
_frequency = frequency;
2018-06-20 10:32:30 -04:00
uint32_t frf = ((uint64_t)frequency << 19) / 32000000;
2018-04-05 12:10:42 -04:00
writeRegister(REG_FRF_MSB, (uint8_t)(frf >> 16));
writeRegister(REG_FRF_MID, (uint8_t)(frf >> 8));
writeRegister(REG_FRF_LSB, (uint8_t)(frf >> 0));
}
2018-06-20 10:32:30 -04:00
uint32_t LoRaClass::getFrequency() {
2018-04-05 12:10:42 -04:00
uint8_t msb = readRegister(REG_FRF_MSB);
uint8_t mid = readRegister(REG_FRF_MID);
uint8_t lsb = readRegister(REG_FRF_LSB);
2018-06-20 10:32:30 -04:00
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);
2018-04-05 12:10:42 -04:00
return frequency;
}
void LoRaClass::setSpreadingFactor(int sf)
{
if (sf < 6) {
sf = 6;
} else if (sf > 12) {
sf = 12;
}
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));
handleLowDataRate();
2018-04-05 12:10:42 -04:00
}
long LoRaClass::getSignalBandwidth()
{
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;
}
2022-01-09 17:40:30 -05:00
return 0;
2018-04-05 12:10:42 -04:00
}
void LoRaClass::handleLowDataRate(){
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));
}
}
2018-04-05 12:10:42 -04:00
void LoRaClass::setSignalBandwidth(long sbw)
{
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));
handleLowDataRate();
2018-04-05 12:10:42 -04:00
}
void LoRaClass::setCodingRate4(int denominator)
{
if (denominator < 5) {
denominator = 5;
} else if (denominator > 8) {
denominator = 8;
}
int cr = denominator - 4;
writeRegister(REG_MODEM_CONFIG_1, (readRegister(REG_MODEM_CONFIG_1) & 0xf1) | (cr << 1));
}
void LoRaClass::setPreambleLength(long length)
{
writeRegister(REG_PREAMBLE_MSB, (uint8_t)(length >> 8));
writeRegister(REG_PREAMBLE_LSB, (uint8_t)(length >> 0));
}
void LoRaClass::setSyncWord(int sw)
{
writeRegister(REG_SYNC_WORD, sw);
}
void LoRaClass::enableCrc()
{
writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) | 0x04);
}
void LoRaClass::disableCrc()
{
writeRegister(REG_MODEM_CONFIG_2, readRegister(REG_MODEM_CONFIG_2) & 0xfb);
}
byte LoRaClass::random()
{
return readRegister(REG_RSSI_WIDEBAND);
}
void LoRaClass::setPins(int ss, int reset, int dio0)
{
_ss = ss;
_reset = reset;
_dio0 = dio0;
}
void LoRaClass::setSPIFrequency(uint32_t frequency)
{
_spiSettings = SPISettings(frequency, MSBFIRST, SPI_MODE0);
}
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_ARDUINO
2018-04-05 12:10:42 -04:00
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);
}
}
2022-02-13 18:19:33 -05:00
#elif LIBRARY_TYPE == LIBRARY_C
void LoRaClass::dumpRegisters(std::ostream& out)
{
for (int i = 0; i < 128; i++) {
out << "0x" << std::hex << i << ": 0x" << std::hex << readRegister(i) << std::endl;
}
out << std::dec;
}
#endif
2022-02-21 13:48:53 -05:00
bool LoRaClass::resetModem()
{
// Reset the modem to a known good default state and put it into sleep mode.
// Returns false if the modem doesn't appear to be the right version.
#if LIBRARY_TYPE == LIBRARY_ARDUINO
if (_reset != -1) {
pinMode(_reset, OUTPUT);
// perform reset
digitalWrite(_reset, LOW);
delay(10);
digitalWrite(_reset, HIGH);
delay(10);
}
#endif
// check version
uint8_t version = readRegister(REG_VERSION);
if (version != 0x12) {
return false;
}
this->sleep();
#if LIBRARY_TYPE == LIBRARY_C
byte CLEAN_STATE[] = {
REG_PA_RAMP, 0x09,
REG_FRF_MSB, 0x6c,
REG_FRF_MID, 0x80,
REG_FRF_LSB, 0x00,
REG_PA_CONFIG, 0x4f,
REG_PA_RAMP, 0x09,
REG_OCP, 0x2b,
REG_LNA, 0x20,
REG_FIFO_ADDR_PTR, 0x00,
REG_FIFO_TX_BASE_ADDR, 0x80,
REG_FIFO_RX_BASE_ADDR, 0x00,
REG_FIFO_RX_CURRENT_ADDR, 0x00,
REG_IRQ_FLAGS_MASK, 0x00,
REG_MODEM_CONFIG_1, 0x72,
REG_MODEM_CONFIG_2, 0x70,
REG_SYMB_TIMEOUT_LSB, 0x64,
REG_PREAMBLE_MSB, 0x00,
REG_PREAMBLE_LSB, 0x08,
REG_PAYLOAD_LENGTH, 0x01,
REG_PAYLOAD_MAX_LENGTH, 0xff,
REG_HOP_PERIOD, 0x00,
REG_MODEM_CONFIG_3, 0x04,
REG_PPM_CORRECTION, 0x00,
2022-02-21 17:11:55 -05:00
REG_DETECTION_OPTIMIZE, 0xc3, // Errata says this needs to be set before REG_IF_FREQ_1 and REG_IF_FREQ_2
REG_IF_FREQ_2, 0x45, // Datasheet says this defaults to 0x20, but dumping says 0x45.
REG_IF_FREQ_1, 0x55, // Datasheet says this defaults to 0x00, but dumping says 0x55.
2022-02-21 13:48:53 -05:00
REG_INVERT_IQ, 0x27,
REG_HIGH_BW_OPTIMIZE_1, 0x03,
REG_DETECTION_THRESHOLD, 0x0a,
REG_SYNC_WORD, 0x12,
REG_HIGH_BW_OPTIMIZE_2, 0x52, // Datasheet says this defaults to 0x20, but dumping says 0x52.
REG_INVERT_IQ_2, 0x1d,
REG_TXCO, 0x09,
REG_PA_DAC, 0x84,
2022-02-21 15:26:14 -05:00
// These are the high frequency mode (mode flag 0x08 is 0) values
REG_AGC_REF, 0x1C,
2022-02-21 13:48:53 -05:00
REG_AGC_THRESHOLD_1, 0x0e,
REG_AGC_THRESHOLD_2, 0x5b,
2022-02-21 15:26:14 -05:00
REG_AGC_THRESHOLD_3, 0xcc,
2022-02-21 13:48:53 -05:00
REG_PLL, 0xd0,
2022-02-21 15:26:14 -05:00
0, 0
2022-02-21 13:48:53 -05:00
};
// Manually set important registers to default values because we can't
// reset.
for (int i = 0; CLEAN_STATE[i] != 0; i += 2) {
writeRegister(CLEAN_STATE[i], CLEAN_STATE[i + 1]);
}
#endif
return true;
}
2018-04-05 12:10:42 -04:00
void LoRaClass::explicitHeaderMode()
{
_implicitHeaderMode = 0;
writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) & 0xfe);
}
void LoRaClass::implicitHeaderMode()
{
_implicitHeaderMode = 1;
writeRegister(REG_MODEM_CONFIG_1, readRegister(REG_MODEM_CONFIG_1) | 0x01);
}
2022-01-14 14:56:10 -05:00
void ISR_VECT LoRaClass::handleDio0Rise()
2018-04-05 12:10:42 -04:00
{
int irqFlags = readRegister(REG_IRQ_FLAGS);
// clear IRQ's
writeRegister(REG_IRQ_FLAGS, irqFlags);
if ((irqFlags & IRQ_PAYLOAD_CRC_ERROR_MASK) == 0) {
// received a packet
2022-02-16 21:02:49 -05:00
handleRx();
}
}
2018-04-05 12:10:42 -04:00
2022-02-16 21:02:49 -05:00
void ISR_VECT LoRaClass::handleRx()
{
// received a packet
_packetIndex = 0;
2018-04-05 12:10:42 -04:00
2022-02-16 21:02:49 -05:00
// read packet length
int packetLength = _implicitHeaderMode ? readRegister(REG_PAYLOAD_LENGTH) : readRegister(REG_RX_NB_BYTES);
2018-04-05 12:10:42 -04:00
2022-02-16 21:02:49 -05:00
// set FIFO address to current RX address
writeRegister(REG_FIFO_ADDR_PTR, readRegister(REG_FIFO_RX_CURRENT_ADDR));
2018-04-05 12:10:42 -04:00
2022-02-16 21:02:49 -05:00
if (_onReceive) {
_onReceive(packetLength);
2018-04-05 12:10:42 -04:00
}
2022-02-16 21:02:49 -05:00
// reset FIFO address
writeRegister(REG_FIFO_ADDR_PTR, 0);
2018-04-05 12:10:42 -04:00
}
2022-01-14 15:41:10 -05:00
uint8_t ISR_VECT LoRaClass::readRegister(uint8_t address)
2018-04-05 12:10:42 -04:00
{
return singleTransfer(address & 0x7f, 0x00);
}
void LoRaClass::writeRegister(uint8_t address, uint8_t value)
{
singleTransfer(address | 0x80, value);
}
2022-01-14 15:41:10 -05:00
uint8_t ISR_VECT LoRaClass::singleTransfer(uint8_t address, uint8_t value)
2018-04-05 12:10:42 -04:00
{
uint8_t response;
2022-02-13 18:19:33 -05:00
#if LIBRARY_TYPE == LIBRARY_ARDUINO
2022-02-13 18:40:30 -05:00
// Select chip, send address, and send/read data, the Arduino way
2018-04-05 12:10:42 -04:00
digitalWrite(_ss, LOW);
SPI.beginTransaction(_spiSettings);
SPI.transfer(address);
response = SPI.transfer(value);
SPI.endTransaction();
digitalWrite(_ss, HIGH);
2022-02-13 18:19:33 -05:00
#elif LIBRARY_TYPE == LIBRARY_C
2022-02-13 18:40:30 -05:00
// Select chip, send address, and send/read data, the Linux way
// In Linux, chip select is automatically turned off outside of transactions.
int status;
if (_fd <= 0) {
throw std::runtime_error("Accessing SPI device without begin()!");
}
2022-02-15 22:00:13 -05:00
2022-02-13 18:40:30 -05:00
// Configure SPI speed and mode to match settings
status = ioctl(_fd, SPI_IOC_WR_MODE, &_spiSettings.mode);
if (status < 0) {
perror("ioctl SPI_IOC_WR_MODE failed");
exit(1);
}
status = ioctl(_fd, SPI_IOC_WR_LSB_FIRST, &_spiSettings.bitness);
if (status < 0) {
perror("ioctl SPI_IOC_WR_LSB_FIRST failed");
exit(1);
}
status = ioctl(_fd, SPI_IOC_WR_MAX_SPEED_HZ, &_spiSettings.frequency);
if (status < 0) {
perror("ioctl SPI_IOC_WR_MAX_SPEED_HZ failed");
exit(1);
}
// We have two transfers: one send-only to send the address, and one
// send/receive, to send the value and get the response.
struct spi_ioc_transfer xfer[2];
memset(xfer, 0, sizeof xfer);
xfer[0].tx_buf = (unsigned long) &address;
xfer[0].len = 1;
xfer[1].tx_buf = (unsigned long) &value;
xfer[1].rx_buf = (unsigned long) &response;
xfer[1].len = 1;
// Do the transaction
status = ioctl(_fd, SPI_IOC_MESSAGE(2), xfer);
if (status < 0) {
perror("ioctl SPI_IOC_MESSAGE failed");
exit(1);
}
2022-02-13 18:19:33 -05:00
#else
#error "SPI transfer not implemented for library type"
#endif
2018-04-05 12:10:42 -04:00
return response;
}
2022-01-14 14:56:10 -05:00
void ISR_VECT LoRaClass::onDio0Rise()
2018-04-05 12:10:42 -04:00
{
LoRa.handleDio0Rise();
}
2022-02-13 16:58:04 -05:00
LoRaClass LoRa;