[SX126x] Added spectral scan

This commit is contained in:
jgromes 2023-03-11 20:09:03 +01:00
parent 15d698c38d
commit 97ab0d357a
9 changed files with 512 additions and 12 deletions

3
.gitignore vendored
View file

@ -15,5 +15,8 @@
extras/decoder/log.txt
extras/decoder/out.txt
# Spectrum scan
extras/SX126x_Spectrum_Scan/out/*
# PlatformIO
.pio*

View file

@ -0,0 +1,112 @@
/*
RadioLib SX126x Spectrum Scan Example
This example shows how to perform a spectrum power scan using SX126x.
The output is in the form of scan lines, each line has 33 power bins.
First power bin corresponds to -11 dBm, the second to -15 dBm and so on.
Higher number of samples in a bin corresponds to more power received
at that level.
To show the results in a plot, run the Python script
RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
WARNING: This functionality is experimental and requires a binary patch
to be uploaded to the SX126x device. There may be some undocumented
side effects!
For default module settings, see the wiki page
https://github.com/jgromes/RadioLib/wiki/Default-configuration#sx126x---lora-modem
For full API reference, see the GitHub Pages
https://jgromes.github.io/RadioLib/
*/
// include the library
#include <RadioLib.h>
// this file contains binary patch for the SX1262
#include <modules/SX126x/patches/SX126x_patch_scan.h>
// SX1262 has the following connections:
// NSS pin: 10
// DIO1 pin: 2
// NRST pin: 3
// BUSY pin: 9
SX1262 radio = new Module(10, 2, 3, 9);
void setup() {
Serial.begin(115200);
// initialize SX1262 FSK modem with default settings
Serial.print(F("[SX1262] Initializing ... "));
int state = radio.beginFSK();
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// upload a patch to the SX1262 to enable spectral scan
// NOTE: this patch is uploaded into volatile memory,
// and must be re-uploaded on every power up
Serial.print(F("[SX1262] Uploading patch ... "));
state = radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan));
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// configure scan bandwidth to 234.4 kHz
// and disable the data shaping
Serial.print(F("[SX1262] Setting scan parameters ... "));
state = radio.setRxBandwidth(234.3);
state |= radio.setDataShaping(RADIOLIB_SHAPING_NONE);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
}
void loop() {
Serial.print(F("[SX1262] Starting spectral scan ... "));
// start spectral scan
// number of bands: 2048 (fewer bands = better temporal resolution)
int state = radio.spectralScanStart(2048);
if(state == RADIOLIB_ERR_NONE) {
Serial.println(F("success!"));
} else {
Serial.print(F("failed, code "));
Serial.println(state);
while(true);
}
// wait for spectral scan to finish
while(radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) {
delay(10);
}
// read the results
uint16_t results[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
state = radio.spectralScanGetResult(results);
if(state == RADIOLIB_ERR_NONE) {
// we have some results, print it
Serial.print("SCAN ");
for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) {
Serial.print(results[i]);
Serial.print(',');
}
Serial.println(" END");
}
// wait a little bit before the next scan
delay(5);
}

View file

