first commit

This commit is contained in:
Egor Shitikov
2024-07-22 16:17:04 -07:00
commit 1ed10b5a95
13 changed files with 672 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

10
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

21
README.md Normal file
View File

@@ -0,0 +1,21 @@
# Lora SA(Spectrum Analyzer)
RF Spectrum Analyzer using Lora Radio
RadioLib SX126x Spectrum Scan
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.
The spectrum analyzer perform power measurements in the configured bandwidth.
To show the results in a plot, run the Python script
RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
# VSCode Platform.IO installation
# Hardware
# 3D printed case

176
SpectrumScan.py Normal file
View File

@@ -0,0 +1,176 @@
#!/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_FREQ = 'FREQ '
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})')
parser.add_argument('--freq',
default=-1,
type=float,
help=f'Default starting frequency in MHz')
args = parser.parse_args()
freq_mode = False
scan_len = args.len
if (args.freq != -1):
freq_mode = True
scan_len = 1000
# create the color map and the result array
arr = np.zeros((SCAN_WIDTH, scan_len))
# scanline counter
row = 0
# list of frequencies in frequency mode
freq_list = []
# open the COM port
with serial.Serial(args.port, args.speed, timeout=None) as com:
while(True):
# update the progress bar
if not freq_mode:
printProgressBar(row, scan_len)
# read a single line
try:
line = com.readline().decode('utf-8')
except:
continue
if SCAN_MARK_FREQ in line:
new_freq = float(line.split(' ')[1])
if (len(freq_list) > 1) and (new_freq < freq_list[-1]):
break
freq_list.append(new_freq)
print('{:.3f}'.format(new_freq), end = '\r')
continue
# 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 (not freq_mode) and (row >= scan_len):
break
# scale to the number of scans (sum of any given scanline)
num_samples = arr.sum(axis=0)[0]
arr *= (num_samples/arr.max())
if freq_mode:
scan_len = len(freq_list)
# create the figure
fig, ax = plt.subplots()
# display the result as heatmap
extent = [0, scan_len, -4*(SCAN_WIDTH + 1), args.offset]
if freq_mode:
extent[0] = freq_list[0]
extent[1] = freq_list[-1]
im = ax.imshow(arr[:,:scan_len], 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}'
if freq_mode:
plt.xlabel("Frequency [Hz]")
else:
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()

39
include/README Normal file
View File

@@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

46
lib/README Normal file
View File

@@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

BIN
media/UCOG-SA.JPEG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
media/ucog-mono.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
media/ucog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

19
platformio.ini Normal file
View File

@@ -0,0 +1,19 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:heltec_wifi_lora_32_V3]
platform = espressif32
board = heltec_wifi_lora_32_V3
framework = arduino
upload_speed = 115200
monitor_speed = 115200
board_build.f_cpu = 240000000
lib_deps =
ropg/Heltec_ESP32_LoRa_v3@^0.9.1

101
src/images.h Normal file
View File

