/* Copyright 2019 - Stuart Robinson Licensed under a MIT license displayed at the bottom of this document. 06/02/20 */ /* Parts of code Copyright (c) 2013, SEMTECH S.A. See LICENSE.TXT file included in the library */ #include #include #define LTUNUSED(v) (void) (v) //add LTUNUSED(variable); to avoid compiler warnings #define USE_SPI_TRANSACTION //#define SX128XDEBUG //enable debug messages //#define RANGINGDEBUG //enable debug messages for ranging //#define SX128XDEBUGRXTX //enable debug messages for RX TX switching //#define SX128XDEBUGPINS //enable pin allocation debug messages SX128XLT::SX128XLT() { } /* Formats for :begin 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, uint8_t device) 2 NiceRF > begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, uint8_t device) 3 Ebyte > begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinRXEN, int8_t pinTXEN, uint8_t device); */ bool SX128XLT::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, 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; _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 SX128XDEBUGPINS Serial.println(F("begin()")); Serial.println(F("SX128XLT 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); #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 SX128XDEBUGPINS Serial.println(F("RX_EN & TX_EN switching enabled")); #endif pinMode(_RXEN, OUTPUT); pinMode(_TXEN, OUTPUT); _rxtxpinmode = true; } else { #ifdef SX128XDEBUGPINS Serial.println(F("RX_EN & TX_EN switching disabled")); #endif _rxtxpinmode = false; } resetDevice(); if (checkDevice()) { return true; } return false; } bool SX128XLT::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; //not defined, so mark as unused _TXEN = -1; //not defined, so mark as unused _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 SX128XDEBUGPINS Serial.println(F("format 2 NiceRF begin()")); Serial.println(F("SX128XLT 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); #endif if (_DIO1 >= 0) { pinMode( _DIO1, INPUT); } #ifdef SX128XDEBUGPINS Serial.println(F("RX_EN & TX_EN switching disabled")); #endif _rxtxpinmode = false; resetDevice(); if (checkDevice()) { return true; } return false; } bool SX128XLT::begin(int8_t pinNSS, int8_t pinNRESET, int8_t pinRFBUSY, int8_t pinDIO1, int8_t pinRXEN, int8_t pinTXEN, uint8_t device) { //format 3 pins for Ebyte, NSS, NRESET, RFBUSY, DIO1, RX_EN, TX_EN _NSS = pinNSS; _NRESET = pinNRESET; _RFBUSY = pinRFBUSY; _DIO1 = pinDIO1; _DIO2 = -1; _DIO3 = -1; _RXEN = pinRXEN; _TXEN = pinTXEN; _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 SX128XDEBUGPINS Serial.println(F("format 3 Ebyte begin()")); Serial.println(F("SX128XLT 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); #endif if (_DIO1 >= 0) { pinMode( _DIO1, INPUT); } if ((_RXEN >= 0) && (_TXEN >= 0)) { #ifdef SX128XDEBUGPINS Serial.println(F("RX_EN & TX_EN switching enabled")); #endif pinMode(_RXEN, OUTPUT); pinMode(_TXEN, OUTPUT); _rxtxpinmode = true; } else { #ifdef SX128XDEBUGPINS Serial.println(F("RX_EN & TX_EN switching disabled")); #endif _rxtxpinmode = false; } resetDevice(); if (checkDevice()) { return true; } return false; } void SX128XLT::rxEnable() { //Enable RX mode on device such as Ebyte E28-2G4M20S which have RX and TX enable pins #ifdef SX128XDEBUGRXTX Serial.println(F("rxEnable()")); #endif digitalWrite(_RXEN, HIGH); digitalWrite(_TXEN, LOW); } void SX128XLT::txEnable() { //Enable RX mode on device such as Ebyte E28-2G4M20S which have RX and TX enable pins #ifdef SX128XDEBUGRXTX Serial.println(F("txEnable()")); #endif digitalWrite(_RXEN, LOW); digitalWrite(_TXEN, HIGH); } void SX128XLT::checkBusy() { #ifdef SX128XDEBUG //Serial.println(F("checkBusy()")); #endif uint8_t busy_timeout_cnt; busy_timeout_cnt = 0; while (digitalRead(_RFBUSY)) { delay(1); busy_timeout_cnt++; if (busy_timeout_cnt > 10) //wait 5mS for busy to complete { Serial.println(F("ERROR - Busy Timeout!")); resetDevice(); setMode(MODE_STDBY_RC); config(); //re-run saved config break; } } } bool SX128XLT::config() { #ifdef SX128XDEBUG Serial.println(F("config()")); #endif resetDevice(); setMode(MODE_STDBY_RC); setRegulatorMode(savedRegulatorMode); setPacketType(savedPacketType); setRfFrequency(savedFrequency, savedOffset); setModulationParams(savedModParam1, savedModParam2, savedModParam3); setPacketParams(savedPacketParam1, savedPacketParam2, savedPacketParam3, savedPacketParam4, savedPacketParam5, savedPacketParam6, savedPacketParam7); setDioIrqParams(savedIrqMask, savedDio1Mask, savedDio2Mask, savedDio3Mask); //set for IRQ on RX done on DIO1 return true; } void SX128XLT::readRegisters(uint16_t address, uint8_t *buffer, uint16_t size) { #ifdef SX128XDEBUG //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 SX128XLT::readRegister(uint16_t address) { #ifdef SX128XDEBUG //Serial.println(F("readRegister()")); #endif uint8_t data; readRegisters(address, &data, 1); return data; } void SX128XLT::writeRegisters(uint16_t address, uint8_t *buffer, uint16_t size) { #ifdef SX128XDEBUG //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 //checkBusy(); } void SX128XLT::writeRegister(uint16_t address, uint8_t value) { #ifdef SX128XDEBUG //Serial.println(F("writeRegister()")); #endif writeRegisters( address, &value, 1 ); } void SX128XLT::writeCommand(uint8_t Opcode, uint8_t *buffer, uint16_t size) { #ifdef SX128XDEBUG //Serial.print(F("writeCommand() ")); //Serial.println(Opcode, HEX); #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 SX128XLT::readCommand(uint8_t Opcode, uint8_t *buffer, uint16_t size) { #ifdef SX128XDEBUG //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 //checkBusy(); } void SX128XLT::resetDevice() { #ifdef SX128XDEBUG Serial.println(F("resetDevice()")); #endif //timings taken from Semtech library delay(20); digitalWrite(_NRESET, LOW); delay(50); digitalWrite(_NRESET, HIGH); delay(20); } bool SX128XLT::checkDevice() { //check there is a device out there, writes a register and reads back #ifdef SX128XDEBUG Serial.println(F("checkDevice()")); #endif uint8_t Regdata1, Regdata2; Regdata1 = readRegister(0x0908); //low byte of frequency setting writeRegister(0x0908, (Regdata1 + 1)); Regdata2 = readRegister(0x0908); //read changed value back writeRegister(0x0908, Regdata1); //restore register to original value if (Regdata2 == (Regdata1 + 1)) { return true; } else { return false; } } void SX128XLT::setupLoRa(uint32_t frequency, int32_t offset, uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) { #ifdef SX128XDEBUG Serial.println(F("setupLoRa()")); #endif setMode(MODE_STDBY_RC); setRegulatorMode(USE_LDO); setPacketType(PACKET_TYPE_LORA); setRfFrequency(frequency, offset); setBufferBaseAddress(0, 0); setModulationParams(modParam1, modParam2, modParam3); setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 255, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0); setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RX_TX_TIMEOUT), 0, 0); } void SX128XLT::setMode(uint8_t modeconfig) { #ifdef SX128XDEBUG Serial.println(F("setMode()")); #endif uint8_t Opcode = 0x80; 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(modeconfig); digitalWrite(_NSS, HIGH); #ifdef USE_SPI_TRANSACTION SPI.endTransaction(); #endif _OperatingMode = modeconfig; } void SX128XLT::setRegulatorMode(uint8_t mode) { #ifdef SX128XDEBUG Serial.println(F("setRegulatorMode()")); #endif savedRegulatorMode = mode; writeCommand(RADIO_SET_REGULATORMODE, &mode, 1); } void SX128XLT::setPacketType(uint8_t packettype ) { #ifdef SX128XDEBUG Serial.println(F("setPacketType()")); #endif savedPacketType = packettype; writeCommand(RADIO_SET_PACKETTYPE, &packettype, 1); } void SX128XLT::setRfFrequency(uint32_t frequency, int32_t offset) { #ifdef SX128XDEBUG Serial.println(F("setRfFrequency()")); #endif savedFrequency = frequency; savedOffset = offset; frequency = frequency + offset; uint8_t buffer[3]; uint32_t freqtemp = 0; freqtemp = ( uint32_t )( (double) frequency / (double)FREQ_STEP); buffer[0] = ( uint8_t )( ( freqtemp >> 16 ) & 0xFF ); buffer[1] = ( uint8_t )( ( freqtemp >> 8 ) & 0xFF ); buffer[2] = ( uint8_t )( freqtemp & 0xFF ); writeCommand(RADIO_SET_RFFREQUENCY, buffer, 3); } void SX128XLT::setBufferBaseAddress(uint8_t txBaseAddress, uint8_t rxBaseAddress) { #ifdef SX128XDEBUG Serial.println(F("setBufferBaseAddress()")); #endif uint8_t buffer[2]; buffer[0] = txBaseAddress; buffer[1] = rxBaseAddress; writeCommand(RADIO_SET_BUFFERBASEADDRESS, buffer, 2); } void SX128XLT::setModulationParams(uint8_t modParam1, uint8_t modParam2, uint8_t modParam3) { //sequence is spreading factor, bandwidth, coding rate. #ifdef SX128XDEBUG Serial.println(F("setModulationParams()")); #endif uint8_t buffer[3]; savedModParam1 = modParam1; savedModParam2 = modParam2; savedModParam3 = modParam3; buffer[0] = modParam1; buffer[1] = modParam2; buffer[2] = modParam3; writeCommand(RADIO_SET_MODULATIONPARAMS, buffer, 3); } void SX128XLT::setPacketParams(uint8_t packetParam1, uint8_t packetParam2, uint8_t packetParam3, uint8_t packetParam4, uint8_t packetParam5, uint8_t packetParam6, uint8_t packetParam7) { //for LoRa order is PreambleLength, HeaderType, PayloadLength, CRC, InvertIQ/chirp invert, not used, not used //for FLRC order is PreambleLength, SyncWordLength, SyncWordMatch, HeaderType, PayloadLength, CrcLength, Whitening #ifdef SX128XDEBUG Serial.println(F("SetPacketParams()")); #endif savedPacketParam1 = packetParam1; savedPacketParam2 = packetParam2; savedPacketParam3 = packetParam3; savedPacketParam4 = packetParam4; savedPacketParam5 = packetParam5; savedPacketParam6 = packetParam6; savedPacketParam7 = packetParam7; uint8_t buffer[7]; buffer[0] = packetParam1; buffer[1] = packetParam2; buffer[2] = packetParam3; buffer[3] = packetParam4; buffer[4] = packetParam5; buffer[5] = packetParam6; buffer[6] = packetParam7; writeCommand(RADIO_SET_PACKETPARAMS, buffer, 7); } void SX128XLT::setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask, uint16_t dio3Mask ) { #ifdef SX128XDEBUG 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_SET_DIOIRQPARAMS, buffer, 8); } void SX128XLT::setHighSensitivity() { //set bits 7,6 of REG_LNA_REGIME #ifdef SX128XDEBUG Serial.println(F("setHighSensitivity()")); #endif writeRegister(REG_LNA_REGIME, (readRegister(REG_LNA_REGIME) | 0xC0)); } void SX128XLT::setLowPowerRX() { //clear bits 7,6 of REG_LNA_REGIME #ifdef SX128XDEBUG Serial.println(F("setLowPowerRX()")); #endif writeRegister(REG_LNA_REGIME, (readRegister(REG_LNA_REGIME) & 0x3F)); } void SX128XLT::printModemSettings() { #ifdef SX128XDEBUG Serial.println(F("printModemSettings()")); #endif printDevice(); Serial.print(F(",")); Serial.print(getFreqInt()); Serial.print(F("hz")); if (savedPacketType == PACKET_TYPE_LORA) { Serial.print(F(",SF")); Serial.print(getLoRaSF()); Serial.print(F(",BW")); Serial.print(returnBandwidth(savedModParam2)); Serial.print(F(",CR4:")); Serial.print((getLoRaCodingRate() + 4)); if (getInvertIQ() == LORA_IQ_INVERTED) { Serial.print(F(",IQInverted")); } else { Serial.print(F(",IQNormal")); } Serial.print(F(",Preamble_")); Serial.print(getPreamble()); } if (savedPacketType == PACKET_TYPE_FLRC) { if (savedPacketParam1 == 0) { Serial.print(F(",No_Syncword")); } if (savedPacketParam1 == 4) { Serial.print(F(",32bit_Syncword")); } switch (savedPacketParam3) { case RADIO_RX_MATCH_SYNCWORD_OFF: Serial.print(F(",SYNCWORD_OFF")); break; case RADIO_RX_MATCH_SYNCWORD_1: Serial.print(F(",SYNCWORD_1")); break; case RADIO_RX_MATCH_SYNCWORD_2: Serial.print(F(",SYNCWORD_2")); break; case RADIO_RX_MATCH_SYNCWORD_1_2: Serial.print(F(",SYNCWORD_1_2")); break; case RADIO_RX_MATCH_SYNCWORD_3: Serial.print(F(",SYNCWORD_3")); break; case RADIO_RX_MATCH_SYNCWORD_1_3: Serial.print(F(",SYNCWORD_1_3")); break; case RADIO_RX_MATCH_SYNCWORD_2_3: Serial.print(F(",SYNCWORD_2_3")); break; case RADIO_RX_MATCH_SYNCWORD_1_2_3: Serial.print(F(",SYNCWORD_1_2_3")); break; default: Serial.print(F("Unknown_SYNCWORD")); } if (savedPacketParam4 == RADIO_PACKET_FIXED_LENGTH) { Serial.print(F(",PACKET_FIXED_LENGTH")); } if (savedPacketParam4 == RADIO_PACKET_VARIABLE_LENGTH) { Serial.print(F(",PACKET_VARIABLE_LENGTH")); } switch (savedPacketParam6) { case RADIO_CRC_OFF: Serial.print(F(",CRC_OFF")); break; case RADIO_CRC_1_BYTES: Serial.print(F(",CRC_1_BYTES")); break; case RADIO_CRC_2_BYTES: Serial.print(F(",CRC_2_BYTES")); break; case RADIO_CRC_3_BYTES: Serial.print(F(",CRC_3_BYTES")); break; default: Serial.print(F(",Unknown_CRC")); } if (savedPacketParam7 == RADIO_WHITENING_ON) { Serial.print(F(",WHITENING_ON")); } if (savedPacketParam7 == RADIO_WHITENING_OFF) { Serial.print(F(",WHITENING_OFF")); } } } void SX128XLT::printDevice() { #ifdef SX128XDEBUG Serial.println(F("printDevice()")); #endif switch (_Device) { case DEVICE_SX1280: Serial.print(F("SX1280")); break; case DEVICE_SX1281: Serial.print(F("SX1281")); break; default: Serial.print(F("Unknown Device")); } } uint32_t SX128XLT::getFreqInt() { #ifdef SX128XDEBUG Serial.println(F("getFreqInt")); #endif //get the current set device frequency, return as long integer uint8_t Msb = 0; uint8_t Mid = 0; uint8_t Lsb = 0; uint32_t uinttemp; float floattemp; LTUNUSED(Msb); //to prevent a compiler warning LTUNUSED(Mid); //to prevent a compiler warning LTUNUSED(Lsb); //to prevent a compiler warning if (savedPacketType == PACKET_TYPE_LORA) { Msb = readRegister(REG_RFFrequency23_16); Mid = readRegister(REG_RFFrequency15_8); Lsb = readRegister(REG_RFFrequency7_0); } if (savedPacketType == PACKET_TYPE_FLRC) { Msb = readRegister(REG_FLRC_RFFrequency23_16); Mid = readRegister(REG_FLRC_RFFrequency15_8); Lsb = readRegister(REG_FLRC_RFFrequency7_0); } floattemp = ((Msb * 0x10000ul) + (Mid * 0x100ul) + Lsb); floattemp = ((floattemp * FREQ_STEP) / 1000000ul); uinttemp = (uint32_t)(floattemp * 1000000); return uinttemp; } uint8_t SX128XLT::getLoRaSF() { #ifdef SX128XDEBUG Serial.println(F("getLoRaSF()")); #endif return (savedModParam1 >> 4); } uint32_t SX128XLT::returnBandwidth(uint8_t data) { #ifdef SX128XDEBUG Serial.println(F("returnBandwidth()")); #endif switch (data) { case LORA_BW_0200: return 203125; case LORA_BW_0400: return 406250; case LORA_BW_0800: return 812500; case LORA_BW_1600: return 1625000; default: break; } return 0x0; //so that a bandwidth not set can be identified } uint8_t SX128XLT::getLoRaCodingRate() { #ifdef SX128XDEBUG Serial.println(F("getLoRaCodingRate")); #endif return savedModParam3; } uint8_t SX128XLT::getInvertIQ() { //IQ mode reg 0x33 #ifdef SX128XDEBUG Serial.println(F("getInvertIQ")); #endif return savedPacketParam5; } uint16_t SX128XLT::getPreamble() { #ifdef SX128XDEBUG Serial.println(F("getPreamble")); #endif return savedPacketParam1; } void SX128XLT::printOperatingSettings() { #ifdef SX128XDEBUG Serial.println(F("printOperatingSettings()")); #endif printDevice(); Serial.print(F(",PacketMode_")); switch (savedPacketType) { case PACKET_TYPE_GFSK: Serial.print(F("GFSK")); break; case PACKET_TYPE_LORA: Serial.print(F("LORA")); break; case PACKET_TYPE_RANGING: Serial.print(F("RANGING")); break; case PACKET_TYPE_FLRC: Serial.print(F("FLRC")); break; case PACKET_TYPE_BLE: Serial.print(F("BLE")); break; default: Serial.print(F("Unknown")); } switch (savedPacketParam2) { case LORA_PACKET_VARIABLE_LENGTH: Serial.print(F(",Explicit")); break; case LORA_PACKET_FIXED_LENGTH: Serial.print(F(",Implicit")); break; default: Serial.print(F(",Unknown")); } Serial.print(F(",LNAgain_")); if (getLNAgain() == 0xC0) { Serial.print(F("HighSensitivity")); } else { Serial.print(F("LowPowerRX")); } } uint8_t SX128XLT::getLNAgain() { #ifdef SX128XDEBUG Serial.println(F("getLNAgain")); #endif return (readRegister(REG_LNA_REGIME) & 0xC0); } void SX128XLT::printRegisters(uint16_t Start, uint16_t End) { //prints the contents of SX1280 registers to serial monitor #ifdef SX128XDEBUG 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 SX128XLT::printASCIIPacket(uint8_t *buffer, uint8_t size) { #ifdef SX128XDEBUG Serial.println(F("printASCIIPacket()")); #endif uint8_t index; for (index = 0; index < size; index++) { Serial.write(buffer[index]); } } uint8_t SX128XLT::transmit(uint8_t *txbuffer, uint8_t size, uint16_t timeout, int8_t txpower, uint8_t wait) { #ifdef SX128XDEBUG 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; if (savedPacketType == PACKET_TYPE_LORA) { writeRegister(REG_LR_PAYLOADLENGTH, _TXPacketL); //only seems to work for lora } else if (savedPacketType == PACKET_TYPE_FLRC) { setPacketParams(savedPacketParam1, savedPacketParam2, savedPacketParam3, savedPacketParam4, _TXPacketL, savedPacketParam6, savedPacketParam7); } 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(timeout); //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 SX128XLT::setTxParams(int8_t TXpower, uint8_t RampTime) { #ifdef SX128XDEBUG Serial.println(F("setTxParams()")); #endif uint8_t buffer[2]; savedTXPower = TXpower; //power register is set to 0 to 31 which is -18dBm to +12dBm buffer[0] = (TXpower + 18); buffer[1] = (uint8_t)RampTime; writeCommand(RADIO_SET_TXPARAMS, buffer, 2); } void SX128XLT::setTx(uint16_t timeout) { #ifdef SX128XDEBUG Serial.println(F("setTx()")); #endif if (_rxtxpinmode) { txEnable(); } //Serial.print(F("timeout ")); //Serial.println(timeout); //Serial.print(F("_PERIODBASE ")); //Serial.println(_PERIODBASE); uint8_t buffer[3]; clearIrqStatus(IRQ_RADIO_ALL); //clear all interrupt flags buffer[0] = _PERIODBASE; buffer[1] = ( uint8_t )( ( timeout >> 8 ) & 0x00FF ); buffer[2] = ( uint8_t )( timeout & 0x00FF ); writeCommand(RADIO_SET_TX, buffer, 3 ); } void SX128XLT::clearIrqStatus(uint16_t irqMask) { #ifdef SX128XDEBUG 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 SX128XLT::readIrqStatus() { #ifdef SX128XDEBUG 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; } void SX128XLT::printIrqStatus() { #ifdef SX128XDEBUG 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_SYNCWORD_VALID) { Serial.print(F(",IRQ_SYNCWORD_VALID")); } //0x0008 if (_IrqStatus & IRQ_SYNCWORD_ERROR) { Serial.print(F(",IRQ_SYNCWORD_ERROR")); } //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_RANGING_SLAVE_RESPONSE_DONE) { Serial.print(F(",IRQ_RANGING_SLAVE_RESPONSE_DONE")); } //0x0100 if (_IrqStatus & IRQ_RANGING_SLAVE_REQUEST_DISCARDED) { Serial.print(",IRQ_RANGING_SLAVE_REQUEST_DISCARDED"); } //0x0200 if (_IrqStatus & IRQ_RANGING_MASTER_RESULT_VALID) { Serial.print(F(",IRQ_RANGING_MASTER_RESULT_VALID")); } //0x0400 if (_IrqStatus & IRQ_RANGING_MASTER_RESULT_TIMEOUT) { Serial.print(F(",IRQ_RANGING_MASTER_RESULT_TIMEOUT")); } //0x0800 if (_IrqStatus & IRQ_RANGING_SLAVE_REQUEST_VALID) { Serial.print(F(",IRQ_RANGING_SLAVE_REQUEST_VALID")); } //0x1000 if (_IrqStatus & IRQ_CAD_DONE) { Serial.print(F(",IRQ_CAD_DONE")); } //0x2000 if (_IrqStatus & IRQ_CAD_ACTIVITY_DETECTED) { Serial.print(F(",IRQ_CAD_ACTIVITY_DETECTED")); } //0x4000 if (_IrqStatus & IRQ_RX_TX_TIMEOUT) { Serial.print(F(",IRQ_RX_TX_TIMEOUT")); } //0x8000 if (_IrqStatus & IRQ_PREAMBLE_DETECTED) { Serial.print(F(",IRQ_PREAMBLE_DETECTED")); } } uint16_t SX128XLT::CRCCCITT(uint8_t *buffer, uint8_t size, uint16_t start) { #ifdef SX128XDEBUG 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 SX128XLT::receive(uint8_t *rxbuffer, uint8_t size, uint16_t timeout, uint8_t wait) { #ifdef SX128XDEBUG 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(timeout); 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 { return 0; //packet is errored somewhere so 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 SX128XLT::readPacketRSSI() { #ifdef SX128XDEBUG Serial.println(F("readPacketRSSI()")); #endif uint8_t status[5]; readCommand(RADIO_GET_PACKETSTATUS, status, 5) ; _PacketRSSI = -status[0] / 2; return _PacketRSSI; } uint8_t SX128XLT::readPacketSNR() { #ifdef SX128XDEBUG 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 SX128XLT::readRXPacketL() { #ifdef SX128XDEBUG Serial.println(F("readRXPacketL()")); #endif uint8_t buffer[2]; readCommand(RADIO_GET_RXBUFFERSTATUS, buffer, 2); _RXPacketL = buffer[0]; return _RXPacketL; } void SX128XLT::setRx(uint16_t timeout) { #ifdef SX128XDEBUG Serial.println(F("setRx()")); #endif if (_rxtxpinmode) { rxEnable(); } uint8_t buffer[3]; clearIrqStatus(IRQ_RADIO_ALL); //clear all interrupt flags buffer[0] = _PERIODBASE; //use pre determined period base setting buffer[1] = ( uint8_t ) ((timeout >> 8 ) & 0x00FF); buffer[2] = ( uint8_t ) (timeout & 0x00FF); writeCommand(RADIO_SET_RX, buffer, 3); } /*************************************************************************** //Start direct access SX buffer routines ***************************************************************************/ void SX128XLT::startWriteSXBuffer(uint8_t ptr) { #ifdef SX128XDEBUG 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); //address in SX buffer to write to //SPI interface ready for byte to write to buffer } uint8_t SX128XLT::endWriteSXBuffer() { #ifdef SX128XDEBUG Serial.println(F("endWriteSXBuffer()")); #endif digitalWrite(_NSS, HIGH); #ifdef USE_SPI_TRANSACTION SPI.endTransaction(); #endif return _TXPacketL; } void SX128XLT::startReadSXBuffer(uint8_t ptr) { #ifdef SX128XDEBUG 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 SX128XLT::endReadSXBuffer() { #ifdef SX128XDEBUG Serial.println(F("endReadSXBuffer()")); #endif digitalWrite(_NSS, HIGH); #ifdef USE_SPI_TRANSACTION SPI.endTransaction(); #endif return _RXPacketL; } void SX128XLT::writeUint8(uint8_t x) { #ifdef SX128XDEBUG Serial.println(F("writeUint8()")); #endif SPI.transfer(x); _TXPacketL++; //increment count of bytes written } uint8_t SX128XLT::readUint8() { #ifdef SX128XDEBUG Serial.println(F("readUint8()")); #endif byte x; x = SPI.transfer(0); _RXPacketL++; //increment count of bytes read return (x); } void SX128XLT::writeInt8(int8_t x) { #ifdef SX128XDEBUG Serial.println(F("writeInt8()")); #endif SPI.transfer(x); _TXPacketL++; //increment count of bytes written } int8_t SX128XLT::readInt8() { #ifdef SX128XDEBUG Serial.println(F("readInt8()")); #endif int8_t x; x = SPI.transfer(0); _RXPacketL++; //increment count of bytes read return (x); } void SX128XLT::writeInt16(int16_t x) { #ifdef SX128XDEBUG Serial.println(F("writeInt16()")); #endif SPI.transfer(lowByte(x)); SPI.transfer(highByte(x)); _TXPacketL = _TXPacketL + 2; //increment count of bytes written } int16_t SX128XLT::readInt16() { #ifdef SX128XDEBUG 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 SX128XLT::writeUint16(uint16_t x) { #ifdef SX128XDEBUG Serial.println(F("writeUint16()")); #endif SPI.transfer(lowByte(x)); SPI.transfer(highByte(x)); _TXPacketL = _TXPacketL + 2; //increment count of bytes written } uint16_t SX128XLT::readUint16() { #ifdef SX128XDEBUG 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 SX128XLT::writeInt32(int32_t x) { #ifdef SX128XDEBUG 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 SX128XLT::readInt32() { #ifdef SX128XDEBUG 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 SX128XLT::writeUint32(uint32_t x) { #ifdef SX128XDEBUG 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 SX128XLT::readUint32() { #ifdef SX128XDEBUG 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 SX128XLT::writeFloat(float x) { #ifdef SX128XDEBUG 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 SX128XLT::readFloat() { #ifdef SX128XDEBUG 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 SX128XLT::transmitSXBuffer(uint8_t startaddr, uint8_t length, uint16_t timeout, int8_t txpower, uint8_t wait) { #ifdef SX128XDEBUG Serial.println(F("transmitSXBuffer()")); #endif setBufferBaseAddress(startaddr, 0); //TX, RX setPacketParams(savedPacketParam1, savedPacketParam2, length, savedPacketParam4, savedPacketParam5, savedPacketParam6, savedPacketParam7); 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(timeout); //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 SX128XLT::writeBuffer(uint8_t *txbuffer, uint8_t size) { #ifdef SX128XDEBUG1 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 SX128XLT::receiveSXBuffer(uint8_t startaddr, uint16_t timeout, 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(timeout); //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 SX128XLT::readBuffer(uint8_t *rxbuffer) { #ifdef SX128XDEBUG1 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 } void SX128XLT::setSyncWord1(uint32_t syncword) { #ifdef SX128XDEBUG1 Serial.println(F("setSyncWord1()")); #endif //For FLRC packet type, the SyncWord is one byte shorter and //the base address is shifted by one byte writeRegister( REG_FLRCSYNCWORD1_BASEADDR, ( syncword >> 24 ) & 0x000000FF ); writeRegister( REG_FLRCSYNCWORD1_BASEADDR + 1, ( syncword >> 16 ) & 0x000000FF ); writeRegister( REG_FLRCSYNCWORD1_BASEADDR + 2, ( syncword >> 8 ) & 0x000000FF ); writeRegister( REG_FLRCSYNCWORD1_BASEADDR + 3, syncword & 0x000000FF ); } /*************************************************************************** //End direct access SX buffer routines ***************************************************************************/ //******************************************************************************* //Start Ranging routines //******************************************************************************* void SX128XLT::setRangingSlaveAddress(uint32_t address) { //sets address of ranging slave #ifdef SX128XDEBUG Serial.println(F("SetRangingSlaveAddress()")); #endif uint8_t buffer[4]; buffer[0] = (address >> 24u ) & 0xFFu; buffer[1] = (address >> 16u) & 0xFFu; buffer[2] = (address >> 8u) & 0xFFu; buffer[3] = (address & 0xFFu); writeRegisters(0x916, buffer, 4 ); } void SX128XLT::setRangingMasterAddress(uint32_t address) { //sets address of ranging master #ifdef SX128XDEBUG Serial.println(F("SetRangingMasterAddress()")); #endif uint8_t buffer[4]; buffer[0] = (address >> 24u ) & 0xFFu; buffer[1] = (address >> 16u) & 0xFFu; buffer[2] = (address >> 8u) & 0xFFu; buffer[3] = (address & 0xFFu); writeRegisters(0x912, buffer, 4 ); } void SX128XLT::setRangingCalibration(uint16_t cal) { #ifdef SX128XDEBUG Serial.println(F("setRangingCalibration()")); #endif savedCalibration = cal; writeRegister( REG_LR_RANGINGRERXTXDELAYCAL, ( uint8_t )( ( cal >> 8 ) & 0xFF ) ); writeRegister( REG_LR_RANGINGRERXTXDELAYCAL + 1, ( uint8_t )( ( cal ) & 0xFF ) ); } void SX128XLT::setRangingRole(uint8_t role) { #ifdef SX128XDEBUG Serial.println(F("setRangingRole()")); #endif uint8_t buffer[1]; buffer[0] = role; writeCommand(RADIO_SET_RANGING_ROLE, buffer, 1 ); } uint32_t SX128XLT::getRangingResultRegValue(uint8_t resultType) { uint32_t valLsb = 0; setMode(MODE_STDBY_XOSC); writeRegister( 0x97F, readRegister( 0x97F ) | ( 1 << 1 ) ); // enable LORA modem clock writeRegister( REG_LR_RANGINGRESULTCONFIG, ( readRegister( REG_LR_RANGINGRESULTCONFIG ) & MASK_RANGINGMUXSEL ) | ( ( ( ( uint8_t )resultType ) & 0x03 ) << 4 ) ); valLsb = ( ( (uint32_t) readRegister( REG_LR_RANGINGRESULTBASEADDR ) << 16 ) | ( (uint32_t) readRegister( REG_LR_RANGINGRESULTBASEADDR + 1 ) << 8 ) | ( readRegister( REG_LR_RANGINGRESULTBASEADDR + 2 ) ) ); setMode(MODE_STDBY_RC); return valLsb; } double SX128XLT::getRangingDistance(uint8_t resultType, int32_t regval, float adjust) { float val = 0.0; if (regval >= 0x800000) //raw reg value at low distance can goto 0x800000 which is negative, set distance to zero if this happens { regval = 0; } // Conversion from LSB to distance. For explanation on the formula, refer to Datasheet of SX1280 switch (resultType) { case RANGING_RESULT_RAW: // Convert the ranging LSB to distance in meter. The theoretical conversion from register value to distance [m] is given by: // distance [m] = ( complement2( register ) * 150 ) / ( 2^12 * bandwidth[MHz] ) ). The API provide BW in [Hz] so the implemented // formula is complement2( register ) / bandwidth[Hz] * A, where A = 150 / (2^12 / 1e6) = 36621.09 val = ( double ) regval / ( double ) returnBandwidth(savedModParam2) * 36621.09375; break; case RANGING_RESULT_AVERAGED: case RANGING_RESULT_DEBIASED: case RANGING_RESULT_FILTERED: Serial.print(F("??")); val = ( double )regval * 20.0 / 100.0; break; default: val = 0.0; break; } val = val * adjust; return val; } bool SX128XLT::setupRanging(uint32_t frequency, int32_t offset, uint8_t modParam1, uint8_t modParam2, uint8_t modParam3, uint32_t address, uint8_t role) { //sequence is frequency, offset, spreading factor, bandwidth, coding rate, calibration, role. #ifdef SX128XDEBUG Serial.println(F("setupRanging()")); #endif setMode(MODE_STDBY_RC); setPacketType(PACKET_TYPE_RANGING); setModulationParams(modParam1, modParam2, modParam3); setPacketParams(12, LORA_PACKET_VARIABLE_LENGTH, 0, LORA_CRC_ON, LORA_IQ_NORMAL, 0, 0); setRfFrequency(frequency, offset); setRangingSlaveAddress(address); setRangingMasterAddress(address); setRangingCalibration(lookupCalibrationValue(modParam1, modParam2)); setRangingRole(role); setHighSensitivity(); return true; } bool SX128XLT::transmitRanging(uint32_t address, uint16_t timeout, int8_t txpower, uint8_t wait) { #ifdef SX128XDEBUG Serial.println(F("transmitRanging()")); #endif if ((_RXEN >= 0) || (_TXEN >= 0)) { return false; } setMode(MODE_STDBY_RC); setRangingMasterAddress(address); setTxParams(txpower, RADIO_RAMP_02_US); setDioIrqParams(IRQ_RADIO_ALL, (IRQ_TX_DONE + IRQ_RANGING_MASTER_RESULT_VALID + IRQ_RANGING_MASTER_RESULT_TIMEOUT), 0, 0); setTx(timeout); //this sends the ranging packet if (!wait) { return true; } while (!digitalRead(_TXDonePin)); //Wait for DIO1 to go high if (readIrqStatus() & IRQ_RANGING_MASTER_RESULT_VALID ) //check for timeout { return true; } else { return false; } } uint8_t SX128XLT::receiveRanging(uint32_t address, uint16_t timeout, int8_t txpower, uint8_t wait) { #ifdef SX128XDEBUG Serial.println(F("receiveRanging()")); #endif setTxParams(txpower, RADIO_RAMP_02_US); setRangingSlaveAddress(address); setDioIrqParams(IRQ_RADIO_ALL, (IRQ_RANGING_SLAVE_RESPONSE_DONE + IRQ_RANGING_SLAVE_REQUEST_DISCARDED), 0, 0); setRx(timeout); if (!wait) { return NO_WAIT; //not wait requested so no packet length to pass } while (!digitalRead(_RXDonePin)); setMode(MODE_STDBY_RC); //ensure to stop further packet reception if (readIrqStatus() & IRQ_RANGING_SLAVE_REQUEST_VALID) { return true; } else { return false; //so we can check for packet having enough buffer space } } uint16_t SX128XLT::lookupCalibrationValue(uint8_t spreadingfactor, uint8_t bandwidth) { //this looks up the calibration value from the table in SX128XLT_Definitions.hifdef SX128XDEBUG #ifdef SX128XDEBUG Serial.println(F("lookupCalibrationValue()")); #endif switch (bandwidth) { case LORA_BW_0400: savedCalibration = RNG_CALIB_0400[(spreadingfactor>>4)-5]; return savedCalibration; case LORA_BW_0800: savedCalibration = RNG_CALIB_0800[(spreadingfactor>>4)-5]; return savedCalibration; case LORA_BW_1600: savedCalibration = RNG_CALIB_1600[(spreadingfactor>>4)-5]; return savedCalibration; default: return 0xFFFF; } } uint16_t SX128XLT::getSetCalibrationValue() { #ifdef SX128XDEBUG Serial.println(F("getCalibrationValue()")); #endif return savedCalibration;; } //******************************************************************************* //End Ranging routines //******************************************************************************* void SX128XLT::setSleep(uint8_t sleepconfig) { #ifdef SX128XDEBUG 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 //need to save registers to device RAM first digitalWrite(_NSS, LOW); SPI.transfer(RADIO_SET_SAVECONTEXT); digitalWrite(_NSS, HIGH); checkBusy(); digitalWrite(_NSS, LOW); SPI.transfer(RADIO_SET_SLEEP); SPI.transfer(sleepconfig); digitalWrite(_NSS, HIGH); #ifdef USE_SPI_TRANSACTION SPI.endTransaction(); #endif delay(1); //allow time for shutdown } uint16_t SX128XLT::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; } uint8_t SX128XLT::getByteSXBuffer(uint8_t addr) { #ifdef SX128XDEBUG1 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 SX128XLT::printSXBufferHEX(uint8_t start, uint8_t end) { #ifdef SX128XDEBUG 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 } void SX128XLT::printHEXByte(uint8_t temp) { if (temp < 0x10) { Serial.print(F("0")); } Serial.print(temp, HEX); } void SX128XLT::wake() { #ifdef SX128XDEBUG Serial.println(F("wake()")); #endif digitalWrite(_NSS, LOW); delay(1); digitalWrite(_NSS, HIGH); delay(1); } int32_t SX128XLT::getFrequencyErrorRegValue() { #ifdef SX128XDEBUG Serial.println(F("getFrequencyErrorRegValue()")); #endif int32_t FrequencyError; uint32_t regmsb, regmid, reglsb, allreg; setMode(MODE_STDBY_XOSC); regmsb = readRegister( REG_LR_ESTIMATED_FREQUENCY_ERROR_MSB ); regmsb = regmsb & 0x0F; //clear bit 20 which is always set regmid = readRegister( REG_LR_ESTIMATED_FREQUENCY_ERROR_MSB + 1 ); reglsb = readRegister( REG_LR_ESTIMATED_FREQUENCY_ERROR_MSB + 2 ); setMode(MODE_STDBY_RC); #ifdef LORADEBUG 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; } int32_t SX128XLT::getFrequencyErrorHz() { #ifdef SX128XDEBUG Serial.println(F("getFrequencyErrorHz()")); #endif int32_t error, regvalue; uint32_t bandwidth; float divider; bandwidth = returnBandwidth(savedModParam2); //gets the last configured bandwidth divider = (float) 1625000 / bandwidth; //data sheet says 1600000, but bandwidth is 1625000 regvalue = getFrequencyErrorRegValue(); error = (FREQ_ERROR_CORRECTION * regvalue) / divider; return error; } uint8_t SX128XLT::transmitAddressed(uint8_t *txbuffer, uint8_t size, char txpackettype, char txdestination, char txsource, uint32_t timeout, int8_t txpower, uint8_t wait) { #ifdef SX128XDEBUG Serial.println(F("transmitAddressed()")); #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); 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 if (savedPacketType == PACKET_TYPE_LORA) { writeRegister(REG_LR_PAYLOADLENGTH, _TXPacketL); //only seems to work for lora } else if (savedPacketType == PACKET_TYPE_FLRC) { setPacketParams(savedPacketParam1, savedPacketParam2, savedPacketParam3, savedPacketParam4, _TXPacketL, savedPacketParam6, savedPacketParam7); } 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(timeout); //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 SX128XLT::receiveAddressed(uint8_t *rxbuffer, uint8_t size, uint16_t timeout, uint8_t wait) { #ifdef SX128XDEBUG 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(timeout); 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 { return 0; //packet is errored somewhere so 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); _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 } uint8_t SX128XLT::readRXPacketType() { #ifdef SX128XDEBUG Serial.println(F("readRXPacketType()")); #endif return _RXPacketType; } uint8_t SX128XLT::readPacket(uint8_t *rxbuffer, uint8_t size) { #ifdef SX128XDEBUG 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 } uint16_t SX128XLT::addCRC(uint8_t data, uint16_t libraryCRC) { uint8_t j; libraryCRC ^= ((uint16_t)data << 8); for (j = 0; j < 8; j++) { if (libraryCRC & 0x8000) libraryCRC = (libraryCRC << 1) ^ 0x1021; else libraryCRC <<= 1; } return libraryCRC; } void SX128XLT::writeBufferChar(char *txbuffer, uint8_t size) { #ifdef SX128XDEBUG1 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 writen really is a null (0) } uint8_t SX128XLT::readBufferChar(char *rxbuffer) { #ifdef SX128XDEBUG1 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 } /* 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. */