[SX128x] Implemented ranging
This commit is contained in:
parent
a355a098e6
commit
1592831e0c
7 changed files with 253 additions and 9 deletions
84
examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino
Normal file
84
examples/SX128x/SX128x_Ranging/SX128x_Ranging.ino
Normal file
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
RadioLib SX128x Ranging Example
|
||||
|
||||
This example performs ranging exchange between two
|
||||
SX1280 LoRa radio modules. Ranging allows to measure
|
||||
distance between the modules using time-of-flight
|
||||
measurement.
|
||||
|
||||
Only SX1280 and SX1282 support ranging!
|
||||
|
||||
For full API reference, see the GitHub Pages
|
||||
https://jgromes.github.io/RadioLib/
|
||||
*/
|
||||
|
||||
// include the library
|
||||
#include <RadioLib.h>
|
||||
|
||||
// SX1280 has the following connections:
|
||||
// NSS pin: 10
|
||||
// DIO1 pin: 2
|
||||
// NRST pin: 3
|
||||
// BUSY pin: 9
|
||||
SX1280 lora = new Module(10, 2, 3, 9);
|
||||
|
||||
// or using RadioShield
|
||||
// https://github.com/jgromes/RadioShield
|
||||
//SX1280 lora = RadioShield.ModuleA;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(9600);
|
||||
|
||||
// initialize SX1280 with default settings
|
||||
Serial.print(F("[SX1280] Initializing ... "));
|
||||
// carrier frequency: 2400.0 MHz
|
||||
// bandwidth: 812.5 kHz
|
||||
// spreading factor: 9
|
||||
// coding rate: 7
|
||||
// output power: 10 dBm
|
||||
// preamble length: 12 symbols
|
||||
// CRC: enabled
|
||||
int state = lora.begin();
|
||||
if (state == ERR_NONE) {
|
||||
Serial.println(F("success!"));
|
||||
} else {
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
while (true);
|
||||
}
|
||||
}
|
||||
|
||||
void loop() {
|
||||
Serial.print(F("[SX1280] Ranging ... "));
|
||||
|
||||
// start ranging exchange
|
||||
// range as master: true
|
||||
// slave address: 0x12345678
|
||||
int state = lora.range(true, 0x12345678);
|
||||
|
||||
// the other module must be configured as slave with the same address
|
||||
/*
|
||||
int state = lora.range(false, 0x12345678);
|
||||
*/
|
||||
|
||||
if (state == ERR_NONE) {
|
||||
// ranging finished successfully
|
||||
Serial.println(F("success!"));
|
||||
Serial.print(F("[SX1280] Distance:\t\t\t"));
|
||||
Serial.print(lora.getRangingResult());
|
||||
Serial.println(F(" meters"));
|
||||
|
||||
} else if (state == ERR_RANGING_TIMEOUT) {
|
||||
// timed out waiting for ranging packet
|
||||
Serial.println(F("timed out!"));
|
||||
|
||||
} else {
|
||||
// some other error occurred
|
||||
Serial.print(F("failed, code "));
|
||||
Serial.println(state);
|
||||
|
||||
}
|
||||
|
||||
// wait for a second before ranging again
|
||||
delay(1000);
|
||||
}
|
|
@ -311,3 +311,5 @@ ERR_INVALID_RX_PERIOD LITERAL1
|
|||
ERR_INVALID_CALLSIGN LITERAL1
|
||||
ERR_INVALID_NUM_REPEATERS LITERAL1
|
||||
ERR_INVALID_REPEATER_CALLSIGN LITERAL1
|
||||
|
||||
ERR_RANGING_TIMEOUT LITERAL1
|
||||
|
|
|
@ -480,6 +480,13 @@
|
|||
*/
|
||||
#define ERR_INVALID_REPEATER_CALLSIGN -803
|
||||
|
||||
// SX128x-specific status codes
|
||||
|
||||
/*!
|
||||
\brief Timed out waiting for ranging exchange finish.
|
||||
*/
|
||||
#define ERR_RANGING_TIMEOUT -901
|
||||
|
||||
/*!
|
||||
\}
|
||||
*/
|
||||
|
|
|
@ -3,3 +3,111 @@
|
|||
SX1280::SX1280(Module* mod) : SX1281(mod) {
|
||||
|
||||
}
|
||||
|
||||
int16_t SX1280::range(bool master, uint32_t addr) {
|
||||
// start ranging
|
||||
int16_t state = startRanging(master, addr);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// wait until ranging is finished
|
||||
uint32_t start = millis();
|
||||
while(!digitalRead(_mod->getIrq())) {
|
||||
yield();
|
||||
if(millis() - start > 10000) {
|
||||
clearIrqStatus();
|
||||
standby();
|
||||
return(ERR_RANGING_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
// clear interrupt flags
|
||||
state = clearIrqStatus();
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set mode to standby
|
||||
state = standby();
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
int16_t SX1280::startRanging(bool master, uint32_t addr) {
|
||||
// check active modem
|
||||
uint8_t modem = getPacketType();
|
||||
if(!((modem == SX128X_PACKET_TYPE_LORA) || (modem == SX128X_PACKET_TYPE_RANGING))) {
|
||||
return(ERR_WRONG_MODEM);
|
||||
}
|
||||
|
||||
// ensure modem is set to ranging
|
||||
int16_t state = ERR_NONE;
|
||||
if(modem == SX128X_PACKET_TYPE_LORA) {
|
||||
state = setPacketType(SX128X_PACKET_TYPE_RANGING);
|
||||
RADIOLIB_ASSERT(state);
|
||||
}
|
||||
|
||||
// set modulation parameters
|
||||
state = setModulationParams(_sf, _bw, _cr);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set packet parameters
|
||||
state = setPacketParamsLoRa(_preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// check all address bits
|
||||
uint8_t regValue;
|
||||
state = readRegister(SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1);
|
||||
RADIOLIB_ASSERT(state);
|
||||
regValue &= 0b00111111;
|
||||
regValue |= 0b11000000;
|
||||
state = writeRegister(SX128X_REG_SLAVE_RANGING_ADDRESS_WIDTH, ®Value, 1);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set remaining parameter values
|
||||
uint32_t addrReg = SX128X_REG_SLAVE_RANGING_ADDRESS_BYTE_3;
|
||||
uint32_t irqMask = SX128X_IRQ_RANGING_SLAVE_RESP_DONE | SX128X_IRQ_RANGING_SLAVE_REQ_DISCARD;
|
||||
uint32_t irqDio1 = SX128X_IRQ_RANGING_SLAVE_RESP_DONE;
|
||||
if(master) {
|
||||
addrReg = SX128X_REG_MASTER_RANGING_ADDRESS_BYTE_3;
|
||||
irqMask = SX128X_IRQ_RANGING_MASTER_RES_VALID | SX128X_IRQ_RANGING_MASTER_TIMEOUT;
|
||||
irqDio1 = SX128X_IRQ_RANGING_MASTER_RES_VALID;
|
||||
}
|
||||
|
||||
// set ranging address
|
||||
uint8_t addrBuff[] = { (uint8_t)((addr >> 24) & 0xFF), (uint8_t)((addr >> 16) & 0xFF), (uint8_t)((addr >> 8) & 0xFF), (uint8_t)(addr & 0xFF) };
|
||||
state = writeRegister(addrReg, addrBuff, 4);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set DIO mapping
|
||||
state = setDioIrqParams(irqMask, irqDio1);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// set role and start ranging
|
||||
if(master) {
|
||||
state = setRangingRole(SX128X_RANGING_ROLE_MASTER);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setTx(SX128X_TX_TIMEOUT_NONE);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
} else {
|
||||
state = setRangingRole(SX128X_RANGING_ROLE_SLAVE);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
state = setRx(SX128X_RX_TIMEOUT_INF);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
}
|
||||
|
||||
return(state);
|
||||
}
|
||||
|
||||
float SX1280::getRangingResult() {
|
||||
// read the register values
|
||||
uint8_t data[4];
|
||||
int16_t state = readRegister(SX128X_REG_RANGING_RESULT_MSB, data + 1, 3);
|
||||
RADIOLIB_ASSERT(state);
|
||||
|
||||
// calculate the real result
|
||||
uint32_t raw = 0;
|
||||
memcpy(&raw, data, sizeof(uint32_t));
|
||||
return((float)raw * (150.0/(4.096 * _bwKhz)));
|
||||
}
|
||||
|
|
|
@ -6,8 +6,6 @@
|
|||
#include "SX128x.h"
|
||||
#include "SX1281.h"
|
||||
|
||||
// TODO implement ranging
|
||||
|
||||
/*!
|
||||
\class SX1280
|
||||
|
||||
|
@ -22,6 +20,35 @@ class SX1280: public SX1281 {
|
|||
*/
|
||||
SX1280(Module* mod);
|
||||
|
||||
/*!
|
||||
\brief Blocking ranging method.
|
||||
|
||||
\param master Whether to execute ranging in master mode (true) or slave mode (false).
|
||||
|
||||
\param addr Ranging address to be used.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t range(bool master, uint32_t addr);
|
||||
|
||||
/*!
|
||||
\brief Interrupt-driven ranging method.
|
||||
|
||||
\param master Whether to execute ranging in master mode (true) or slave mode (false).
|
||||
|
||||
\param addr Ranging address to be used.
|
||||
|
||||
\returns \ref status_codes
|
||||
*/
|
||||
int16_t startRanging(bool master, uint32_t addr);
|
||||
|
||||
/*!
|
||||
\brief Gets ranging result of the last ranging exchange.
|
||||
|
||||
\returns Ranging result in meters.
|
||||
*/
|
||||
float getRangingResult();
|
||||
|
||||
#ifndef RADIOLIB_GODMODE
|
||||
private:
|
||||
#endif
|
||||
|
|
|
@ -1182,6 +1182,16 @@ int16_t SX128x::clearIrqStatus(uint16_t clearIrqParams) {
|
|||
return(SPIwriteCommand(SX128X_CMD_CLEAR_IRQ_STATUS, data, 2));
|
||||
}
|
||||
|
||||
int16_t SX128x::setRangingRole(uint8_t role) {
|
||||
uint8_t data[] = { role };
|
||||
return(SPIwriteCommand(SX128X_CMD_SET_RANGING_ROLE, data, 1));
|
||||
}
|
||||
|
||||
int16_t SX128x::setPacketType(uint8_t type) {
|
||||
uint8_t data[] = { type };
|
||||
return(SPIwriteCommand(SX128X_CMD_SET_PACKET_TYPE, data, 1));
|
||||
}
|
||||
|
||||
int16_t SX128x::setHeaderType(uint8_t headerType, size_t len) {
|
||||
// check active modem
|
||||
uint8_t modem = getPacketType();
|
||||
|
|
|
@ -322,6 +322,10 @@
|
|||
#define SX128X_REGULATOR_LDO 0x00 // 7 0 set regulator mode: LDO (default)
|
||||
#define SX128X_REGULATOR_DC_DC 0x01 // 7 0 DC-DC
|
||||
|
||||
//SX128X_CMD_SET_RANGING_ROLE
|
||||
#define SX128X_RANGING_ROLE_MASTER 0x01 // 7 0 ranging role: master
|
||||
#define SX128X_RANGING_ROLE_SLAVE 0x00 // 7 0 slave
|
||||
|
||||
|
||||
/*!
|
||||
\class SX128x
|
||||
|
@ -740,6 +744,13 @@ class SX128x: public PhysicalLayer {
|
|||
#ifndef RADIOLIB_GODMODE
|
||||
protected:
|
||||
#endif
|
||||
Module* _mod;
|
||||
|
||||
// cached LoRa parameters
|
||||
float _bwKhz;
|
||||
uint8_t _bw, _sf, _cr;
|
||||
uint8_t _preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa;
|
||||
|
||||
// SX128x SPI command implementations
|
||||
uint8_t getStatus();
|
||||
int16_t writeRegister(uint16_t addr, uint8_t* data, uint8_t numBytes);
|
||||
|
@ -760,22 +771,17 @@ class SX128x: public PhysicalLayer {
|
|||
int16_t setDioIrqParams(uint16_t irqMask, uint16_t dio1Mask, uint16_t dio2Mask = SX128X_IRQ_NONE, uint16_t dio3Mask = SX128X_IRQ_NONE);
|
||||
uint16_t getIrqStatus();
|
||||
int16_t clearIrqStatus(uint16_t clearIrqParams = SX128X_IRQ_ALL);
|
||||
int16_t setRangingRole(uint8_t role);
|
||||
int16_t setPacketType(uint8_t type);
|
||||
|
||||
int16_t setHeaderType(uint8_t headerType, size_t len = 0xFF);
|
||||
|
||||
#ifndef RADIOLIB_GODMODE
|
||||
private:
|
||||
#endif
|
||||
Module* _mod;
|
||||
|
||||
// common parameters
|
||||
uint8_t _pwr;
|
||||
|
||||
// cached LoRa parameters
|
||||
float _bwKhz;
|
||||
uint8_t _bw, _sf, _cr;
|
||||
uint8_t _preambleLengthLoRa, _headerType, _payloadLen, _crcLoRa;
|
||||
|
||||
// cached GFSK parameters
|
||||
float _modIndexReal;
|
||||
uint16_t _brKbps;
|
||||
|
|
Loading…
Add table
Reference in a new issue