@ -0,0 +1,136 @@
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
import argparse
import serial
import sys
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
from datetime import datetime
from argparse import RawTextHelpFormatter
# number of samples in each scanline
SCAN_WIDTH = 33
# scanline Serial start/end markers
SCAN_MARK_START = 'SCAN '
SCAN_MARK_END = ' END'
# output path
OUT_PATH = 'out'
# default settings
DEFAULT_BAUDRATE = 115200
DEFAULT_COLOR_MAP = 'viridis'
DEFAULT_SCAN_LEN = 200
DEFAULT_RSSI_OFFSET = -11
# Print iterations progress
# from https://stackoverflow.com/questions/3173320/text-progress-bar-in-terminal-with-block-characters
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 50, fill = '', printEnd = "\r"):
"""
Call in a loop to create terminal progress bar
@params:
iteration - Required : current iteration (Int)
total - Required : total iterations (Int)
prefix - Optional : prefix string (Str)
suffix - Optional : suffix string (Str)
decimals - Optional : positive number of decimals in percent complete (Int)
length - Optional : character length of bar (Int)
fill - Optional : bar fill character (Str)
printEnd - Optional : end character (e.g. "\r", "\r\n") (Str)
"""
percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
filledLength = int(length * iteration // total)
bar = fill * filledLength + '-' * (length - filledLength)
print(f'\r{prefix} |{bar}| {percent}% {suffix}', end = printEnd)
if iteration == total:
print()
def main():
parser = argparse.ArgumentParser(formatter_class=RawTextHelpFormatter, description='''
RadioLib SX126x_Spectrum_Scan plotter script. Displays output from SX126x_Spectrum_Scan example
as grayscale and
Depends on pyserial and matplotlib, install by:
'python3 -m pip install pyserial matplotlib'
Step-by-step guide on how to use the script:
1. Upload the SX126x_Spectrum_Scan example to your Arduino board with SX1262 connected.
2. Run the script with appropriate arguments.
3. Once the scan is complete, output files will be saved to out/
''')
parser.add_argument('port',
type=str,
help='COM port to connect to the device')
parser.add_argument('--speed',
default=DEFAULT_BAUDRATE,
type=int,
help=f'COM port baudrate (defaults to {DEFAULT_BAUDRATE})')
parser.add_argument('--map',
default=DEFAULT_COLOR_MAP,
type=str,
help=f'Matplotlib color map to use for the output (defaults to "{DEFAULT_COLOR_MAP}")')
parser.add_argument('--len',
default=DEFAULT_SCAN_LEN,
type=int,
help=f'Number of scanlines to record (defaults to {DEFAULT_SCAN_LEN})')
parser.add_argument('--offset',
default=DEFAULT_RSSI_OFFSET,
type=int,
help=f'Default RSSI offset in dBm (defaults to {DEFAULT_RSSI_OFFSET})')
args = parser.parse_args()
# create the color map and the result array
arr = np.zeros((SCAN_WIDTH, args.len))
# scanline counter
row = 0
# open the COM port
with serial.Serial(args.port, args.speed, timeout=None) as com:
while(True):
# update the progress bar
printProgressBar(row, args.len)
# read a single line
line = com.readline().decode('utf-8')
# check the markers
if (SCAN_MARK_START in line) and (SCAN_MARK_END in line):
# get the values
scanline = line[len(SCAN_MARK_START):-len(SCAN_MARK_END)].split(',')
for col in range(SCAN_WIDTH):
arr[col][row] = int(scanline[col])
# increment the row counter
row = row + 1
# check if we're done
if row >= args.len:
break
# create the figure
fig, ax = plt.subplots()
# display the result as heatmap
extent = [0, args.len, -4*(SCAN_WIDTH + 1), args.offset]
im = ax.imshow(arr, cmap=args.map, extent=extent)
fig.colorbar(im)
# set some properites and show
timestamp = datetime.now().strftime('%y-%m-%d %H-%M-%S')
title = f'RadioLib SX126x Spectral Scan {timestamp}'
plt.xlabel("Time [sample]")
plt.ylabel("RSSI [dBm]")
ax.set_aspect('auto')
fig.suptitle(title)
fig.canvas.manager.set_window_title(title)
plt.savefig(f'{OUT_PATH}/{title.replace(" ", "_")}.png', dpi=300)
plt.show()
if __name__ == "__main__":
main()

View file

@ -195,6 +195,11 @@ getCurrentLimit KEYWORD2
getIrqStatus KEYWORD2
getLastError KEYWORD2
setRxBoostedGainMode KEYWORD2
uploadPatch KEYWORD2
spectralScanStart KEYWORD2
spectralScanAbort KEYWORD2
spectralScanGetStatus KEYWORD2
spectralScanGetResult KEYWORD2
# nRF24
setIrqAction KEYWORD2

View file

@ -120,6 +120,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -155,6 +156,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -190,6 +192,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// ESP32 doesn't support tone(), but it can be emulated via LED control peripheral
@ -229,6 +232,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -264,6 +268,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -299,6 +304,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -334,6 +340,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
#define RADIOLIB_TONE_UNSUPPORTED
@ -370,6 +377,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -405,6 +413,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -440,6 +449,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -475,6 +485,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -510,6 +521,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds
@ -549,6 +561,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds
@ -588,6 +601,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -623,6 +637,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -658,6 +673,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino mbed OS boards have a really bad tone implementation which will crash after a couple seconds
@ -697,6 +713,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -732,6 +749,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
// Arduino API callbacks
#define RADIOLIB_CB_ARGS_PIN_MODE (void, pinMode, uint8_t pin, PINMODE mode)
@ -788,6 +806,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -843,6 +862,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks
@ -879,6 +899,7 @@
#define RADIOLIB_DEFAULT_SPI_SETTINGS SPISettings(2000000, MSBFIRST, SPI_MODE0)
#define RADIOLIB_NONVOLATILE PROGMEM
#define RADIOLIB_NONVOLATILE_READ_BYTE(addr) pgm_read_byte(addr)
#define RADIOLIB_NONVOLATILE_READ_DWORD(addr) pgm_read_dword(addr)
#define RADIOLIB_TYPE_ALIAS(type, alias) using alias = type;
// Arduino API callbacks

View file

@ -98,6 +98,7 @@
#include "protocols/Pager/Pager.h"
#include "protocols/RTTY/RTTY.h"
#include "protocols/SSTV/SSTV.h"
#include "protocols/SSDV/SSDV.h"
#include "protocols/FSK4/FSK4.h"
#include "protocols/APRS/APRS.h"
#include "protocols/ExternalRadio/ExternalRadio.h"

View file

@ -206,13 +206,13 @@ int16_t SX126x::reset(bool verify) {
}
// standby command failed, check timeout and try again
if(_mod->millis() - start >= 3000) {
if(_mod->millis() - start >= 1000) {
// timed out, possibly incorrect wiring
return(state);
}
// wait a bit to not spam the module
_mod->delay(10);
_mod->delay(100);
}
}
@ -1378,6 +1378,95 @@ void SX126x::readBit(RADIOLIB_PIN_TYPE pin) {
}
#endif
int16_t SX126x::uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile) {
// set to standby RC mode
int16_t state = standby(RADIOLIB_SX126X_STANDBY_RC);
RADIOLIB_ASSERT(state);
// check the version
#if defined(RADIOLIB_DEBUG)
char ver_pre[16];
_mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_pre);
RADIOLIB_DEBUG_PRINT(F("Pre-update version string: "));
RADIOLIB_DEBUG_PRINTLN(ver_pre);
#endif
// enable patch update
_mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_ENABLED);
// upload the patch
uint8_t data[4];
for(uint32_t i = 0; i < len / sizeof(uint32_t); i++) {
uint32_t bin = 0;
if(nonvolatile) {
bin = RADIOLIB_NONVOLATILE_READ_DWORD(patch + i);
} else {
bin = patch[i];
}
data[0] = (bin >> 24) & 0xFF;
data[1] = (bin >> 16) & 0xFF;
data[2] = (bin >> 8) & 0xFF;
data[3] = bin & 0xFF;
_mod->SPIwriteRegisterBurst(RADIOLIB_SX126X_REG_PATCH_MEMORY_BASE + i*sizeof(uint32_t), data, sizeof(uint32_t));
}
// disable patch update
_mod->SPIwriteRegister(RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE, RADIOLIB_SX126X_PATCH_UPDATE_DISABLED);
// update
_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_PRAM_UPDATE, NULL, 0);
// check the version again
#if defined(RADIOLIB_DEBUG)
char ver_post[16];
_mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_VERSION_STRING, 16, (uint8_t*)ver_post);
RADIOLIB_DEBUG_PRINT(F("Post-update version string: "));
RADIOLIB_DEBUG_PRINTLN(ver_post);
#endif
return(state);
}
int16_t SX126x::spectralScanStart(uint16_t numBands, uint8_t window, uint8_t interval) {
// abort first - not sure if this is strictly needed, but the example code does this
spectralScanAbort();
// set the RSSI window size
_mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, window);
// start Rx with infinite timeout
int16_t state = setRx(RADIOLIB_SX126X_RX_TIMEOUT_INF);
RADIOLIB_ASSERT(state);
// now set the actual spectral scan parameters
uint8_t data[3] = { (uint8_t)((numBands >> 8) & 0xFF), (uint8_t)(numBands & 0xFF), interval };
return(_mod->SPIwriteStream(RADIOLIB_SX126X_CMD_SET_SPECTR_SCAN_PARAMS, data, 3));
}
void SX126x::spectralScanAbort() {
_mod->SPIwriteRegister(RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW, 0x00);
}
int16_t SX126x::spectralScanGetStatus() {
uint8_t status = _mod->SPIreadRegister(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS);
if(status == RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED) {
return(RADIOLIB_ERR_NONE);
}
return(RADIOLIB_ERR_RANGING_TIMEOUT);
}
int16_t SX126x::spectralScanGetResult(uint16_t* results) {
// read the raw results
uint8_t data[2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
_mod->SPIreadRegisterBurst(RADIOLIB_SX126X_REG_SPECTRAL_SCAN_RESULT, 2*RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE, data);
// convert it
for(uint8_t i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) {
results[i] = ((uint16_t)data[i*2] << 8) | ((uint16_t)data[i*2 + 1]);
}
return(RADIOLIB_ERR_NONE);
}
int16_t SX126x::setTCXO(float voltage, uint32_t delay) {
// check if TCXO is enabled at all
if(this->XTAL) {

View file

@ -412,14 +412,19 @@
#define RADIOLIB_SX126X_RX_GAIN_SPECTRAL_SCAN 0xCB // 7 0 spectral scan
// RADIOLIB_SX126X_REG_PATCH_UPDATE_ENABLE
#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00010000 // 4 4 patch update: disabled
#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00000000 // 4 4 enabled
#define RADIOLIB_SX126X_PATCH_UPDATE_DISABLED 0b00000000 // 4 4 patch update: disabled
#define RADIOLIB_SX126X_PATCH_UPDATE_ENABLED 0b00010000 // 4 4 enabled
// RADIOLIB_SX126X_REG_SPECTRAL_SCAN_STATUS
#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none
#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing
#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted
#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed
#define RADIOLIB_SX126X_SPECTRAL_SCAN_NONE 0x00 // 7 0 spectral scan status: none
#define RADIOLIB_SX126X_SPECTRAL_SCAN_ONGOING 0x0F // 7 0 ongoing
#define RADIOLIB_SX126X_SPECTRAL_SCAN_ABORTED 0xF0 // 7 0 aborted
#define RADIOLIB_SX126X_SPECTRAL_SCAN_COMPLETED 0xFF // 7 0 completed
// RADIOLIB_SX126X_REG_RSSI_AVG_WINDOW
#define RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT (0x05 << 2) // 7 0 default RSSI average window
#define RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE (33)
/*!
\class SX126x
@ -1041,20 +1046,68 @@ class SX126x: public PhysicalLayer {
#if !defined(RADIOLIB_EXCLUDE_DIRECT_RECEIVE)
/*!
\brief Dummy method, to ensure PhysicalLayer compatibility.
\brief Set interrupt service routine function to call when data bit is receveid in direct mode.
\param func Ignored.
\param func Pointer to interrupt service routine.
*/
void setDirectAction(void (*func)(void));
/*!
\brief Dummy method, to ensure PhysicalLayer compatibility.
\brief Function to read and process data bit in direct reception mode.
\param pin Ignored.
\param pin Pin on which to read.
*/
void readBit(RADIOLIB_PIN_TYPE pin);
#endif
/*!
\brief Upload binary patch into the SX126x device RAM.
Patch is needed to e.g., enable spectral scan and must be uploaded again on every power cycle.
\param patch Binary patch to upload.
\param len Length of the binary patch in 4-byte words.
\param nonvolatile Set to true when the patch is saved in non-volatile memory of the host processor,
or to false when the patch is in its RAM.
\returns \ref status_codes
*/
int16_t uploadPatch(const uint32_t* patch, size_t len, bool nonvolatile = true);
/*!
\brief Start spectral scan. Requires binary path to be uploaded.
\param numBands Number of bands for the scan. Fewer bands = better temporal resolution, but fewer power samples.
\param window RSSI averaging window size.
\param interval Scan interval length, one of RADIOLIB_SX126X_SCAN_INTERVAL_* macros.
\returns \ref status_codes
*/
int16_t spectralScanStart(uint16_t numBands, uint8_t window = RADIOLIB_SX126x_SPECTRAL_SCAN_WINDOW_DEFAULT, uint8_t interval = RADIOLIB_SX126X_SCAN_INTERVAL_8_20_US);
/*!
\brief Abort an ongoing spectral scan.
*/
void spectralScanAbort();
/*!
\brief Read the status of spectral scan.
\returns \ref status_codes
*/
int16_t spectralScanGetStatus();
/*!
\brief Read the result of spectral scan.
\param results Array to which the results will be saved, must be RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE long.
\returns \ref status_codes
*/
int16_t spectralScanGetResult(uint16_t* results);
#if !defined(RADIOLIB_GODMODE)
protected:

View file

@ -0,0 +1,80 @@
#if !defined(_RADIOLIB_SX126X_PATCH_SCAN_H)
#define _RADIOLIB_SX126X_PATCH_SCAN_H
#include "../../../TypeDef.h"
#if !defined(RADIOLIB_EXCLUDE_SX126X)
// the following is a binary patch to the SX1262
// this patch is needed to enable spectral scan functionality
const uint32_t sx126x_patch_scan[] RADIOLIB_NONVOLATILE = {
0x337fe1, 0x337fdb, 0x337fd5, 0x337fcf, 0x3a7fc8, 0x3f3fff,
0x0378ff, 0x0379ff, 0x3a7fb7, 0x16a901, 0x16a801, 0x23ffff,
0x0378ff, 0x0379ff, 0x3a7faf, 0x16a901, 0x16a801, 0x23ffff,
0x0378ff, 0x0379ff, 0x3a7f34, 0x16a901, 0x16a801, 0x23ffff,
0x0378ff, 0x0379ff, 0x3a7e80, 0x16a901, 0x16a801, 0x23ffff,
0x0378ff, 0x0379ff, 0x3a7fc3, 0x16a901, 0x16a801, 0x337fc9,
0x0378ff, 0x0379ff, 0x3a7fc0, 0x16a901, 0x16a801, 0x337fc9,
0x0378ff, 0x0379ff, 0x3a7fbd, 0x16a901, 0x16a801, 0x337fc9,
0x0378ff, 0x0379ff, 0x3a7fba, 0x16a901, 0x16a801, 0x337fc9,
0x23ffff, 0x0ea1fc, 0x0ea0df, 0x0eafc9, 0x02cf0e, 0x23ffff,
0x0eacff, 0x0eabff, 0x23ffff, 0x0eacff, 0x0eabff, 0x23ffff,
0x0eacff, 0x0eabff, 0x23ffff, 0x0eacff, 0x0eabff, 0x23ffff,
0x0378ff, 0x0379ff, 0x3a7fc8, 0x0eacfd, 0x0eabff, 0x16a901,
0x16a801, 0x23ffff, 0x0374ff, 0x0375ff, 0x0378ff, 0x0379ff,
0x16affe, 0x0ea5ff, 0x0ea465, 0x1dbb04, 0x0e1bfd, 0x307fa3,
0x1caf00, 0x327fa0, 0x0eacf7, 0x0eabff, 0x337f3a, 0x1cad04,
0x0eacfe, 0x0eabff, 0x0dbfdd, 0x307f97, 0x0dafcc, 0x0defbb,
0x0dbfdd, 0x347f9b, 0x0eecef, 0x0caffc, 0x04ade8, 0x0cbdcd,
0x01bde8, 0x04abe8, 0x0ebbbf, 0x01bbe8, 0x04abe8, 0x0ebbdf,
0x01bbe8, 0x1ca800, 0x0ea9ff, 0x04abe3, 0x0e2b01, 0x01bbe3,
0x04abee, 0x0e2b01, 0x01bbee, 0x1ca202, 0x1ca301, 0x02f300,
0x02f201, 0x0ea064, 0x0ea1f7, 0x18ab00, 0x367f58, 0x0ea041,
0x0ea1f7, 0x18ab00, 0x1c1b03, 0x317f3f, 0x1ea201, 0x1ea300,
0x0cb23f, 0x327f4a, 0x1cab04, 0x0eaefe, 0x0dbfbb, 0x307f6c,
0x0dafee, 0x0dbfbb, 0x347f6f, 0x04abee, 0x0cbbeb, 0x01bbee,
0x0eacff, 0x0eabff, 0x0c1b9f, 0x327f64, 0x0c1c8f, 0x317f5c,
0x3fffff, 0x0d1fcc, 0x0d5fbb, 0x0c1b9f, 0x327f5d, 0x0c1c8f,
0x357f63, 0x0ea064, 0x0ea1f7, 0x18ab00, 0x327f7c, 0x1cad04,
0x0eacfe, 0x0dbfdd, 0x307f51, 0x0dafcc, 0x0dbfdd, 0x347f54,
0x0d8fcb, 0x04acee, 0x0c2bcb, 0x01bbee, 0x0eacfd, 0x0eabff,
0x337f3a, 0x1cad04, 0x0eacfe, 0x0dbfdd, 0x307f43, 0x0dafcc,
0x0dbfdd, 0x347f46, 0x0d8fcb, 0x04acee, 0x0c2bcb, 0x337f6a,
0x0cb23f, 0x367f75, 0x0dbf22, 0x0dff33, 0x337f75, 0x16af02,
0x16a901, 0x16a801, 0x16a501, 0x16a401, 0x23ffff, 0x0374ff,
0x0375ff, 0x0378ff, 0x0379ff, 0x16afe0, 0x0ea5ff, 0x0ea465,
0x1ca802, 0x0ea9ff, 0x0eafff, 0x02ff00, 0x0eaff7, 0x02ff01,
0x0eafef, 0x02ff02, 0x0eafe7, 0x02ff03, 0x0eafdf, 0x02ff04,
0x0eafd7, 0x02ff05, 0x0eafcf, 0x02ff06, 0x0eafc7, 0x02ff07,
0x0eafbf, 0x02ff08, 0x0eafb7, 0x02ff09, 0x0eafaf, 0x02ff0a,
0x0eafa7, 0x02ff0b, 0x0eaf9f, 0x02ff0c, 0x0eaf97, 0x02ff0d,
0x0eaf8f, 0x02ff0e, 0x0eaf87, 0x02ff0f, 0x0eaf7f, 0x02ff10,
0x0eaf77, 0x02ff11, 0x0eaf6f, 0x02ff12, 0x0eaf67, 0x02ff13,
0x0eaf5f, 0x02ff14, 0x0eaf57, 0x02ff15, 0x0eaf4f, 0x02ff16,
0x0eaf47, 0x02ff17, 0x0eaf3f, 0x02ff18, 0x0eaf37, 0x02ff19,
0x0eaf2f, 0x02ff1a, 0x0eaf27, 0x02ff1b, 0x0eaf1f, 0x02ff1c,
0x0eaf17, 0x02ff1d, 0x0eaf0f, 0x02ff1e, 0x0eaf07, 0x02ff1f,
0x04abee, 0x0e2b01, 0x01bbee, 0x0eacff, 0x0eabff, 0x0cafc0,
0x0ec0ff, 0x0cafb1, 0x0ed1fb, 0x0eafff, 0x02cf00, 0x0d1fcc,
0x0d5fbb, 0x0e1bff, 0x327edb, 0x0e1c00, 0x347ee6, 0x0ea2ff,
0x0ea3ff, 0x0ea032, 0x0ea1f8, 0x0eaff0, 0x02cf00, 0x0ea064,
0x0ea1f7, 0x18ad00, 0x1c1300, 0x327ece, 0x1c1201, 0x317e9b,
0x0e1dff, 0x367e9b, 0x0ea041, 0x0ea1f7, 0x18ab00, 0x0eebdf,
0x0cafbc, 0x0eabff, 0x0ccccc, 0x0cdbbb, 0x0cafc0, 0x0ec0ff,
0x0cafb1, 0x0ed1fb, 0x18ab01, 0x0eacff, 0x18ae02, 0x0eadff,
0x0ccecc, 0x0cddbb, 0x0d1fcc, 0x0d5fbb, 0x0cafbe, 0x0eadff,
0x02ce01, 0x02cc02, 0x0d1f22, 0x0d5f33, 0x0ea064, 0x0ea1f7,
0x18ad00, 0x0eacff, 0x0eabff, 0x0c1b9f, 0x327ea9, 0x0c1c8f,
0x317ea1, 0x3fffff, 0x0d1fcc, 0x0d5fbb, 0x0c1b9f, 0x327ea2,
0x0c1c8f, 0x357ea8, 0x1c1300, 0x327e9e, 0x1c1201, 0x317e9b,
0x0e1dff, 0x327ecb, 0x0e1dff, 0x367e90, 0x0ea032, 0x0ea1f8,
0x0eaf00, 0x02cf00, 0x0ea1fb, 0x0ea0ff, 0x0eaf00, 0x02cf00,
0x337e88, 0x0ea032, 0x0ea1f8, 0x0eaf0f, 0x02cf00, 0x0ea1fb,
0x0ea0ff, 0x0eaf0f, 0x02cf00, 0x0eacfd, 0x0eabff, 0x16af20,
0x16a901, 0x16a801, 0x16a501, 0x16a401, 0x23ffff, 0x0eacf7,
0x0eabff, 0x23ffff
};
#endif
#endif