Files
Rocket2021/lib/SX12XX-LoRa/src/SX126XLT.cpp
2021-05-11 20:43:42 +03:00

3495 lines
77 KiB
C++

/*
Copyright 2019 - Stuart Robinson
Licensed under a MIT license displayed at the bottom of this document.
17/12/19
*/
/*
Parts of code Copyright (c) 2013, SEMTECH S.A.
See LICENSE.TXT file included in the library
*/
#include <SX126XLT.h>
#include <SPI.h>
#define LTUNUSED(v) (void) (v) //add LTUNUSED(variable); to avoid compiler warnings
#define USE_SPI_TRANSACTION
//#define DEBUGBUSY //comment out if you do not want a busy timeout message
//#define SX126XDEBUG //enable debug messages
//#define SX126XDEBUG3 //enable debug messages
//#define SX126XDEBUGPINS //enable pin allocation debug messages
//#define DEBUGFSKRTTY //enable for FSKRTTY debugging
/*
****************************************************************************
To Do:
****************************************************************************
*/
SX126XLT::SX126XLT()
{
//Anything you need when instantiating your object goes here
}
/* Formats for :begin
original > begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinDIO2, int8_t pinDIO3, int8_t pinSW, uint8_t device);
1 All pins > begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinDIO2, int8_t pinDIO3, int8_t pinRXEN, int8_t pinTXEN, int8_t pinSW, uint8_t device)
2 NiceRF > begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, uint8_t device)
3 Dorji > begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinSW, uint8_t device)
4 Ebyte > begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinRXEN, int8_t pinTXEN, uint8_t device)
*/
bool SX126XLT::begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinDIO2, int8_t pinDIO3, int8_t pinRXEN, int8_t pinTXEN, int8_t pinSW, uint8_t device)
{
//format 1 pins, assign all available pins
_NSS = pinNSS;
_NRESET = pinNRESET;
_RFBUSY = pinRFBUSY;
_DIO1 = pinDIO1;
_DIO2 = pinDIO2;
_DIO3 = pinDIO3;
_RXEN = pinRXEN;
_TXEN = pinTXEN;
_SW = pinSW;
_Device = device;
_TXDonePin = pinDIO1; //this is defalt pin for sensing TX done
_RXDonePin = pinDIO1; //this is defalt pin for sensing RX done
pinMode(_NSS, OUTPUT);
digitalWrite(_NSS, HIGH);
pinMode(_NRESET, OUTPUT);
digitalWrite(_NRESET, LOW);
pinMode(_RFBUSY, INPUT);
#ifdef SX126XDEBUGPINS
Serial.println(F("format 1 begin()"));
Serial.println(F("SX126XLT constructor instantiated successfully"));
Serial.print(F("NSS "));
Serial.println(_NSS);
Serial.print(F("NRESET "));
Serial.println(_NRESET);
Serial.print(F("RFBUSY "));
Serial.println(_RFBUSY);
Serial.print(F("DIO1 "));
Serial.println(_DIO1);
Serial.print(F("DIO2 "));
Serial.println(_DIO2);
Serial.print(F("DIO3 "));
Serial.println(_DIO3);
Serial.print(F("RX_EN "));
Serial.println(_RXEN);
Serial.print(F("TXEN "));
Serial.println(_TXEN);
Serial.print(F("SW "));
Serial.println(_SW);
#endif
if (_DIO1 >= 0)
{
pinMode( _DIO1, INPUT);
}
if (_DIO2 >= 0)
{
pinMode( _DIO2, INPUT);
}
if (_DIO3 >= 0)
{
pinMode( _DIO3, INPUT);
}
if ((_RXEN >= 0) && (_TXEN >= 0))
{
#ifdef SX126XDEBUGPINS
Serial.println(F("RX_EN & TX_EN switching enabled"));
#endif
pinMode(_RXEN, OUTPUT);
pinMode(_TXEN, OUTPUT);
_rxtxpinmode = true;
}
else
{
#ifdef SX126XDEBUGPINS
Serial.println(F("RX_EN & TX_EN not used"));
#endif
_rxtxpinmode = false;
}
if (_SW >= 0)
{
pinMode( _SW, OUTPUT); //Dorji devices have an RW pin that needs to be set high to power antenna switch
digitalWrite(_SW, HIGH);
}
resetDevice();
if (checkDevice())
{
return true;
}
return false;
}
bool SX126XLT::begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, uint8_t device)
{
//format 2 pins for NiceRF, NSS, NRESET, RFBUSY, DIO1
_NSS = pinNSS;
_NRESET = pinNRESET;
_RFBUSY = pinRFBUSY;
_DIO1 = pinDIO1;
_DIO2 = -1;
_DIO3 = -1;
_RXEN = -1;
_TXEN = -1;
_SW = -1;
_Device = device;
_TXDonePin = pinDIO1; //this is defalt pin for sensing TX done
_RXDonePin = pinDIO1; //this is defalt pin for sensing RX done
pinMode(_NSS, OUTPUT);
digitalWrite(_NSS, HIGH);
pinMode(_NRESET, OUTPUT);
digitalWrite(_NRESET, LOW);
pinMode(_RFBUSY, INPUT);
#ifdef SX126XDEBUGPINS
Serial.println(F("format 2 NiceRF begin()"));
Serial.println(F("SX126XLT constructor instantiated successfully"));
Serial.print(F("NSS "));
Serial.println(_NSS);
Serial.print(F("NRESET "));
Serial.println(_NRESET);
Serial.print(F("RFBUSY "));
Serial.println(_RFBUSY);
Serial.print(F("DIO1 "));
Serial.println(_DIO1);
Serial.print(F("DIO2 "));
Serial.println(_DIO2);
Serial.print(F("DIO3 "));
Serial.println(_DIO3);
Serial.print(F("RX_EN "));
Serial.println(_RXEN);
Serial.print(F("TX_EN "));
Serial.println(_TXEN);
Serial.print(F("SW "));
Serial.println(_SW);
#endif
if (_DIO1 >= 0)
{
pinMode( _DIO1, INPUT);
}
#ifdef SX126XDEBUGPINS
Serial.println(F("RX_EN & TX_EN switching disabled"));
#endif
_rxtxpinmode = false;
resetDevice();
if (checkDevice())
{
return true;
}
return false;
}
bool SX126XLT::begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinSW, uint8_t device)
{
//format 3 pins for Dorji, NSS, NRESET, RFBUSY, DIO1, SW
_NSS = pinNSS;
_NRESET = pinNRESET;
_RFBUSY = pinRFBUSY;
_DIO1 = pinDIO1;
_DIO2 = -1;
_DIO3 = -1;
_RXEN = -1;
_TXEN = -1;
_SW = pinSW;
_Device = device;
_TXDonePin = pinDIO1; //this is defalt pin for sensing TX done
_RXDonePin = pinDIO1; //this is defalt pin for sensing RX done
pinMode(_NSS, OUTPUT);
digitalWrite(_NSS, HIGH);
pinMode(_NRESET, OUTPUT);
digitalWrite(_NRESET, LOW);
pinMode(_RFBUSY, INPUT);
#ifdef SX126XDEBUGPINS
Serial.println(F("format 3 Dorji begin()"));
Serial.println(F("SX126XLT constructor instantiated successfully"));
Serial.print(F("NSS "));
Serial.println(_NSS);
Serial.print(F("NRESET "));
Serial.println(_NRESET);
Serial.print(F("RFBUSY "));
Serial.println(_RFBUSY);
Serial.print(F("DIO1 "));
Serial.println(_DIO1);
Serial.print(F("DIO2 "));
Serial.println(_DIO2);
Serial.print(F("DIO3 "));
Serial.println(_DIO3);
Serial.print(F("RX_EN "));
Serial.println(_RXEN);
Serial.print(F("TX_EN "));
Serial.println(_TXEN);
Serial.print(F("SW "));
Serial.println(_SW);
#endif
if (_DIO1 >= 0)
{
pinMode( _DIO1, INPUT);
}
#ifdef SX126XDEBUGPINS
Serial.println(F("RX_EN & TX_EN switching disabled"));
#endif
_rxtxpinmode = false;
if (_SW >= 0)
{
pinMode( _SW, OUTPUT); //Dorji devices have an RW pin that needs to be set high to power antenna switch
digitalWrite(_SW, HIGH);
}
resetDevice();
if (checkDevice())
{
return true;
}
return false;
}
bool SX126XLT::begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinRXEN, int8_t pinTXEN, uint8_t device)
{
//format 4 pins for Ebyte (not tested) , NSS, NRESET, RFBUSY, DIO1, RXEN, TXEN
_NSS = pinNSS;
_NRESET = pinNRESET;
_RFBUSY = pinRFBUSY;
_DIO1 = pinDIO1;
_DIO2 = -1;
_DIO3 = -1;
_RXEN = pinRXEN;
_TXEN = pinTXEN;
_SW = -1;
_Device = device;
_TXDonePin = pinDIO1; //this is defalt pin for sensing TX done
_RXDonePin = pinDIO1; //this is defalt pin for sensing RX done
pinMode(_NSS, OUTPUT);
digitalWrite(_NSS, HIGH);
pinMode(_NRESET, OUTPUT);
digitalWrite(_NRESET, LOW);
pinMode(_RFBUSY, INPUT);
#ifdef SX126XDEBUGPINS
Serial.println(F("format 4 Ebyte begin()"));
Serial.println(F("SX126XLT constructor instantiated successfully"));
Serial.print(F("NSS "));
Serial.println(_NSS);
Serial.print(F("NRESET "));
Serial.println(_NRESET);
Serial.print(F("RFBUSY "));
Serial.println(_RFBUSY);
Serial.print(F("DIO1 "));
Serial.println(_DIO1);
Serial.print(F("DIO2 "));
Serial.println(_DIO2);
Serial.print(F("DIO3 "));
Serial.println(_DIO3);
Serial.print(F("RX_EN "));
Serial.println(_RXEN);
Serial.print(F("TX_EN "));
Serial.println(_TXEN);
Serial.print(F("SW "));
Serial.println(_SW);
#endif
if (_DIO1 >= 0)
{
pinMode( _DIO1, INPUT);
}
if ((_RXEN >= 0) && (_TXEN >= 0))
{
#ifdef SX126XDEBUGPINS
Serial.println(F("RX_EN & TX_EN switching enabled"));
#endif
pinMode(_RXEN, OUTPUT);
pinMode(_TXEN, OUTPUT);
_rxtxpinmode = true;
}
else
{
#ifdef SX126XDEBUGPINS
Serial.println(F("RX_EN & TX_EN switching disabled"));
#endif
_rxtxpinmode = false;
}
if (_SW >= 0)
{
pinMode( _SW, OUTPUT); //Dorji devices have an RW pin that needs to be set high to power antenna switch
digitalWrite(_SW, HIGH);
}
resetDevice();
if (checkDevice())
{
return true;
}
return false;
}
void SX126XLT::checkBusy()
{
#ifdef SX126XDEBUG
//Serial.println(F("checkBusy()"));
#endif
uint8_t busy_timeout_cnt;
busy_timeout_cnt = 0;
while (digitalRead(_RFBUSY))
{
delay(1);
busy_timeout_cnt++;
//this function checks for a timeout on the busy pin
//if there is a timeout the device is set back to the saved settings
//the fuction is of limited benefit, since you cannot know at which stage of the
//operation the timeout occurs, so operation could resume
if (busy_timeout_cnt > 10) //wait 10mS for busy to complete
{
busy_timeout_cnt = 0;
#ifdef DEBUGBUSY
Serial.println(F("ERROR - Busy Timeout!"));
#endif
resetDevice(); //reset device
setMode(MODE_STDBY_RC);
config(); //re-run saved config
break;
}
}
}
void SX126XLT::writeCommand(uint8_t Opcode, uint8_t *buffer, uint16_t size)
{
#ifdef SX126XDEBUG
//Serial.println(F("writeCommand()"));
#endif
uint8_t index;
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(Opcode);
for (index = 0; index < size; index++)
{
SPI.transfer(buffer[index]);
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
if (Opcode != RADIO_SET_SLEEP)
{
checkBusy();
}
}
void SX126XLT::readCommand(uint8_t Opcode, uint8_t *buffer, uint16_t size)
{
#ifdef SX126XDEBUG
//Serial.println(F("readCommand()"));
#endif
uint8_t i;
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(Opcode);
SPI.transfer(0xFF);
for ( i = 0; i < size; i++ )
{
*(buffer + i) = SPI.transfer(0xFF);
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
}
void SX126XLT::writeRegisters(uint16_t address, uint8_t *buffer, uint16_t size)
{
#ifdef SX126XDEBUG
//Serial.println(F("writeRegisters()"));
#endif
uint8_t addr_l, addr_h;
uint8_t i;
addr_l = address & 0xff;
addr_h = address >> 8;
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_WRITE_REGISTER);
SPI.transfer(addr_h); //MSB
SPI.transfer(addr_l); //LSB
for (i = 0; i < size; i++)
{
SPI.transfer(buffer[i]);
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
}
void SX126XLT::writeRegister(uint16_t address, uint8_t value)
{
#ifdef SX126XDEBUG
//Serial.println(F("writeRegisters()"));
#endif
writeRegisters( address, &value, 1 );
}
void SX126XLT::readRegisters(uint16_t address, uint8_t *buffer, uint16_t size)
{
#ifdef SX126XDEBUG
//Serial.println(F("readRegisters()"));
#endif
uint16_t index;
uint8_t addr_l, addr_h;
addr_h = address >> 8;
addr_l = address & 0x00FF;
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_READ_REGISTER);
SPI.transfer(addr_h); //MSB
SPI.transfer(addr_l); //LSB
SPI.transfer(0xFF);
for (index = 0; index < size; index++)
{
*(buffer + index) = SPI.transfer(0xFF);
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
}
uint8_t SX126XLT::readRegister(uint16_t address)
{
#ifdef SX126XDEBUG
//Serial.println(F("readRegister()"));
#endif
uint8_t data;
readRegisters(address, &data, 1);
return data;
}
void SX126XLT::resetDevice()
{
#ifdef SX126XDEBUG
Serial.println(F("resetDevice()"));
#endif
delay(10);
digitalWrite(_NRESET, LOW);
delay(2);
digitalWrite(_NRESET, HIGH);
delay(25);
checkBusy();
}
bool SX126XLT::checkDevice()
{
//check there is a device out there, writes a register and reads back
#ifdef SX126XDEBUG
Serial.println(F("checkDevice()"));
#endif
uint8_t Regdata1, Regdata2;
Regdata1 = readRegister(0x88e); //low byte of frequency setting
writeRegister(0x88e, (Regdata1 + 1));
Regdata2 = readRegister(0x88e); //read changed value back
writeRegister(0x88e, Regdata1); //restore register to original value
if (Regdata2 == (Regdata1 + 1))
{
return true;
}
else
{
return false;
}
}
void SX126XLT::setupLoRa(uint32_t frequency, int32_t offset, uint8_t modParam1, uint8_t modParam2, uint8_t modParam3, uint8_t modParam4)
{
//order of passed parameters is, frequency, offset, spreadingfactor, bandwidth, coderate, optimisation
#ifdef SX126XDEBUG
Serial.println(F("setupLoRa()"));
#endif
setMode(MODE_STDBY_RC);
setRegulatorMode(USE_DCDC);
setPaConfig(0x04, PAAUTO, _Device); //use _Device, saved by begin.
setDIO3AsTCXOCtrl(TCXO_CTRL_3_3V);
calibrateDevice(ALLDevices); //is required after setting TCXO
calibrateImage(frequency);
setDIO2AsRfSwitchCtrl();
setPacketType(PACKET_TYPE_LORA);
setRfFrequency(frequency, offset);
setModulationParams(modParam1, modParam2, modParam3, modParam4);
setBufferBaseAddress(0, 0);
setPacketParams(8, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL);
setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on TX done and timeout on DIO1
setHighSensitivity(); //set for maximum gain
setSyncWord(LORA_MAC_PRIVATE_SYNCWORD);
}
void SX126XLT::setMode(uint8_t modeconfig)
{
#ifdef SX126XDEBUG
Serial.println(F("setMode()"));
#endif
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_SET_STANDBY);
SPI.transfer(modeconfig);
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
_OperatingMode = modeconfig;
}
void SX126XLT::setRegulatorMode(uint8_t mode)
{
#ifdef SX126XDEBUG
Serial.println(F("setRegulatorMode()"));
#endif
savedRegulatorMode = mode;
writeCommand(RADIO_SET_REGULATORMODE, &mode, 1);
}
void SX126XLT::setPaConfig(uint8_t dutycycle, uint8_t hpMax, uint8_t device)
{
#ifdef SX126XDEBUG
Serial.println(F("setPaConfig()"));
#endif
uint8_t buffer[4];
if (hpMax == PAAUTO)
{
if (device == DEVICE_SX1261)
{
hpMax = 0x00;
}
if (device == DEVICE_SX1262)
{
hpMax = 0x07;
}
if (device == DEVICE_SX1268)
{
hpMax = 0x07;
}
}
if (_Device == DEVICE_SX1261)
{
device = 1;
}
else
{
device = 0;
}
buffer[0] = dutycycle; //paDutyCycle
buffer[1] = hpMax; //hpMax:0x00~0x07; 7 for =22dbm
buffer[2] = device; //deviceSel: 0 = SX1262; 1 = SX1261; 0 = SX1268;
buffer[3] = 0x01; //reserved, always 0x01
writeCommand(RADIO_SET_PACONFIG, buffer, 4);
}
void SX126XLT::setDIO3AsTCXOCtrl(uint8_t tcxoVoltage)
{
#ifdef SX126XDEBUG
Serial.println(F("setDIO3AsTCXOCtrl()"));
#endif
uint8_t buffer[4];
buffer[0] = tcxoVoltage;
buffer[1] = 0x00;
buffer[2] = 0x00;
buffer[3] = 0x64;
writeCommand(RADIO_SET_TCXOMODE, buffer, 4);
}
void SX126XLT::calibrateDevice(uint8_t devices)
{
#ifdef SX126XDEBUG
Serial.println(F("calibrateDevice()"));
#endif
writeCommand(RADIO_CALIBRATE, &devices, 1);
delay(5); //calibration time for all devices is 3.5mS, SX126x
}
void SX126XLT::calibrateImage(uint32_t freq)
{
#ifdef SX126XDEBUG
Serial.println(F("calibrateImage()"));
#endif
uint8_t calFreq[2];
if ( freq > 900000000 )
{
calFreq[0] = 0xE1;
calFreq[1] = 0xE9;
}
else if ( freq > 850000000 )
{
calFreq[0] = 0xD7;
calFreq[1] = 0xD8;
}
else if ( freq > 770000000 )
{
calFreq[0] = 0xC1;
calFreq[1] = 0xC5;
}
else if ( freq > 460000000 )
{
calFreq[0] = 0x75;
calFreq[1] = 0x81;
}
else if ( freq > 425000000 )
{
calFreq[0] = 0x6B;
calFreq[1] = 0x6F;
}
writeCommand( RADIO_CALIBRATEIMAGE, calFreq, 2 );
}
void SX126XLT::setDIO2AsRfSwitchCtrl()
{
#ifdef SX126XDEBUG
Serial.println(F("setDIO2AsRfSwitchCtrl()"));
#endif
uint8_t mode = 0x01;
writeCommand(RADIO_SET_RFSWITCHMODE, &mode, 1);
}
void SX126XLT::setPacketType(uint8_t packettype )
{
#ifdef SX126XDEBUG
Serial.println(F("setPacketType()"));
#endif
savedPacketType = packettype;
writeCommand(RADIO_SET_PACKETTYPE, &packettype, 1);
}
void SX126XLT::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3, uint8_t modParam4)
{
//order for LoRa is spreading factor, bandwidth, code rate, optimisation
#ifdef SX126XDEBUG
Serial.println(F("setModulationParams()"));
#endif
uint8_t regvalue;
uint8_t buffer[4];
regvalue = readRegister(REG_TX_MODULATION);
savedModParam1 = modParam1;
savedModParam2 = modParam2;
savedModParam3 = modParam3;
if (modParam2 == LORA_BW_500)
{
writeRegister(REG_TX_MODULATION, (regvalue & 0xFB)); //if bandwidth is 500k set bit 2 to 0, see datasheet 15.1.1
}
else
{
writeRegister(REG_TX_MODULATION, (regvalue | 0x04)); //if bandwidth is < 500k set bit 2 to 0 see datasheet 15.1.1
}
if (modParam4 == LDRO_AUTO)
{
modParam4 = returnOptimisation(modParam1, modParam2); //pass Spreading factor then bandwidth to optimisation calc
}
savedModParam4 = modParam4;
buffer[0] = modParam1;
buffer[1] = modParam2;
buffer[2] = modParam3;
buffer[3] = modParam4;
writeCommand(RADIO_SET_MODULATIONPARAMS, buffer, 4);
}
uint8_t SX126XLT::returnOptimisation(uint8_t SpreadingFactor, uint8_t Bandwidth)
{
//from the passed bandwidth (bandwidth) and spreading factor this routine
//calculates whether low data rate optimisation should be on or off
#ifdef SX126XDEBUG
Serial.println(F("returnOptimisation()"));
#endif
uint32_t tempBandwidth;
float symbolTime;
tempBandwidth = returnBandwidth(Bandwidth);
symbolTime = calcSymbolTime(tempBandwidth, SpreadingFactor);
if (symbolTime > 16)
{
return LDRO_ON;
}
else
{
return LDRO_OFF;
}
}
uint32_t SX126XLT::returnBandwidth(uint8_t BWregvalue)
{
#ifdef SX126XDEBUG
Serial.println(F("returnBandwidth()"));
#endif
switch (BWregvalue)
{
case 0:
return 7800;
case 8:
return 10400;
case 1:
return 15600;
case 9:
return 20800;
case 2:
return 31200;
case 10:
return 41700;
case 3:
return 62500;
case 4:
return 125000;
case 5:
return 250000;
case 6:
return 500000;
default:
break;
}
return 0xFFFF; //so that a bandwidth not set can be identified
}
float SX126XLT::calcSymbolTime(float Bandwidth, uint8_t SpreadingFactor)
{
//calculates symbol time from passed bandwidth (lbandwidth) and Spreading factor (lSF)and returns in mS
#ifdef SX126XDEBUG
Serial.println(F("calcSymbolTime()"));
#endif
float symbolTimemS;
symbolTimemS = (Bandwidth / pow(2, SpreadingFactor));
symbolTimemS = (1000 / symbolTimemS);
return symbolTimemS;
}
void SX126XLT::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress)
{
#ifdef SX126XDEBUG
Serial.println(F("setBufferBaseAddress()"));
#endif
uint8_t buffer[2];
buffer[0] = txBaseAddress;
buffer[1] = rxBaseAddress;
writeCommand(RADIO_SET_BUFFERBASEADDRESS, buffer, 2);
}
void SX126XLT::setPacketParams(uint16_t packetParam1, uint8_t packetParam2, uint8_t packetParam3, uint8_t packetParam4, uint8_t packetParam5)
{
//order is preamble, header type, packet length, CRC, IQ
#ifdef SX126XDEBUG
Serial.println(F("SetPacketParams()"));
#endif
uint8_t preambleMSB, preambleLSB;
preambleMSB = packetParam1 >> 8;
preambleLSB = packetParam1 & 0xFF;
savedPacketParam1 = packetParam1;
savedPacketParam2 = packetParam2;
savedPacketParam3 = packetParam3;
savedPacketParam4 = packetParam4;
savedPacketParam5 = packetParam5;
uint8_t buffer[9];
buffer[0] = preambleMSB;
buffer[1] = preambleLSB;
buffer[2] = packetParam2;
buffer[3] = packetParam3;
buffer[4] = packetParam4;
buffer[5] = packetParam5;
buffer[6] = 0xFF;
buffer[7] = 0xFF;
buffer[8] = 0xFF;
writeCommand(RADIO_SET_PACKETPARAMS, buffer, 9);
}
void SX126XLT::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask )
{
#ifdef SX126XDEBUG
Serial.println(F("setDioIrqParams()"));
#endif
savedIrqMask = irqMask;
savedDio1Mask = dio1Mask;
savedDio2Mask = dio2Mask;
savedDio3Mask = dio3Mask;
uint8_t buffer[8];
buffer[0] = (uint8_t) (irqMask >> 8);
buffer[1] = (uint8_t) (irqMask & 0xFF);
buffer[2] = (uint8_t) (dio1Mask >> 8);
buffer[3] = (uint8_t) (dio1Mask & 0xFF);
buffer[4] = (uint8_t) (dio2Mask >> 8);
buffer[5] = (uint8_t) (dio2Mask & 0xFF);
buffer[6] = (uint8_t) (dio3Mask >> 8);
buffer[7] = (uint8_t) (dio3Mask & 0xFF);
writeCommand(RADIO_CFG_DIOIRQ, buffer, 8);
}
void SX126XLT::setHighSensitivity()
{
//set RX Boosted gain mode
#ifdef SX126XDEBUG
Serial.println(F("setHighSensitivity()"));
#endif
writeRegister( REG_RX_GAIN, BOOSTED_GAIN ); //max LNA gain, increase current by ~2mA for around ~3dB in sensivity
}
void SX126XLT::setLowPowerRX()
{
//set RX power saving mode
#ifdef SX126XDEBUG
Serial.println(F("setLowPowerRX()"));
#endif
writeRegister( REG_RX_GAIN, POWER_SAVE_GAIN ); // min LNA gain, reduce current by 2mA for around 3dB loss in sensivity
}
void SX126XLT::setSyncWord(uint16_t syncword)
{
#ifdef SX126XDEBUG
Serial.println(F("setSyncWord()"));
#endif
writeRegister( REG_LR_SYNCWORD, ( syncword >> 8 ) & 0xFF );
writeRegister( REG_LR_SYNCWORD + 1, syncword & 0xFF );
}
void SX126XLT::printModemSettings()
{
#ifdef SX126XDEBUG
Serial.println(F("printModemSettings()"));
#endif
printDevice();
Serial.print(F(","));
Serial.print(getFreqInt());
Serial.print(F("hz,SF"));
Serial.print(getLoRaSF());
Serial.print(F(",BW"));
Serial.print(returnBandwidth(savedModParam2));
Serial.print(F(",CR4:"));
Serial.print((getLoRaCodingRate() + 4));
Serial.print(F(",LDRO_"));
if (getOptimisation())
{
Serial.print(F("On"));
}
else
{
Serial.print(F("Off"));
}
Serial.print(F(",SyncWord_0x"));
Serial.print(getSyncWord(), HEX);
if (getInvertIQ() == LORA_IQ_INVERTED)
{
Serial.print(F(",IQInverted"));
}
else
{
Serial.print(F(",IQNormal"));
}
Serial.print(F(",Preamble_"));
Serial.print(getPreamble());
}
uint32_t SX126XLT::getFreqInt()
{
//get the current set device frequency from registers, return as long integer
#ifdef SX126XDEBUG
Serial.println(F("getFreqInt()"));
#endif
uint8_t MsbH, MsbL, Mid, Lsb;
uint32_t uinttemp;
float floattemp;
MsbH = readRegister(REG_RFFrequency31_24);
MsbL = readRegister(REG_RFFrequency23_16);
Mid = readRegister(REG_RFFrequency15_8);
Lsb = readRegister(REG_RFFrequency7_0);
floattemp = ( (MsbH * 0x1000000ul) + (MsbL * 0x10000ul) + (Mid * 0x100ul) + Lsb);
floattemp = ((floattemp * FREQ_STEP) / 1000000ul);
uinttemp = (uint32_t)(floattemp * 1000000);
return uinttemp;
}
uint8_t SX126XLT::getLoRaCodingRate()
{
#ifdef SX126XDEBUG
Serial.println(F("getLoRaCodingRate"));
#endif
return savedModParam3;
}
uint8_t SX126XLT::getOptimisation()
{
#ifdef SX126XDEBUG
Serial.println(F("getOptimisation"));
#endif
return savedModParam4;
}
uint16_t SX126XLT::getSyncWord()
{
#ifdef SX126XDEBUG
Serial.println(F("getSyncWord"));
#endif
uint8_t msb, lsb;
uint16_t syncword;
msb = readRegister(REG_LR_SYNCWORD);
lsb = readRegister(REG_LR_SYNCWORD + 1);
syncword = (msb << 8) + lsb;
return syncword;
}
uint16_t SX126XLT::getPreamble()
{
#ifdef SX126XDEBUG
Serial.println(F("getPreamble"));
#endif
return savedPacketParam1;
}
void SX126XLT::printOperatingSettings()
{
#ifdef SX126XDEBUG
Serial.println(F("printOperatingSettings()"));
#endif
printDevice();
Serial.print(F(",PacketMode_"));
if (savedPacketType == PACKET_TYPE_LORA)
{
Serial.print(F("LoRa"));
}
if (savedPacketType == PACKET_TYPE_GFSK)
{
Serial.print(F("GFSK"));
}
if (getHeaderMode())
{
Serial.print(F(",Implicit"));
}
else
{
Serial.print(F(",Explicit"));
}
Serial.print(F(",LNAgain_"));
if (getLNAgain() == BOOSTED_GAIN)
{
Serial.print(F("Boosted"));
}
else
{
Serial.print(F("Powersave"));
}
}
uint8_t SX126XLT::getHeaderMode()
{
#ifdef SX126XDEBUG
Serial.println(F("getHeaderMode"));
#endif
return savedPacketParam2;
}
uint8_t SX126XLT::getLNAgain()
{
#ifdef SX126XDEBUG
Serial.println(F("getLNAgain"));
#endif
return readRegister(REG_RX_GAIN);
}
void SX126XLT::setTxParams(int8_t TXpower, uint8_t RampTime)
{
//note this routine does not check if power levels are valid for the module in use
#ifdef SX126XDEBUG
Serial.println(F("setTxParams()"));
#endif
uint8_t buffer[2];
savedTXPower = TXpower;
buffer[0] = TXpower;
buffer[1] = (uint8_t)RampTime;
writeCommand(RADIO_SET_TXPARAMS, buffer, 2);
}
void SX126XLT::setTx(uint32_t timeout)
{
//SX126x base timeout in units of 15.625 µs
//Note: timeout passed to function is in mS
#ifdef SX126XDEBUG
Serial.println(F("setTx()"));
#endif
uint8_t buffer[3];
clearIrqStatus(IRQ_RADIO_ALL);
if (_rxtxpinmode)
{
txEnable();
}
timeout = timeout << 6; //timeout passed in mS, convert to units of 15.625us
buffer[0] = (timeout >> 16) & 0xFF;
buffer[1] = (timeout >> 8) & 0xFF;
buffer[2] = timeout & 0xFF;
writeCommand(RADIO_SET_TX, buffer, 3 );
_OperatingMode = MODE_TX;
}
void SX126XLT::clearIrqStatus(uint16_t irqMask)
{
#ifdef SX126XDEBUG
Serial.println(F("clearIrqStatus()"));
#endif
uint8_t buffer[2];
buffer[0] = (uint8_t) (irqMask >> 8);
buffer[1] = (uint8_t) (irqMask & 0xFF);
writeCommand(RADIO_CLR_IRQSTATUS, buffer, 2);
}
uint16_t SX126XLT::readIrqStatus()
{
#ifdef SX126XDEBUG
Serial.print(F("readIrqStatus()"));
#endif
uint16_t temp;
uint8_t buffer[2];
readCommand(RADIO_GET_IRQSTATUS, buffer, 2);
temp = ((buffer[0] << 8) + buffer[1]);
return temp;
}
uint16_t SX126XLT::CRCCCITT(uint8_t *buffer, uint8_t size, uint16_t start)
{
#ifdef SX126XDEBUG
Serial.println(F("CRCCCITT()"));
#endif
uint16_t index, libraryCRC;
uint8_t j;
libraryCRC = start; //start value for CRC16
for (index = 0; index < size; index++)
{
libraryCRC ^= (((uint16_t)buffer[index]) << 8);
for (j = 0; j < 8; j++)
{
if (libraryCRC & 0x8000)
libraryCRC = (libraryCRC << 1) ^ 0x1021;
else
libraryCRC <<= 1;
}
}
return libraryCRC;
}
uint8_t SX126XLT::transmit(uint8_t *txbuffer, uint8_t size, uint32_t txtimeout, int8_t txpower, uint8_t wait)
{
#ifdef SX126XDEBUG
Serial.println(F("transmit()"));
#endif
uint8_t index;
uint8_t bufferdata;
if (size == 0)
{
return false;
}
setMode(MODE_STDBY_RC);
setBufferBaseAddress(0, 0);
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_WRITE_BUFFER);
SPI.transfer(0);
for (index = 0; index < size; index++)
{
bufferdata = txbuffer[index];
SPI.transfer(bufferdata);
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
_TXPacketL = size;
writeRegister(REG_LR_PAYLOADLENGTH, _TXPacketL);
setTxParams(txpower, RADIO_RAMP_200_US);
setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on TX done and timeout on DIO1
setTx(txtimeout); //this starts the TX
if (!wait)
{
return _TXPacketL;
}
while (!digitalRead(_TXDonePin)); //Wait for DIO1 to go high
if (readIrqStatus() & IRQ_RX_TX_TIMEOUT ) //check for timeout
{
return 0;
}
else
{
return _TXPacketL;
}
}
void SX126XLT::printIrqStatus()
{
#ifdef SX126XDEBUG
Serial.println(F("printIrqStatus()"));
#endif
uint16_t _IrqStatus;
_IrqStatus = readIrqStatus();
//0x0001
if (_IrqStatus & IRQ_TX_DONE)
{
Serial.print(F(",IRQ_TX_DONE"));
}
//0x0002
if (_IrqStatus & IRQ_RX_DONE)
{
Serial.print(F(",IRQ_RX_DONE"));
}
//0x0004
if (_IrqStatus & IRQ_PREAMBLE_DETECTED)
{
Serial.print(F(",IRQ_PREAMBLE_DETECTED"));
}
//0x0008
if (_IrqStatus & IRQ_SYNCWORD_VALID)
{
Serial.print(F(",IRQ_SYNCWORD_VALID"));
}
//0x0010
if (_IrqStatus & IRQ_HEADER_VALID)
{
Serial.print(F(",IRQ_HEADER_VALID"));
}
//0x0020
if (_IrqStatus & IRQ_HEADER_ERROR)
{
Serial.print(F(",IRQ_HEADER_ERROR"));
}
//0x0040
if (_IrqStatus & IRQ_CRC_ERROR)
{
Serial.print(F(",IRQ_CRC_ERROR"));
}
//0x0080
if (_IrqStatus & IRQ_CAD_DONE)
{
Serial.print(F(",IRQ_CAD_DONE"));
}
//0x0100
if (_IrqStatus & IRQ_CAD_ACTIVITY_DETECTED)
{
Serial.print(",IRQ_CAD_ACTIVITY_DETECTED");
}
//0x0200
if (_IrqStatus & IRQ_RX_TX_TIMEOUT)
{
Serial.print(F(",IRQ_RX_TX_TIMEOUT"));
}
}
void SX126XLT::printRegisters(uint16_t Start, uint16_t End)
{
//prints the contents of SX1262 registers to serial monitor
#ifdef SX126XDEBUG
Serial.println(F("printRegisters()"));
#endif
uint16_t Loopv1, Loopv2, RegData;
Serial.print(F("Reg 0 1 2 3 4 5 6 7 8 9 A B C D E F"));
Serial.println();
for (Loopv1 = Start; Loopv1 <= End;) //32 lines
{
Serial.print(F("0x"));
Serial.print((Loopv1), HEX); //print the register number
Serial.print(F(" "));
for (Loopv2 = 0; Loopv2 <= 15; Loopv2++)
{
RegData = readRegister(Loopv1);
if (RegData < 0x10)
{
Serial.print(F("0"));
}
Serial.print(RegData, HEX); //print the register number
Serial.print(F(" "));
Loopv1++;
}
Serial.println();
}
}
void SX126XLT::printDevice()
{
#ifdef SX126XDEBUG
Serial.println(F("printDevice()"));
#endif
switch (_Device)
{
case DEVICE_SX1261:
Serial.print(F("SX1261"));
break;
case DEVICE_SX1262:
Serial.print(F("SX1262"));
break;
case DEVICE_SX1268:
Serial.print(F("SX1268"));
break;
default:
Serial.print(F("Unknown Device"));
}
}
bool SX126XLT::config()
{
#ifdef SX126XDEBUG
Serial.println(F("config()"));
#endif
resetDevice();
setMode(MODE_STDBY_RC);
setRegulatorMode(savedRegulatorMode);
setPacketType(savedPacketType);
setRfFrequency(savedFrequency, savedOffset);
setModulationParams(savedModParam1, savedModParam2, savedModParam3, LDRO_ON);
setPacketParams(savedPacketParam1, savedPacketParam2, savedPacketParam3, savedPacketParam4, savedPacketParam5);
setDioIrqParams(savedIrqMask, savedDio1Mask, savedDio2Mask, savedDio3Mask); //set for IRQ on RX done on DIO1
_TXPacketL = 0;
_RXPacketL = 0;
return true;
}
void SX126XLT::setRfFrequency( uint32_t frequency, int32_t offset )
{
//Note RF_Freq = freq_reg*32M/(2^25)-----> freq_reg = (RF_Freq * (2^25))/32
#ifdef SX126XDEBUG
Serial.print(F("setRfFrequency() "));
Serial.println(frequency + offset);
#endif
uint8_t buffer[4];
uint32_t localfrequencyRegs;
savedFrequency = frequency;
savedOffset = offset;
localfrequencyRegs = frequency + offset;
localfrequencyRegs = ( uint32_t )( ( double )localfrequencyRegs / ( double )FREQ_STEP );
savedFrequencyReg = localfrequencyRegs;
buffer[0] = (localfrequencyRegs >> 24) & 0xFF; //MSB
buffer[1] = (localfrequencyRegs >> 16) & 0xFF;
buffer[2] = (localfrequencyRegs >> 8) & 0xFF;
buffer[3] = localfrequencyRegs & 0xFF;//LSB
_freqregH = buffer[0];
_freqregMH = buffer[1];
_freqregML = buffer[2];
_freqregL = buffer[3];
writeCommand(RADIO_SET_RFFREQUENCY, buffer, 4);
}
uint8_t SX126XLT::getLoRaSF()
{
#ifdef SX126XDEBUG
Serial.println(F("getLoRaSF()"));
#endif
return savedModParam1;
}
uint8_t SX126XLT::getInvertIQ()
{
//IQ mode reg 0x33
#ifdef SX126XDEBUG
Serial.println(F("getInvertIQ"));
#endif
return readRegister(REG_IQ_POLARITY_SETUP);
}
void SX126XLT::rxEnable()
{
#ifdef SX126XDEBUG
Serial.println(F("rxEnable()"));
#endif
digitalWrite(_RXEN, HIGH);
digitalWrite(_TXEN, LOW);
}
void SX126XLT::txEnable()
{
#ifdef SX126XDEBUGPINS
Serial.println(F("txEnable()"));
#endif
digitalWrite(_RXEN, LOW);
digitalWrite(_TXEN, HIGH);
}
void SX126XLT::printASCIIPacket(uint8_t *buffer, uint8_t size)
{
#ifdef SX126XDEBUGPINS
Serial.println(F("printASCIIPacket()"));
#endif
uint8_t index;
for (index = 0; index < size; index++)
{
Serial.write(buffer[index]);
}
}
uint8_t SX126XLT::receive(uint8_t *rxbuffer, uint8_t size, uint32_t rxtimeout, uint8_t wait)
{
#ifdef SX126XDEBUG
Serial.println(F("receive()"));
#endif
uint8_t index, RXstart, RXend;
uint16_t regdata;
uint8_t buffer[2];
setDioIrqParams(IRQ_RADIO_ALL, (IRQ_RX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on RX done or timeout
setRx(rxtimeout);
if (!wait)
{
return 0; //not wait requested so no packet length to pass
}
while (!digitalRead(_RXDonePin)); //Wait for DIO1 to go high
setMode(MODE_STDBY_RC); //ensure to stop further packet reception
regdata = readIrqStatus();
if ( (regdata & IRQ_HEADER_ERROR) | (regdata & IRQ_CRC_ERROR) | (regdata & IRQ_RX_TX_TIMEOUT ) ) //check if any of the preceding IRQs is set
{
//packet is errored somewhere so return 0
return 0;
}
readCommand(RADIO_GET_RXBUFFERSTATUS, buffer, 2);
_RXPacketL = buffer[0];
if (_RXPacketL > size) //check passed buffer is big enough for packet
{
_RXPacketL = size; //truncate packet if not enough space
}
RXstart = buffer[1];
RXend = RXstart + _RXPacketL;
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW); //start the burst read
SPI.transfer(RADIO_READ_BUFFER);
SPI.transfer(RXstart);
SPI.transfer(0xFF);
for (index = RXstart; index < RXend; index++)
{
regdata = SPI.transfer(0);
rxbuffer[index] = regdata;
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
return _RXPacketL; //so we can check for packet having enough buffer space
}
uint8_t SX126XLT::readPacketRSSI()
{
#ifdef SX126XDEBUG
Serial.println(F("readPacketRSSI()"));
#endif
uint8_t status[5];
readCommand(RADIO_GET_PACKETSTATUS, status, 5) ;
_PacketRSSI = -status[0] / 2;
return _PacketRSSI;
}
uint8_t SX126XLT::readPacketSNR()
{
#ifdef SX126XDEBUG
Serial.println(F("readPacketSNR()"));
#endif
uint8_t status[5];
readCommand(RADIO_GET_PACKETSTATUS, status, 5) ;
if ( status[1] < 128 )
{
_PacketSNR = status[1] / 4 ;
}
else
{
_PacketSNR = (( status[1] - 256 ) / 4);
}
return _PacketSNR;
}
uint8_t SX126XLT::readRXPacketL()
{
#ifdef SX126XDEBUG
Serial.println(F("readRXPacketL()"));
#endif
uint8_t buffer[2];
readCommand(RADIO_GET_RXBUFFERSTATUS, buffer, 2);
_RXPacketL = buffer[0];
return _RXPacketL;
}
void SX126XLT::setRx(uint32_t timeout)
{
//SX126x base timeout in units of 15.625 µs
//timeout passed to function in mS
//range is 1mS to 262 seconds
#ifdef SX126XDEBUG
Serial.println(F("setRx()"));
#endif
uint8_t buffer[3];
clearIrqStatus(IRQ_RADIO_ALL);
if (_rxtxpinmode)
{
rxEnable();
}
timeout = timeout << 6; //timeout passed in mS, multiply by 64 to convert units of 15.625us to 1mS
buffer[0] = (timeout >> 16) & 0xFF;
buffer[1] = (timeout >> 8) & 0xFF;
buffer[2] = timeout & 0xFF;
writeCommand(RADIO_SET_RX, buffer, 3 );
}
/***************************************************************************
//Start direct access SX buffer routines
***************************************************************************/
void SX126XLT::startWriteSXBuffer(uint8_t ptr)
{
#ifdef SX126XDEBUG
Serial.println(F("startWriteSXBuffer()"));
#endif
_TXPacketL = 0; //this variable used to keep track of bytes written
setMode(MODE_STDBY_RC);
setBufferBaseAddress(ptr, 0); //TX,RX
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_WRITE_BUFFER);
SPI.transfer(ptr);
//SPI interface ready for byte to write to buffer
}
uint8_t SX126XLT::endWriteSXBuffer()
{
#ifdef SX126XDEBUG
Serial.println(F("endWriteSXBuffer()"));
#endif
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
return _TXPacketL;
}
void SX126XLT::startReadSXBuffer(uint8_t ptr)
{
#ifdef SX126XDEBUG
Serial.println(F("startReadSXBuffer"));
#endif
_RXPacketL = 0;
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW); //start the burst read
SPI.transfer(RADIO_READ_BUFFER);
SPI.transfer(ptr);
SPI.transfer(0xFF);
//next line would be data = SPI.transfer(0);
//SPI interface ready for byte to read from
}
uint8_t SX126XLT::endReadSXBuffer()
{
#ifdef SX126XDEBUG
Serial.println(F("endReadSXBuffer()"));
#endif
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
return _RXPacketL;
}
void SX126XLT::writeUint8(uint8_t x)
{
#ifdef SX126XDEBUG
Serial.println(F("writeUint8()"));
#endif
SPI.transfer(x);
_TXPacketL++; //increment count of bytes written
}
uint8_t SX126XLT::readUint8()
{
#ifdef SX126XDEBUG
Serial.println(F("readUint8()"));
#endif
byte x;
x = SPI.transfer(0);
_RXPacketL++; //increment count of bytes read
return (x);
}
void SX126XLT::writeInt8(int8_t x)
{
#ifdef SX126XDEBUG
Serial.println(F("writeInt8()"));
#endif
SPI.transfer(x);
_TXPacketL++; //increment count of bytes written
}
int8_t SX126XLT::readInt8()
{
#ifdef SX126XDEBUG
Serial.println(F("readInt8()"));
#endif
int8_t x;
x = SPI.transfer(0);
_RXPacketL++; //increment count of bytes read
return (x);
}
void SX126XLT::writeInt16(int16_t x)
{
#ifdef SX126XDEBUG
Serial.println(F("writeInt16()"));
#endif
SPI.transfer(lowByte(x));
SPI.transfer(highByte(x));
_TXPacketL = _TXPacketL + 2; //increment count of bytes written
}
int16_t SX126XLT::readInt16()
{
#ifdef SX126XDEBUG
Serial.println(F("readInt16()"));
#endif
byte lowbyte, highbyte;
lowbyte = SPI.transfer(0);
highbyte = SPI.transfer(0);
_RXPacketL = _RXPacketL + 2; //increment count of bytes read
return ((highbyte << 8) + lowbyte);
}
void SX126XLT::writeUint16(uint16_t x)
{
#ifdef SX126XDEBUG
Serial.println(F("writeUint16()"));
#endif
SPI.transfer(lowByte(x));
SPI.transfer(highByte(x));
_TXPacketL = _TXPacketL + 2; //increment count of bytes written
}
uint16_t SX126XLT::readUint16()
{
#ifdef SX126XDEBUG
Serial.println(F("writeUint16()"));
#endif
byte lowbyte, highbyte;
lowbyte = SPI.transfer(0);
highbyte = SPI.transfer(0);
_RXPacketL = _RXPacketL + 2; //increment count of bytes read
return ((highbyte << 8) + lowbyte);
}
void SX126XLT::writeInt32(int32_t x)
{
#ifdef SX126XDEBUG
Serial.println(F("writeInt32()"));
#endif
byte i, j;
union
{
byte b[4];
int32_t f;
} data;
data.f = x;
for (i = 0; i < 4; i++)
{
j = data.b[i];
SPI.transfer(j);
}
_TXPacketL = _TXPacketL + 4; //increment count of bytes written
}
int32_t SX126XLT::readInt32()
{
#ifdef SX126XDEBUG
Serial.println(F("readInt32()"));
#endif
byte i, j;
union
{
byte b[4];
int32_t f;
} readdata;
for (i = 0; i < 4; i++)
{
j = SPI.transfer(0);
readdata.b[i] = j;
}
_RXPacketL = _RXPacketL + 4; //increment count of bytes read
return readdata.f;
}
void SX126XLT::writeUint32(uint32_t x)
{
#ifdef SX126XDEBUG
Serial.println(F("writeUint32()"));
#endif
byte i, j;
union
{
byte b[4];
uint32_t f;
} data;
data.f = x;
for (i = 0; i < 4; i++)
{
j = data.b[i];
SPI.transfer(j);
}
_TXPacketL = _TXPacketL + 4; //increment count of bytes written
}
uint32_t SX126XLT::readUint32()
{
#ifdef SX126XDEBUG
Serial.println(F("readUint32()"));
#endif
byte i, j;
union
{
byte b[4];
uint32_t f;
} readdata;
for (i = 0; i < 4; i++)
{
j = SPI.transfer(0);
readdata.b[i] = j;
}
_RXPacketL = _RXPacketL + 4; //increment count of bytes read
return readdata.f;
}
void SX126XLT::writeFloat(float x)
{
#ifdef SX126XDEBUG
Serial.println(F("writeFloat()"));
#endif
byte i, j;
union
{
byte b[4];
float f;
} data;
data.f = x;
for (i = 0; i < 4; i++)
{
j = data.b[i];
SPI.transfer(j);
}
_TXPacketL = _TXPacketL + 4; //increment count of bytes written
}
float SX126XLT::readFloat()
{
#ifdef SX126XDEBUG
Serial.println(F("readFloat()"));
#endif
byte i, j;
union
{
byte b[4];
float f;
} readdata;
for (i = 0; i < 4; i++)
{
j = SPI.transfer(0);
readdata.b[i] = j;
}
_RXPacketL = _RXPacketL + 4; //increment count of bytes read
return readdata.f;
}
uint8_t SX126XLT::transmitSXBuffer(uint8_t startaddr, uint8_t length, uint32_t txtimeout, int8_t txpower, uint8_t wait)
{
#ifdef SX126XDEBUG
Serial.println(F("transmitSXBuffer()"));
#endif
setBufferBaseAddress(startaddr, 0); //TX, RX
setPacketParams(savedPacketParam1, savedPacketParam2, length, savedPacketParam4, savedPacketParam5);
setTxParams(txpower, RAMP_TIME);
setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on TX done and timeout on DIO1
setTx(txtimeout); //this starts the TX
if (!wait)
{
return _TXPacketL;
}
while (!digitalRead(_TXDonePin)); //Wait for DIO1 to go high
if (readIrqStatus() & IRQ_RX_TX_TIMEOUT ) //check for timeout
{
return 0;
}
else
{
return _TXPacketL;
}
}
void SX126XLT::writeBuffer(uint8_t *txbuffer, uint8_t size)
{
#ifdef SX126XDEBUG1
Serial.println(F("writeBuffer()"));
#endif
uint8_t index, regdata;
_TXPacketL = _TXPacketL + size; //these are the number of bytes that will be added
size--; //loose one byte from size, the last byte written MUST be a 0
for (index = 0; index < size; index++)
{
regdata = txbuffer[index];
SPI.transfer(regdata);
}
SPI.transfer(0); //this ensures last byte of buffer written really is a null (0)
}
uint8_t SX126XLT::receiveSXBuffer(uint8_t startaddr, uint32_t rxtimeout, uint8_t wait )
{
#ifdef SX127XDEBUG1
Serial.println(F("receiveSXBuffer()"));
#endif
uint16_t regdata;
uint8_t buffer[2];
setMode(MODE_STDBY_RC);
setBufferBaseAddress(0, startaddr); //order is TX RX
setDioIrqParams(IRQ_RADIO_ALL, (IRQ_RX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on RX done or timeout
setRx(rxtimeout); //no actual RX timeout in this function
if (!wait)
{
return 0;
}
while (!digitalRead(_RXDonePin)); //Wait for DIO1 to go high
setMode(MODE_STDBY_RC); //ensure to stop further packet reception
regdata = readIrqStatus();
if ( (regdata & IRQ_HEADER_ERROR) | (regdata & IRQ_CRC_ERROR) | (regdata & IRQ_RX_TX_TIMEOUT ) )
{
return 0; //no RX done and header valid only, could be CRC error
}
readCommand(RADIO_GET_RXBUFFERSTATUS, buffer, 2);
_RXPacketL = buffer[0];
return _RXPacketL;
}
uint8_t SX126XLT::readBuffer(uint8_t *rxbuffer)
{
#ifdef SX126XDEBUG1
Serial.println(F("readBuffer()"));
#endif
uint8_t index = 0, regdata;
do //need to find the size of the buffer first
{
regdata = SPI.transfer(0);
rxbuffer[index] = regdata; //fill the buffer.
index++;
} while (regdata != 0); //keep reading until we have reached the null (0) at the buffer end
//or exceeded size of buffer allowed
_RXPacketL = _RXPacketL + index; //increment count of bytes read
return index; //return the actual size of the buffer, till the null (0) detected
}
/***************************************************************************
//End direct access SX buffer routines
***************************************************************************/
uint16_t SX126XLT::CRCCCITTSX(uint8_t startadd, uint8_t endadd, uint16_t startvalue)
{
//genrates a CRC of an area of the internal SX buffer
#ifdef SX126XDEBUG1
Serial.println(F("CRCCCITTSX()"));
#endif
uint16_t index, libraryCRC;
uint8_t j;
libraryCRC = startvalue; //start value for CRC16
startReadSXBuffer(startadd); //begin the buffer read
for (index = startadd; index <= endadd; index++)
{
libraryCRC ^= (((uint16_t) readUint8() ) << 8);
for (j = 0; j < 8; j++)
{
if (libraryCRC & 0x8000)
libraryCRC = (libraryCRC << 1) ^ 0x1021;
else
libraryCRC <<= 1;
}
}
endReadSXBuffer(); //end the buffer read
return libraryCRC;
}
void SX126XLT::setSleep(uint8_t sleepconfig)
{
#ifdef SX126XDEBUG
Serial.println(F("setSleep()"));
#endif
setMode(MODE_STDBY_RC);
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_SET_SLEEP);
SPI.transfer(sleepconfig);
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
if (_SW >= 0)
{
digitalWrite(_SW, LOW); //turn off antenna switch if SW pin in use, saves 9uA.
}
delay(1); //allow time for shutdown
}
void SX126XLT::wake()
{
#ifdef SX126XDEBUG
Serial.println(F("wake()"));
#endif
if (_SW >= 0)
{
digitalWrite(_SW, HIGH); //turn on antenna switch if SW pin in use
}
digitalWrite(_NSS, LOW);
delay(1);
digitalWrite(_NSS, HIGH);
delay(1);
}
void SX126XLT::setupDirect(uint32_t frequency, int32_t offset)
{
//setup LoRa device for direct modulation mode
#ifdef SX126XDEBUG1
Serial.print(F("setupDirect()"));
#endif
setMode(MODE_STDBY_RC);
setRegulatorMode(USE_DCDC);
setPaConfig(0x04, PAAUTO, _Device); //use _Device, saved by begin.
setDIO3AsTCXOCtrl(TCXO_CTRL_3_3V);
calibrateDevice(ALLDevices); //is required after setting TCXO
calibrateImage(frequency);
setDIO2AsRfSwitchCtrl();
setRfFrequency(frequency, offset);
}
void SX126XLT::setTXDirect()
{
//turns on transmitter,in direct mode for FSK and audio power level is from 2 to 17
#ifdef SX127XDEBUG1
Serial.print(F("setTxFSK()"));
#endif
writeCommand(RADIO_SET_TXCONTINUOUSWAVE, 0, 0);
}
void SX126XLT::toneFM(uint16_t frequency, uint32_t length, uint32_t deviation, float adjust, uint8_t txpower)
{
#ifdef SX126XDEBUG1
Serial.print(F("toneFM()"));
#endif
uint16_t index;
uint32_t ToneDelayus;
uint32_t registershift;
uint32_t shiftedfreqregH, shiftedfreqregL;
uint32_t loopcount;
registershift = deviation/FREQ_STEP;
shiftedfreqregH = savedFrequencyReg + registershift;
shiftedfreqregL = savedFrequencyReg - registershift;
uint8_t HighShiftH = shiftedfreqregH >> 24;
uint8_t HighShiftMH = shiftedfreqregH >> 16;
uint8_t HighShiftML = shiftedfreqregH >> 8;
uint8_t HighShiftL = shiftedfreqregH;
uint8_t LowShiftH = shiftedfreqregL >> 24;
uint8_t LowShiftMH = shiftedfreqregL >> 16;
uint8_t LowShiftML = shiftedfreqregL >> 8;
uint8_t LowShiftL = shiftedfreqregL;
uint8_t freqregH = savedFrequencyReg >> 24;
uint8_t freqregMH = savedFrequencyReg >> 16;
uint8_t freqregML = savedFrequencyReg >> 8;
uint8_t freqregL = savedFrequencyReg;
ToneDelayus = ((500000/frequency));
loopcount = (length * 500) / (ToneDelayus);
ToneDelayus = ToneDelayus * adjust;
#ifdef SX126XDEBUG3
Serial.print(F("frequency "));
Serial.println(frequency);
Serial.print(F("length "));
Serial.println(length);
Serial.print(F("savedFrequencyReg "));
Serial.println(savedFrequencyReg, HEX);
Serial.print(F("registershift "));
Serial.println(registershift);
shiftedfreqregH = savedFrequencyReg + (registershift/2);
shiftedfreqregL = savedFrequencyReg - (registershift/2);
Serial.print(F("shiftedfreqregH "));
Serial.println(shiftedfreqregH, HEX);
Serial.print(F("shiftedfreqregL "));
Serial.println(shiftedfreqregL, HEX);
Serial.print(F("ShiftedHigh,"));
Serial.print(HighShiftH,HEX);
Serial.print(F(","));
Serial.print(HighShiftMH,HEX);
Serial.print(F(","));
Serial.print(HighShiftML,HEX);
Serial.print(F(","));
Serial.println(HighShiftL,HEX);
Serial.print(F("ShiftedLow,"));
Serial.print(LowShiftH,HEX);
Serial.print(F(","));
Serial.print(LowShiftMH,HEX);
Serial.print(F(","));
Serial.print(LowShiftML,HEX);
Serial.print(F(","));
Serial.println(LowShiftL,HEX);
Serial.print(F("ToneDelayus,"));
Serial.println(ToneDelayus);
Serial.print(F("loopcount,"));
Serial.println(loopcount);
Serial.println();
Serial.println();
#endif
setTxParams(txpower, RADIO_RAMP_200_US);
setTXDirect();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
for (index = 1; index <= loopcount; index++)
{
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_SET_RFFREQUENCY);
SPI.transfer(HighShiftH);
SPI.transfer(HighShiftMH);
SPI.transfer(HighShiftML);
SPI.transfer(HighShiftL);
digitalWrite(_NSS, HIGH);
delayMicroseconds(ToneDelayus);
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_SET_RFFREQUENCY);
SPI.transfer(LowShiftH);
SPI.transfer(LowShiftMH);
SPI.transfer(LowShiftML);
SPI.transfer(LowShiftL);
digitalWrite(_NSS, HIGH);
delayMicroseconds(ToneDelayus);
}
//now set the frequency registers back to centre
digitalWrite(_NSS, LOW); //set NSS low
SPI.transfer(0x86); //address for write to REG_FRMSB
SPI.transfer(freqregH);
SPI.transfer(freqregMH);
SPI.transfer(freqregML);
SPI.transfer(freqregL);
digitalWrite(_NSS, HIGH); //set NSS high
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
setMode(MODE_STDBY_RC); //turns off carrier
}
uint8_t SX126XLT::getByteSXBuffer(uint8_t addr)
{
#ifdef SX126XDEBUG1
Serial.println(F("getByteSXBuffer()"));
#endif
uint8_t regdata;
setMode(MODE_STDBY_RC); //this is needed to ensure we can read from buffer OK.
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW); //start the burst read
SPI.transfer(RADIO_READ_BUFFER);
SPI.transfer(addr);
SPI.transfer(0xFF);
regdata = SPI.transfer(0);
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
return regdata;
}
void SX126XLT::printSXBufferHEX(uint8_t start, uint8_t end)
{
#ifdef SX126XDEBUG
Serial.println(F("printSXBufferHEX()"));
#endif
uint8_t index, regdata;
setMode(MODE_STDBY_RC);
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW); //start the burst read
SPI.transfer(RADIO_READ_BUFFER);
SPI.transfer(start);
SPI.transfer(0xFF);
for (index = start; index <= end; index++)
{
regdata = SPI.transfer(0);
printHEXByte(regdata);
Serial.print(F(" "));
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
}
int32_t SX126XLT::getFrequencyErrorHz()
{
//Note: Semtech appear to have stated that the frequency error function that this code uses,
//is not supported for SX126X, for reasons that have not been given, so use at your own risk.
//The fuctions here are a replication of the routines for the very similar SX128X
#ifdef SX126XDEBUG
Serial.println(F("getFrequencyErrorHz()"));
#endif
int32_t error, regvalue;
uint32_t bandwidth;
float divider;
bandwidth = returnBandwidth(savedModParam2); //gets the last configured bandwidth in hz
divider = (float) 1625000 / bandwidth; //why the values from the SX1280 datasheet work I have no idea
regvalue = getFrequencyErrorRegValue();
error = (FREQ_ERROR_CORRECTION * regvalue) / divider;
return error;
}
int32_t SX126XLT::getFrequencyErrorRegValue()
{
#ifdef SX126XDEBUG
Serial.println(F("getFrequencyErrorRegValue()"));
#endif
int32_t FrequencyError;
uint32_t regmsb, regmid, reglsb, allreg;
setMode(MODE_STDBY_XOSC);
regmsb = readRegister( REG_FREQUENCY_ERRORBASEADDR );
regmsb = regmsb & 0x0F; //clear bit 20 which is always set
regmid = readRegister( REG_FREQUENCY_ERRORBASEADDR + 1 );
reglsb = readRegister( REG_FREQUENCY_ERRORBASEADDR + 2 );
setMode(MODE_STDBY_RC);
#ifdef SX126XDEBUG
Serial.println();
Serial.print(F("Registers "));
Serial.print(regmsb,HEX);
Serial.print(F(" "));
Serial.print(regmid,HEX);
Serial.print(F(" "));
Serial.println(reglsb,HEX);
#endif
allreg = (uint32_t) ( regmsb << 16 ) | ( regmid << 8 ) | reglsb;
if (allreg & 0x80000)
{
FrequencyError = (0xFFFFF - allreg) * -1;
}
else
{
FrequencyError = allreg;
}
return FrequencyError;
}
void SX126XLT::printHEXByte(uint8_t temp)
{
if (temp < 0x10)
{
Serial.print(F("0"));
}
Serial.print(temp, HEX);
}
uint8_t SX126XLT::transmitAddressed(uint8_t *txbuffer, uint8_t size, char txpackettype, char txdestination, char txsource, uint32_t txtimeout, int8_t txpower, uint8_t wait)
{
#ifdef SX126XDEBUG
Serial.println(F("transmitAddressed()"));
#endif
uint8_t index;
uint8_t bufferdata;
if (size == 0)
{
return false;
}
setMode(MODE_STDBY_RC);
checkBusy();
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_WRITE_BUFFER);
SPI.transfer(0);
SPI.transfer(txpackettype); //Write the packet type
SPI.transfer(txdestination); //Destination node
SPI.transfer(txsource); //Source node
_TXPacketL = 3 + size; //we have added 3 header bytes to size
for (index = 0; index < size; index++)
{
bufferdata = txbuffer[index];
SPI.transfer(bufferdata);
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
//checkBusy();
writeRegister(REG_LR_PAYLOADLENGTH, _TXPacketL);
setTxParams(txpower, RAMP_TIME);
setTx(txtimeout); //this starts the TX
if (!wait)
{
return _TXPacketL;
}
while (!digitalRead(_TXDonePin)); //Wait for DIO1 to go high
if (readIrqStatus() & IRQ_RX_TX_TIMEOUT ) //check for timeout
{
return 0;
}
else
{
return _TXPacketL;
}
}
uint8_t SX126XLT::readRXPacketType()
{
#ifdef SX126XDEBUG
Serial.println(F("readRXPacketType()"));
#endif
return _RXPacketType;
}
uint8_t SX126XLT::readRXDestination()
{
#ifdef SX126XDEBUG
Serial.println(F("readRXDestination()"));
#endif
return _RXDestination;
}
uint8_t SX126XLT::readRXSource()
{
#ifdef SX126XDEBUG
Serial.println(F("readRXSource()"));
#endif
return _RXSource;
}
uint8_t SX126XLT::receiveAddressed(uint8_t *rxbuffer, uint8_t size, uint32_t rxtimeout, uint8_t wait)
{
#ifdef SX126XDEBUG
Serial.println(F("receiveAddressed()"));
#endif
uint8_t index, RXstart, RXend;
uint16_t regdata;
uint8_t buffer[2];
setDioIrqParams(IRQ_RADIO_ALL, (IRQ_RX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); //set for IRQ on RX done or timeout
setRx(rxtimeout);
if (!wait)
{
return 0; //not wait requested so no packet length to pass
}
while (!digitalRead(_RXDonePin)); //Wait for DIO1 to go high
setMode(MODE_STDBY_RC); //ensure to stop further packet reception
regdata = readIrqStatus();
if ( (regdata & IRQ_HEADER_ERROR) | (regdata & IRQ_CRC_ERROR) | (regdata & IRQ_RX_TX_TIMEOUT ) ) //check if any of the preceding IRQs is set
{
//packet is errored somewhere so return 0
return 0;
}
readCommand(RADIO_GET_RXBUFFERSTATUS, buffer, 2);
_RXPacketL = buffer[0];
if (_RXPacketL > size) //check passed buffer is big enough for packet
{
_RXPacketL = size; //truncate packet if not enough space
}
RXstart = buffer[1];
RXend = RXstart + _RXPacketL;
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW); //start the burst read
SPI.transfer(RADIO_READ_BUFFER);
SPI.transfer(RXstart);
SPI.transfer(0xFF);
_RXPacketType = SPI.transfer(0);
_RXDestination = SPI.transfer(0);
_RXSource = SPI.transfer(0);
for (index = RXstart; index < RXend; index++)
{
regdata = SPI.transfer(0);
rxbuffer[index] = regdata;
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
return _RXPacketL; //so we can check for packet having enough buffer space
}
void SX126XLT::clearDeviceErrors()
{
#ifdef SX126XDEBUG
Serial.println(F("clearDeviceErrors()"));
#endif
uint8_t buffer[2];
buffer[0] = 0x00; //can only clear all errors
buffer[1] = 0x00;
writeCommand(RADIO_CLEAR_ERRORS, buffer, 2);
}
void SX126XLT::printDeviceErrors()
{
#ifdef SX126XDEBUG
Serial.println(F("printDeviceErrors()"));
#endif
uint16_t errors;
uint8_t buffer[2];
readCommand(RADIO_GET_ERROR, buffer, 2);
errors = (buffer[0] << 8) + buffer[1];
//0x0001
if (errors & RC64K_CALIB_ERR)
{
Serial.print(F(",RC64K_CALIB_ERR"));
}
//0x0002
if (errors & RC13M_CALIB_ERR)
{
Serial.print(F(",RC13M_CALIB_ERR"));
}
//0x0004
if (errors & PLL_CALIB_ERR)
{
Serial.print(F(",PLL_CALIB_ERR"));
}
//0x0008
if (errors & ADC_CALIB_ERR)
{
Serial.print(F(",ADC_CALIB_ERR"));
}
//0x0010
if (errors & IMG_CALIB_ERR)
{
Serial.print(F(",IMG_CALIB_ERR"));
}
//0x0020
if (errors & XOSC_START_ERR)
{
Serial.print(F(",XOSC_START_ERR"));
}
//0x0040
if (errors & PLL_LOCK_ERR)
{
Serial.print(F(",PLL_LOCK_ERR"));
}
//0x0080
if (errors & RFU)
{
Serial.print(F(",RFU"));
}
//0x0100
if (errors & PA_RAMP_ERR)
{
Serial.print(",PA_RAMP_ERR");
}
}
void SX126XLT::printHEXPacket(uint8_t *buffer, uint8_t size)
{
#ifdef SX126XDEBUG
Serial.println(F("printHEXPacket()"));
#endif
uint8_t index;
for (index = 0; index < size; index++)
{
//Serial.print(F("["));
//Serial.print(index);
//Serial.print(F("],"));
printHEXByte(buffer[index]);
Serial.print(F(" "));
}
}
void SX126XLT::printHEXByte0x(uint8_t temp)
{
//print a byte, adding 0x
Serial.print(F("0x"));
if (temp < 0x10)
{
Serial.print(F("0"));
}
Serial.print(temp, HEX);
}
uint8_t SX126XLT::readsavedModParam1()
{
//return previously set spreading factor
#ifdef SX126XDEBUG
Serial.println(F("readsavedModParam1()"));
#endif
return savedModParam1;
}
uint8_t SX126XLT::readsavedModParam2()
{
//return previously set bandwidth
#ifdef SX126XDEBUG
Serial.println(F("readsavedModParam2()"));
#endif
return savedModParam2;
}
uint8_t SX126XLT::readsavedModParam3()
{
//return previously set code rate
#ifdef SX126XDEBUG
Serial.println(F("readsavedModParam3()"));
#endif
return savedModParam3;
}
uint8_t SX126XLT::readsavedModParam4()
{
//return previously set optimisation
#ifdef SX126XDEBUG
Serial.println(F("readsavedModParam4()"));
#endif
return savedModParam4;
}
uint8_t SX126XLT::readsavedPower()
{
#ifdef SX126XDEBUG
Serial.println(F("readsavedPower()"));
#endif
return savedTXPower;
}
uint8_t SX126XLT::getPacketMode()
{
//its either LoRa or FSK
#ifdef SX126XDEBUG
Serial.println(F("getPacketMode()"));
#endif
return savedPacketType;
}
uint8_t SX126XLT::readsavedPacketParam1()
{
//return previously set preamble
#ifdef SX126XDEBUG
Serial.println(F("readsavedPacketParam1()"));
#endif
return savedPacketParam1;
}
uint8_t SX126XLT::readsavedPacketParam2()
{
//return previously set header type
#ifdef SX126XDEBUG
Serial.println(F("readsavedPacketParam2()"));
#endif
return savedPacketParam2;
}
uint8_t SX126XLT::readsavedPacketParam3()
{
//return previously set packet length
#ifdef SX126XDEBUG
Serial.println(F("readsavedPacketParam3()"));
#endif
return savedPacketParam3;
}
uint8_t SX126XLT::readsavedPacketParam4()
{
//return previously set CRC
#ifdef SX126XDEBUG
Serial.println(F("readsavedPacketParam4()"));
#endif
return savedPacketParam4;
}
uint8_t SX126XLT::readsavedPacketParam5()
{
//return previously set IQ
#ifdef SX126XDEBUG
Serial.println(F("readsavedPacketParam5()"));
#endif
return savedPacketParam5;
}
uint8_t SX126XLT::getOpmode()
{
//return last saved opmode
#ifdef SX126XDEBUG
Serial.println(F("getOpmode()"));
#endif
return _OperatingMode;
}
uint8_t SX126XLT::getCRCMode()
{
//return last saved opmode
#ifdef SX126XDEBUG
Serial.println(F("getCRCMode()"));
#endif
return savedPacketParam4;
}
void SX126XLT::fillSXBuffer(uint8_t startaddress, uint8_t size, uint8_t character)
{
#ifdef SX126XDEBUG1
Serial.println(F("fillSXBuffer()"));
#endif
uint8_t index;
setMode(MODE_STDBY_RC);
//writeRegister(REG_FIFOADDRPTR, startaddress); //and save in FIFO access ptr
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_WRITE_BUFFER);
SPI.transfer(startaddress);
//SPI interface ready for byte to write to buffer
for (index = 0; index < size; index++)
{
SPI.transfer(character);
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
}
uint8_t SX126XLT::readPacket(uint8_t *rxbuffer, uint8_t size)
{
#ifdef SX126XDEBUG
Serial.println(F("readPacket()"));
#endif
uint8_t index, regdata, RXstart, RXend;
uint8_t buffer[2];
readCommand(RADIO_GET_RXBUFFERSTATUS, buffer, 2);
_RXPacketL = buffer[0];
if (_RXPacketL > size) //check passed buffer is big enough for packet
{
_RXPacketL = size; //truncate packet if not enough space
}
RXstart = buffer[1];
RXend = RXstart + _RXPacketL;
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW); //start the burst read
SPI.transfer(RADIO_READ_BUFFER);
SPI.transfer(RXstart);
SPI.transfer(0xFF);
for (index = RXstart; index < RXend; index++)
{
regdata = SPI.transfer(0);
rxbuffer[index] = regdata;
}
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
return _RXPacketL; //so we can check for packet having enough buffer space
}
void SX126XLT::writeByteSXBuffer(uint8_t addr, uint8_t regdata)
{
#ifdef SX126XDEBUG1
Serial.println(F("writeByteSXBuffer"));
#endif
setMode(MODE_STDBY_RC); //this is needed to ensure we can write to buffer OK.
#ifdef USE_SPI_TRANSACTION //to use SPI_TRANSACTION enable define at beginning of CPP file
SPI.beginTransaction(SPISettings(LTspeedMaximum, LTdataOrder, LTdataMode));
#endif
digitalWrite(_NSS, LOW);
SPI.transfer(RADIO_WRITE_BUFFER);
SPI.transfer(addr);
SPI.transfer(regdata);
digitalWrite(_NSS, HIGH);
#ifdef USE_SPI_TRANSACTION
SPI.endTransaction();
#endif
}
void SX126XLT::printSXBufferASCII(uint8_t start, uint8_t end)
{
#ifdef SX126XDEBUG1
Serial.println(F("printSXBufferASCII)"));
#endif
uint8_t index, regdata;
setMode(MODE_STDBY_RC);
for (index = start; index <= end; index++)
{
regdata = getByteSXBuffer(index);
Serial.write(regdata);
}
}
void SX126XLT::startFSKRTTY(uint32_t freqshift, uint8_t pips, uint16_t pipPeriodmS, uint16_t pipDelaymS, uint16_t leadinmS)
{
#ifdef SX126XDEBUG1
Serial.print(F("startFSKRTTY()"));
#endif
uint32_t shiftedFrequencyRegisters;
uint8_t index;
uint32_t endmS;
uint32_t calculatedRegShift;
calculatedRegShift = (uint32_t) (freqshift/FREQ_STEP);
shiftedFrequencyRegisters = savedFrequencyReg + calculatedRegShift;
_ShiftfreqregH = (shiftedFrequencyRegisters >> 24) & 0xFF; //MSB
_ShiftfreqregMH = (shiftedFrequencyRegisters >> 16) & 0xFF;
_ShiftfreqregML = (shiftedFrequencyRegisters >> 8) & 0xFF;
_ShiftfreqregL = shiftedFrequencyRegisters & 0xFF; //LSB
#ifdef DEBUGFSKRTTY
Serial.print(F("NotShiftedFrequencyRegisters "));
Serial.println(savedFrequencyReg, HEX);
Serial.print(F("calculatedRegShift "));
Serial.println(calculatedRegShift, HEX);
Serial.print(F("ShiftedFrequencyRegisters "));
Serial.print((uint32_t) shiftedFrequencyRegisters, HEX);
Serial.print(F(" ("));
Serial.print(_ShiftfreqregH,HEX);
Serial.print(F(" "));
Serial.print(_ShiftfreqregMH,HEX);
Serial.print(F(" "));
Serial.print(_ShiftfreqregML,HEX);
Serial.print(F(" "));
Serial.print(_ShiftfreqregL,HEX);
Serial.print(F(" )"));
Serial.println();
#endif
setTxParams(10, RADIO_RAMP_200_US);
for (index = 1; index <= pips; index++)
{
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML, _ShiftfreqregL); //set carrier frequency
setTXDirect(); //turn on carrier
delay(pipPeriodmS);
setMode(MODE_STDBY_RC); //turns off carrier
delay(pipDelaymS);
}
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML,_ShiftfreqregL); //set carrier frequency
endmS = millis() + leadinmS;
setTXDirect(); //turn on carrier
while (millis() < endmS); //leave leadin on
}
void SX126XLT::transmitFSKRTTY(uint8_t chartosend, uint8_t databits, uint8_t stopbits, uint8_t parity, uint16_t baudPerioduS, int8_t pin)
{
//micros() will rollover at 4294967295 or 71mins 35secs
//assume slowest baud rate is 45 (baud period of 22222us) then with 11 bits max to send if routine starts
//when micros() > (4294967295 - (22222 * 11) = 4294722855 = 0xFFFC4525 then it could overflow during send
//Rather than deal with rolloever in the middle of a character lets wait till it overflows and then
//start the character
#ifdef SX126XDEBUG1
Serial.print(F("transmitFSKRTTY()"));
#endif
uint8_t numbits;
uint32_t enduS;
uint8_t bitcount = 0; //set when a bit is 1
if (micros() > 0xFFFB6000) //check if micros would overflow within circa 300mS, approx 1 char at 45baud
{
#ifdef DEBUGFSKRTTY
Serial.print(F("Overflow pending - micros() = "));
Serial.println(micros(),HEX);
#endif
while (micros() > 0xFFFB6000); //wait a short while until micros overflows to 0
#ifdef DEBUGFSKRTTY
Serial.print(F("Paused - micros() = "));
Serial.println(micros(),HEX);
#endif
}
enduS = micros() + baudPerioduS;
setRfFrequencyDirect(_freqregH, _freqregMH, _freqregML, _freqregL); //set carrier frequency (low)
if (pin >= 0)
{
digitalWrite(pin, LOW);
}
while (micros() < enduS); //start bit
for (numbits = 1; numbits <= databits; numbits++) //send bits, LSB first
{
enduS = micros() + baudPerioduS; //start the timer
if ((chartosend & 0x01) != 0) //test for bit set, a 1
{
bitcount++;
if (pin >= 0)
{
digitalWrite(pin, HIGH);
}
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML, _ShiftfreqregL); //set carrier frequency for a 1
}
else
{
if (pin >= 0)
{
digitalWrite(pin, LOW);
}
setRfFrequencyDirect(_freqregH, _freqregMH, _freqregML, _freqregL); //set carrier frequency for a 0
}
chartosend = (chartosend >> 1); //get the next bit
while (micros() < enduS);
}
enduS = micros() + baudPerioduS; //start the timer for possible parity bit
switch (parity)
{
case ParityNone:
break;
case ParityZero:
setRfFrequencyDirect(_freqregH, _freqregMH, _freqregML, _freqregL); //set carrier frequency for a 0
while (micros() < enduS);
break;
case ParityOne:
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML, _ShiftfreqregL); //set carrier frequency for a 1
while (micros() < enduS);
break;
case ParityOdd:
if (bitRead(bitcount, 0))
{
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML, _ShiftfreqregL); //set carrier frequency for a 1
}
else
{
setRfFrequencyDirect(_freqregH, _freqregMH, _freqregML, _freqregL); //set carrier frequency for a 0
}
while (micros() < enduS);
break;
case ParityEven:
if (bitRead(bitcount, 0))
{
setRfFrequencyDirect(_freqregH, _freqregMH, _freqregML, _freqregL); //set carrier frequency for a 0
}
else
{
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML, _ShiftfreqregL); //set carrier frequency for a 1
}
while (micros() < enduS);
break;
default:
break;
}
//stop bits, normally 1 or 2
enduS = micros() + (baudPerioduS * stopbits);
if (pin >= 0)
{
digitalWrite(pin, HIGH);
}
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML, _ShiftfreqregL); //set carrier frequency for a 1
while (micros() < enduS);
}
void SX126XLT::transmitFSKRTTY(uint8_t chartosend, uint16_t baudPerioduS, int8_t pin)
{
//micros() will rollover at 4294967295 or 71mins 35secs
//assume slowest baud rate is 45 (baud period of 22222us) then with 11 bits max to send if routine starts
//when micros() > (4294967295 - (22222 * 11) = 4294722855 = 0xFFFC4525 then it could overflow during send
//Rather than deal with rolloever in the middle of a character lets wait till it overflows and then
//start the character
//This overloaded version of transmitFSKRTTY() uses 1 start bit, 7 data bits, no parity and 2 stop bits.
#ifdef SX126XDEBUG1
Serial.print(F("transmitFSKRTTY()"));
#endif
uint8_t numbits;
uint32_t enduS;
if (micros() > 0xFFFB6000) //check if micros would overflow within circa 300mS, approx 1 char at 45baud
{
#ifdef DEBUGFSKRTTY
Serial.print(F("Overflow pending - micros() = "));
Serial.println(micros(),HEX);
#endif
while (micros() > 0xFFFB6000); //wait a short while until micros overflows to 0
#ifdef DEBUGFSKRTTY
Serial.print(F("Paused - micros() = "));
Serial.println(micros(),HEX);
#endif
}
enduS = micros() + baudPerioduS;
setRfFrequencyDirect(_freqregH, _freqregMH, _freqregML, _freqregL); //set carrier frequency (low)
if (pin >= 0)
{
digitalWrite(pin, LOW);
}
while (micros() < enduS); //start bit
for (numbits = 1; numbits <= 7; numbits++) //send bits, LSB first
{
enduS = micros() + baudPerioduS; //start the timer
if ((chartosend & 0x01) != 0) //test for bit set, a 1
{
if (pin >= 0)
{
digitalWrite(pin, HIGH);
}
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML, _ShiftfreqregL); //set carrier frequency for a 1
}
else
{
if (pin >= 0)
{
digitalWrite(pin, LOW);
}
setRfFrequencyDirect(_freqregH, _freqregMH, _freqregML, _freqregL); //set carrier frequency for a 0
}
chartosend = (chartosend >> 1); //get the next bit
while (micros() < enduS);
}
//stop bits, normally 1 or 2
enduS = micros() + (baudPerioduS * 2);
if (pin >= 0)
{
digitalWrite(pin, HIGH);
}
setRfFrequencyDirect(_ShiftfreqregH, _ShiftfreqregMH, _ShiftfreqregML, _ShiftfreqregL); //set carrier frequency
while (micros() < enduS);
}
void SX126XLT::printRTTYregisters()
{
#ifdef SX126XDEBUG1
Serial.print(F("printRTTYregisters()"));
#endif
Serial.print(F("NoShift Registers "));
Serial.print(_freqregH, HEX);
Serial.print(F(" "));
Serial.print(_freqregMH, HEX);
Serial.print(F(" "));
Serial.print(_freqregML, HEX);
Serial.print(F(" "));
Serial.println(_freqregL, HEX);
Serial.print(F("Shifted Registers "));
Serial.print(_ShiftfreqregH, HEX);
Serial.print(F(" "));
Serial.print(_ShiftfreqregMH, HEX);
Serial.print(F(" "));
Serial.print(_ShiftfreqregML, HEX);
Serial.print(F(" "));
Serial.println(_ShiftfreqregL, HEX);
}
void SX126XLT::endFSKRTTY()
{
#ifdef SX126XDEBUG1
Serial.print(F("endFSKRTTY()"));
#endif
setMode(MODE_STDBY_RC);
}
void SX126XLT::getRfFrequencyRegisters(uint8_t *buff)
{
//returns the register values for the current set frequency
#ifdef SX126XDEBUG1
Serial.print(F("getRfFrequencyRegisters()"));
#endif
buff[0] = _freqregH;
buff[1] = _freqregMH;
buff[2] = _freqregML;
buff[3] = _freqregL;
}
void SX126XLT::setRfFrequencyDirect(uint8_t high, uint8_t midhigh, uint8_t midlow, uint8_t low)
{
#ifdef SX126XDEBUG1
Serial.print(F("setRfFrequencyDirect()"));
#endif
uint8_t buffer[4];
buffer[0] = high; //MSB
buffer[1] = midhigh;
buffer[2] = midlow;
buffer[3] = low;//LSB
writeCommand(RADIO_SET_RFFREQUENCY, buffer, 4);
}
/*
MIT license
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/