@@ -0,0 +1,101 @@
//'Logo_UCOG', 128x64px
//https://www.online-utility.org/image/convert/to/XBM
//https://javl.github.io/image2cpp/
//#define 1721604660673_width 128
//#define 1721604660673_height 64
const unsigned char epd_bitmap_ucog [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF8, 0x01, 0x00, 0x00,
0x00, 0xC0, 0x00, 0x00, 0x10, 0x84, 0xC3, 0x81, 0x03, 0x00, 0x60, 0x00,
0xCC, 0x07, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x30, 0xE6, 0xF3, 0xE3,
0x07, 0x00, 0x60, 0x00, 0x0C, 0x3E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00,
0x30, 0x66, 0x10, 0x36, 0x00, 0x00, 0x60, 0x00, 0x06, 0xF8, 0x00, 0x00,
0x00, 0x0E, 0x00, 0x00, 0x30, 0x26, 0x18, 0x36, 0x00, 0x00, 0x60, 0x00,
0x07, 0xE0, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x26, 0x18, 0x36,
0x07, 0x00, 0x60, 0x00, 0x03, 0x00, 0x1F, 0x00, 0xC0, 0x01, 0x00, 0x00,
0x30, 0x26, 0x18, 0x36, 0x06, 0x00, 0x60, 0x80, 0x01, 0x00, 0x7C, 0x00,
0xE0, 0x00, 0x00, 0x00, 0x30, 0x66, 0x38, 0x76, 0x06, 0x0C, 0x60, 0xC0,
0x01, 0x00, 0xF0, 0x01, 0x78, 0x00, 0x00, 0x00, 0xE0, 0xE3, 0xF3, 0xE3,
0x07, 0x0E, 0x60, 0xC0, 0x03, 0x00, 0x80, 0x0F, 0x1C, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x60, 0xE0, 0x07, 0x00, 0x00, 0x3E,
0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x60, 0x60,
0x0E, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xE0, 0x01, 0x60, 0x70, 0x1C, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x60, 0x30, 0x38, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x60, 0x18,
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x38, 0x00, 0xF0, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xFC, 0x0D, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F,
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x80, 0x67, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x61, 0x1C, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x38,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x38, 0x60, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xE0, 0xE0, 0x01, 0x00, 0x00, 0x00,
0xF0, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x67, 0xE0, 0x83,
0x03, 0x00, 0x00, 0xE0, 0xFF, 0xE1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x02,
0xD0, 0x63, 0x60, 0x07, 0x07, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0x03, 0x00,
0x00, 0x08, 0x00, 0x02, 0xF0, 0x61, 0x60, 0x1C, 0x1F, 0x80, 0xFF, 0x07,
0x00, 0x00, 0x0E, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xF8,
0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x18, 0x00, 0x02,
0xF0, 0x7F, 0x60, 0xDC, 0x1F, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x1E, 0x00,
0x00, 0x00, 0x00, 0x02, 0xD0, 0x61, 0x60, 0x07, 0x0F, 0x00, 0xC0, 0xFF,
0x03, 0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x90, 0x67, 0xE0, 0x83,
0x03, 0x00, 0x00, 0xF0, 0xFF, 0xC1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x7E, 0xE0, 0xC1, 0x01, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x38,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xC0, 0x61, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x67, 0x0F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xEE, 0x0F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x1C, 0x00, 0xFC, 0x0D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xF0, 0x18, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x18,
0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x70, 0x00, 0x60, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x60, 0x70, 0x3C, 0x00, 0x00, 0xE0,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x60, 0x60,
0x1E, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x80, 0x07, 0x60, 0xE0, 0x0F, 0x00, 0x00, 0x3E, 0x0F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x07, 0x03, 0x00, 0x0F, 0x60, 0xC0, 0x03, 0x00, 0x80, 0x0F,
0x1C, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x07, 0x00, 0x0C, 0x60, 0xC0,
0x01, 0x00, 0xF0, 0x01, 0x38, 0x00, 0x00, 0x00, 0x00, 0x80, 0x81, 0x05,
0x00, 0x08, 0x60, 0xC0, 0x01, 0x00, 0x7C, 0x00, 0xE0, 0x00, 0x00, 0x00,
0x00, 0x80, 0x83, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, 0x1F, 0x00,
0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x0C, 0x00, 0x00, 0x60, 0x00,
0x07, 0xE0, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x0F,
0x00, 0x00, 0x60, 0x00, 0x06, 0xF8, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00,
0x00, 0x00, 0xCC, 0x1F, 0x00, 0x00, 0x60, 0x00, 0x0E, 0x3E, 0x00, 0x00,
0x00, 0x1C, 0x00, 0x00, 0x00, 0x80, 0x67, 0x18, 0x00, 0x00, 0x60, 0x00,
0xCC, 0x07, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x60, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xFC, 0x01, 0x00, 0x00,
0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
};
// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 1040)
const int epd_bitmap_allArray_LEN = 1;
const unsigned char* epd_bitmap_allArray[1] = {
epd_bitmap_ucog
};

244
src/main.cpp Normal file
View File

