[SX126x] Added spectral scan
This commit is contained in:
parent
15d698c38d
commit
97ab0d357a
9 changed files with 512 additions and 12 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -15,5 +15,8 @@
|
|||
extras/decoder/log.txt
|
||||
extras/decoder/out.txt
|
||||
|
||||
# Spectrum scan
|
||||
extras/SX126x_Spectrum_Scan/out/*
|
||||
|
||||
# PlatformIO
|
||||
.pio*
|
||||
|
|
112
examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino
Normal file
112
examples/SX126x/SX126x_Spectrum_Scan/SX126x_Spectrum_Scan.ino
Normal 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);
|
||||
}
|
136
extras/SX126x_Spectrum_Scan/SpectrumScan.py
Normal file
136
extras/SX126x_Spectrum_Scan/SpectrumScan.py
Normal 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()
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
80
src/modules/SX126x/patches/SX126x_patch_scan.h
Normal file
80
src/modules/SX126x/patches/SX126x_patch_scan.h
Normal 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
|
Loading…
Add table
Reference in a new issue