@@ -0,0 +1,244 @@
/**
RadioLib SX126x Spectrum Scan
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/
*/
// frequency range in MHz to scan
#define FREQ_BEGIN 400.00
#define FREQ_END 500.00
// Measurement bandwidth. Allowed bandwidth values (in kHz) are:
// 4.8, 5.8, 7.3, 9.7, 11.7, 14.6, 19.5, 23.4, 29.3, 39.0, 46.9, 58.6,
// 78.2, 93.8, 117.3, 156.2, 187.2, 234.3, 312.0, 373.6 and 467.0
#define BANDWIDTH 93.8//467.0
// (optional) major and minor tickmarks at x MHz
#define MAJOR_TICKS 10
// #define MINOR_TICKS 5
// Turns the 'PRG' button into the power button, long press is off
#define HELTEC_POWER_BUTTON // must be before "#include <heltec_unofficial.h>"
#include <Arduino.h>
#include <heltec_unofficial.h>
#include <images.h>
// This file contains binary patch for the SX1262
#include "modules/SX126x/patches/SX126x_patch_scan.h"
// Prints the scan measurement bins from the SX1262 in hex
#define PRINT_SCAN_VALUES
#define PRINT_PROFILE_TIME
// numbers of the spectrum screan lines = width of screan
#define STEPS 128
// Number of samples for each scan. Fewer samples = better temporal resolution.
#define SAMPLES 256 //(scan time = 1294)
#define MAJOR_TICK_LENGTH 3
#define MINOR_TICK_LENGTH 1
#define X_AXIS_WEIGHT 2
#define HEIGHT RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE
//
#define SCALE_TEXT_TOP (HEIGHT + X_AXIS_WEIGHT + MAJOR_TICK_LENGTH)
#define STATUS_TEXT_TOP (64 - 14)
#define RANGE (float)(FREQ_END - FREQ_BEGIN)
#define SINGLE_STEP (float)(RANGE / STEPS)
// Array to store the scan results
uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
// global variable
unsigned short int scan_var = 0;
// initialized flag
bool initialized = false;
bool led_flag = true;
// drone tetection flag
unsigned short int drone_detected = 0;
unsigned int start_scan_text = (128 / 2) - 3;
unsigned int scan_time = 0;
uint64_t start = 0;
unsigned int x,y = 0;
/**
* @brief Draws ticks on the display at regular whole intervals.
*
* @param every The interval between ticks in MHz.
* @param length The length of each tick in pixels.
*/
void drawTicks(float every, int length) {
float first_tick = FREQ_BEGIN + (every - (FREQ_BEGIN - (int)(FREQ_BEGIN / every) * every));
if (first_tick < FREQ_BEGIN){
first_tick += every;
}
for (float tick_freq = first_tick; tick_freq <= FREQ_END; tick_freq += every) {
int tick = round((tick_freq - FREQ_BEGIN) / SINGLE_STEP);
display.drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick, HEIGHT + X_AXIS_WEIGHT + length);
}
}
/**
* @brief Decorates the display: everything but the plot itself.
*/
void displayDecorate() {
if (!initialized) {
// begining and end ticks
display.fillRect(0, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH);
display.fillRect(126, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH);
// frequencies
display.setTextAlignment(TEXT_ALIGN_LEFT);
display.drawString(0, SCALE_TEXT_TOP, String(FREQ_BEGIN));
display.setTextAlignment(TEXT_ALIGN_RIGHT);
display.drawString(127, SCALE_TEXT_TOP, String(FREQ_END));
}
if(led_flag == true){
digitalWrite(35, HIGH);
led_flag = false;
} else {
digitalWrite(35, LOW);
led_flag = true;
}
// Status text block
if (drone_detected == 0) {
// "Scanning"
display.setTextAlignment(TEXT_ALIGN_CENTER);
//clear status line
display.setColor(BLACK);
display.fillRect(0, STATUS_TEXT_TOP, 128, 16);
display.setColor(WHITE);
if (scan_var == 0) {
display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scanning. ");
}
else if (scan_var == 1) {
display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scanning.. ");
}
else if (scan_var == 2) {
display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scanning...");
}
scan_var++;
if (scan_var == 3) scan_var = 0;
}
if (!initialized) {
// X-axis
display.fillRect(0, HEIGHT, STEPS, X_AXIS_WEIGHT);
// ticks
#ifdef MAJOR_TICKS
drawTicks(MAJOR_TICKS, MAJOR_TICK_LENGTH);
#endif
#ifdef MINOR_TICKS
drawTicks(MINOR_TICKS, MINOR_TICK_LENGTH);
#endif
}
initialized = true;
}
void setup() {
pinMode(35, OUTPUT);
heltec_setup();
display.clear();
// draw the logo
display.drawXbm(0, 0, 128, 64, epd_bitmap_ucog);
display.display();
heltec_delay(4000);
// initialize SX1262 FSK modem at the initial frequency
both.println("Init radio");
RADIOLIB_OR_HALT(radio.beginFSK(FREQ_BEGIN));
// 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
both.println("Upload SX1262 patch");
// 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.
RADIOLIB_OR_HALT(radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan)));
// configure scan bandwidth and disable the data shaping
both.println("Setting up radio");
RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH));
// and disable the data shaping
RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE));
both.println("Starting scaning...");
float vbat = heltec_vbat();
both.printf("Vbat: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat));
heltec_delay(800);
display.clear();
displayDecorate();
}
void loop() {
displayDecorate();
#ifdef PRINT_PROFILE_TIME
start = millis();
#endif
// clear the scan plot rectangle
display.setColor(BLACK);
display.fillRect(0, 0, STEPS, HEIGHT);
display.setColor(WHITE);
// do the scan
for (x = 0; x < STEPS; x++) {
float freq = FREQ_BEGIN + (RANGE * ((float) x / STEPS));
radio.setFrequency(freq);
#ifdef PRINT_SCAN_VALUES
Serial.println();
Serial.print("step-");
Serial.print(x);
Serial.print(" Frequancy:");
Serial.print(freq);
Serial.println();
#endif
// start spectral scan
radio.spectralScanStart(SAMPLES, 1);
// wait for spectral scan to finish
while(radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) {
heltec_delay(1);
}
digitalWrite(25, HIGH);
// read the results Array to which the results will be saved
radio.spectralScanGetResult(result);
for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) {
#ifdef PRINT_SCAN_VALUES
Serial.printf("%04X,", result[y]);
#endif
if (result[y]) {
display.setPixel(x, y);
}
}
#ifdef PRINT_SCAN_VALUES
Serial.println();
#endif
// wait a little bit before the next scan, otherwise the SX1262 hangs
heltec_delay(4);
}
#ifdef PRINT_SCAN_VALUES
Serial.println();
#endif
display.display();
#ifdef PRINT_PROFILE_TIME
scan_time = millis() - start;
Serial.printf("Scan took %lld ms\n", scan_time);
#endif
}

11
test/README Normal file
View File

@@ -0,0 +1,11 @@
This directory is intended for PlatformIO Test Runner and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PlatformIO Unit Testing:
- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html