mirror of
https://github.com/Genaker/LoraSA.git
synced 2026-08-04 16:03:09 +02:00
Vendored
+12
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"files.associations": {
|
||||
"images.h": "c",
|
||||
"*.tcc": "cpp",
|
||||
"deque": "cpp",
|
||||
"string": "cpp",
|
||||
"unordered_map": "cpp",
|
||||
"unordered_set": "cpp",
|
||||
"vector": "cpp",
|
||||
"system_error": "cpp"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
# Lora SA(Spectrum Analyzer)
|
||||
RF Spectrum Analyzer using Lora Radio
|
||||
|
||||
## RF Spectrum Analyzer using Lora Radio
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/4caeb467-1964-4184-ab20-ba68b97144aa" alt="LORA hardware" width="200"/>
|
||||
|
||||
@@ -10,46 +11,48 @@ The output is in the form of scan lines; each line has 33 power bins.
|
||||
The first power bin corresponds to -11 dBm, the second to -15 dBm, and so on.
|
||||
The higher number of samples in a bin corresponds to more power received
|
||||
at that level.
|
||||
```
|
||||
|
||||
```text
|
||||
N in Bin / dBm
|
||||
1 -11
|
||||
2 -15
|
||||
3 -19
|
||||
4 -23
|
||||
5 -27
|
||||
6 -31
|
||||
7 -35
|
||||
8 -39
|
||||
9 -43
|
||||
10 -47
|
||||
11 -51
|
||||
12 -55
|
||||
13 -59
|
||||
14 -63
|
||||
15 -67
|
||||
16 -71
|
||||
17 -75
|
||||
18 -79
|
||||
19 -83
|
||||
20 -87
|
||||
21 -91
|
||||
22 -95
|
||||
23 -99
|
||||
24 -103
|
||||
25 -107
|
||||
26 -111
|
||||
27 -115
|
||||
28 -119
|
||||
29 -123
|
||||
30 -127
|
||||
31 -131
|
||||
32 -135
|
||||
33 -139
|
||||
1 -11
|
||||
2 -15
|
||||
3 -19
|
||||
4 -23
|
||||
5 -27
|
||||
6 -31
|
||||
7 -35
|
||||
8 -39
|
||||
9 -43
|
||||
10 -47
|
||||
11 -51
|
||||
12 -55
|
||||
13 -59
|
||||
14 -63
|
||||
15 -67
|
||||
16 -71
|
||||
17 -75
|
||||
18 -79
|
||||
19 -83
|
||||
20 -87
|
||||
21 -91
|
||||
22 -95
|
||||
23 -99
|
||||
24 -103
|
||||
25 -107
|
||||
26 -111
|
||||
27 -115
|
||||
28 -119
|
||||
29 -123
|
||||
30 -127
|
||||
31 -131
|
||||
32 -135
|
||||
33 -139
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
step-13 Frequancy:816.25
|
||||
|
||||
```text
|
||||
step-13 Frequency:816.25
|
||||
Power Bins: 0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0000,0400, 0000,0000,0000,0000,0000,0000,0006,001B,000E,0005,0006,0002,0000
|
||||
```
|
||||
|
||||
@@ -57,47 +60,58 @@ The spectrum analyzer performs power measurements in the configured bandwidth.
|
||||
|
||||
The X-axis represents frequency in MHz, and the Y-axis displays actually received power.
|
||||
In the example above, the frequency span goes from 850 MHz to 950 MHz (that is a 100MHz range), and
|
||||
the visual amplitude goes from -11 dBm to -110(-139) according to the datasheet(High sensitivity: down to -148dBm) dBm.
|
||||
the visual amplitude goes from -11 dBm to -110(-139) according to the datasheet (High sensitivity: down to -148dBm) dBm.
|
||||
|
||||
To show the results in a plot, run the Python script
|
||||
RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py
|
||||
|
||||
# Features
|
||||
## Multiple Ranges Scan
|
||||
## Features
|
||||
|
||||
### Multiple Ranges Scan
|
||||
|
||||
Disabled By Default
|
||||
```
|
||||
|
||||
```c
|
||||
// Feature to scan diapazones. Other frequency settings will be ignored.
|
||||
int SCAN_DIAPAZONES[] = {};
|
||||
//int SCAN_DIAPAZONES[] = {850890, 920950};
|
||||
```
|
||||
To Enable Add/ uncomment an array of the frequencies
|
||||
```
|
||||
|
||||
To Enable Add/ uncomment an array of the frequencies
|
||||
|
||||
```c
|
||||
int SCAN_DIAPAZONES[] = {850890, 920950};
|
||||
```
|
||||
where 850890 stands for 950-890Mhz range
|
||||
920950 - 920-890Mhz
|
||||
Other settings will be ignored if **Multiple Ranges Scan** is enabled.
|
||||
|
||||
## Waterfall
|
||||
Waterfall showed only on One Page Scan
|
||||
to disable - uncomment this line
|
||||
```
|
||||
where 850890 stands for 950-890Mhz range
|
||||
920950 - 920-890Mhz
|
||||
Other settings will be ignored if **Multiple Ranges Scan** is enabled.
|
||||
|
||||
### Waterfall
|
||||
|
||||
Waterfall showed only on One Page Scan
|
||||
to disable - uncomment this line
|
||||
|
||||
```c
|
||||
#define WATERFALL_ENABLED true
|
||||
```
|
||||
Waterfall shows the last **N** = SCREAN_HEIGHT (64) - WATERFALL_START(37) - 8 (part of the STATUS_TEXT_TOP) = **19** signal detection that excited set signal level
|
||||
|
||||
## RSSI Method of scan
|
||||
By default, we are using the spectralScan method of the RadioLib Library: https://jgromes.github.io/RadioLib/class_s_x126x.html#a8a3ad4e12df862ab18b326d9dba26d66
|
||||
This method works only with Sx1262 modules.
|
||||
We implemented a scan using the **getRSSI** method, which has more flexibility and supports sx1276 and other modules.
|
||||
Using this method, we also receive the signal's **dB** values, not just the O-33 number.
|
||||
To enable this method, set the value of the **RSSI_METHOD** to true.
|
||||
Waterfall shows the last **N** = SCREEN_HEIGHT (64) - WATERFALL_START(37) - 8 (part of the ROW_STATUS_TEXT) = **19** signal detection that excited set signal level
|
||||
|
||||
### RSSI Method of scan
|
||||
|
||||
By default, we are using the spectralScan method of the RadioLib Library: <https://jgromes.github.io/RadioLib/class_s_x126x.html#a8a3ad4e12df862ab18b326d9dba26d66>
|
||||
This method works only with Sx1262 modules.
|
||||
We implemented a scan using the **getRSSI** method, which has more flexibility and supports sx1276 and other modules.
|
||||
Using this method, we also receive the signal's **dB** values, not just the O-33 number.
|
||||
To enable this method, set the value of the **RSSI_METHOD** to true.
|
||||
|
||||
### Multi Screen Scan
|
||||
|
||||
## Multi Screen Scan
|
||||
Single screen scan for now has **RANGE / 128** resolution.
|
||||
Multi-page scan can be adjusted to how many MHz per page you wanna scan
|
||||
Multi-page scan can be adjusted to how many MHz per page you wanna scan
|
||||
|
||||
```
|
||||
```c
|
||||
// frequency range in MHz to scan
|
||||
#define FREQ_BEGIN 850
|
||||
// TODO: if % RANGE_PER_PAGE != 0
|
||||
@@ -108,72 +122,81 @@ int SCAN_DIAPAZONES[] = {};
|
||||
// int SCAN_DIAPAZONES[] = {850890, 920950};
|
||||
|
||||
// MHZ per page
|
||||
//To put everething into one page set RANGE_PER_PAGE = FREQ_END - 800
|
||||
//To put everything into one page set RANGE_PER_PAGE = FREQ_END - 800
|
||||
unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN
|
||||
//To Enable Multi Screen scan
|
||||
// unsigned int RANGE_PER_PAGE = 50;
|
||||
// Default Range on Menu Button Switch
|
||||
#define DEFAULT_RANGE_PER_PAGE = 50;
|
||||
|
||||
```
|
||||
|
||||
To enable Multi-page by default set **RANGE_PER_PAGE** less than **FREQ_END - FREQ_BEGIN**;
|
||||
Switch to multi-page during regular One Screen application run. Restart the ESP32 on screen after the logo press the P button.
|
||||
Switch to multi-page during regular One Screen application run. Restart the ESP32 on screen after the logo press the P button.
|
||||
|
||||
## Mute Autio Notifications
|
||||
Restart ESP32, and on the logo display, press the P button.
|
||||
### Mute Audio Notifications
|
||||
|
||||
## Pause Execution
|
||||
Press P for more than 2 seconds. Execution will pause, and the scan's current Mhz position will be shown on the display.
|
||||
If less, ESP32 will turn off. Fast pressing(less than 0.5 second) P button changes the notification level
|
||||
Restart ESP32, and on the logo display, press the P button.
|
||||
|
||||
### Pause Execution
|
||||
|
||||
Press P for more than 2 seconds. Execution will pause, and the scan's current Mhz position will be shown on the display.
|
||||
If less, ESP32 will turn off. Fast pressing(less than 0.5 second) P button changes the notification level
|
||||
|
||||
## VSCode Platform.IO development env installation
|
||||
|
||||
# VSCode Platform.IO development env installation
|
||||
1. Install VSCode
|
||||
2. install Platfor.IO extension
|
||||
2. install Platform.IO extension
|
||||

|
||||
3. Connect ESP32 to USB. Install USB drivers for Windows
|
||||
4. Clone this Git Repo or download zip of the sources
|
||||

|
||||
```
|
||||
git clone https://github.com/Genaker/LoraSA.git
|
||||
```
|
||||
NOTE: in you case name will be Just LoraSA. I have LoraSA2 because I already have LoraSA folder
|
||||
6. Open the Project with the VS code Platform.IO
|
||||
|
||||
```bash
|
||||
git clone https://github.com/Genaker/LoraSA.git
|
||||
```
|
||||
|
||||
NOTE: in you case name will be Just LoraSA. I have LoraSA2 because I already have LoraSA folder
|
||||
|
||||
5. Open the Project with the VS code Platform.IO
|
||||

|
||||

|
||||
|
||||
7. Select Proper Environment
|
||||
6. Select Proper Environment
|
||||

|
||||
8. Select ESP32 USB Device to program
|
||||
7. Select ESP32 USB Device to program
|
||||

|
||||
Note: It is theoretically possible to program via WiFi and BTH.
|
||||
9. Programm your ESP32
|
||||
8. Program your ESP32
|
||||

|
||||
|
||||
10. Wait until you are done with the compilation and upload.
|
||||
Usually takes 1 minute. The first run is slower. It needs to compile all libraries.
|
||||
9. Wait until you are done with the compilation and upload.
|
||||
Usually takes 1 minute. The first run is slower. It needs to compile all libraries.
|
||||

|
||||
You will have the UCOG SA logo and spectrum analyzing scanning screen when done.
|
||||

|
||||
|
||||
# Hardware
|
||||
|
||||
## Hardware
|
||||
|
||||
Heltec ESP32 Lora V3:
|
||||
https://www.amazon.com/Heltec-Development-863-870MHz-ESP32-S3FN8-902-928MHz/dp/B0D1H1FN9Y/
|
||||
https://heltec.org/project/wifi-lora-32-v3/
|
||||
https://www.aliexpress.us/item/3256807037422978.html
|
||||
<https://www.amazon.com/Heltec-Development-863-870MHz-ESP32-S3FN8-902-928MHz/dp/B0D1H1FN9Y/>
|
||||
<https://heltec.org/project/wifi-lora-32-v3/>
|
||||
<https://www.aliexpress.us/item/3256807037422978.html>
|
||||
|
||||
Battery with Wire JT connector :
|
||||
https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ
|
||||
Battery with Wire JT connector :
|
||||
<https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ>
|
||||
|
||||
## 3D printed case
|
||||
|
||||
# 3D printed case
|
||||

|
||||
https://www.printables.com/model/118750-heltec-lora-32-case-for-meshtastic
|
||||
https://www.thingiverse.com/thing:3125854
|
||||
https://thangs.com/designer/Snake0017/3d-model/Heltec%20LoRa%2032%20Desktop%20%26%20Vehicle%20Enclosure-40844
|
||||
or buy :
|
||||
https://www.amazon.com/DIYmalls-ESP32-OLED-WiFi-Type-C/dp/B0BR3MQ9BG
|
||||
<https://www.printables.com/model/118750-heltec-lora-32-case-for-meshtastic>
|
||||
<https://www.thingiverse.com/thing:3125854>
|
||||
<https://thangs.com/designer/Snake0017/3d-model/Heltec%20LoRa%2032%20Desktop%20%26%20Vehicle%20Enclosure-40844>
|
||||
or buy :
|
||||
<https://www.amazon.com/DIYmalls-ESP32-OLED-WiFi-Type-C/dp/B0BR3MQ9BG>
|
||||
|
||||
https://www.thingiverse.com/thing:6522462
|
||||
<https://www.thingiverse.com/thing:6522462>
|
||||
|
||||
## Heltec ESP32 Lora v3 Pin Map
|
||||
|
||||
# Heltec ESP32 Lora v3 Pin Map
|
||||

|
||||
We are using pin 41 as a Buzzer trigger. Connect buzzer + leg with pin 41 and - leg with the ground (GND). You can change the buzzer pin in the code.
|
||||
We are using pin 41 as a Buzzer trigger. Connect buzzer + leg with pin 41 and - leg with the ground (GND). You can change the buzzer pin in the code.
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef __GLOBAL_CONFIG_H__
|
||||
#define __GLOBAL_CONFIG_H__
|
||||
|
||||
// frequency range in MHz to scan
|
||||
#define FREQ_BEGIN 850
|
||||
// TODO: if % RANGE_PER_PAGE != 0
|
||||
#define FREQ_END 950
|
||||
|
||||
// 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 467.0
|
||||
|
||||
// Detection level from the 33 levels. The higher number is more sensitive
|
||||
#define DEFAULT_DRONE_DETECTION_LEVEL 21
|
||||
|
||||
#define BUZZER_PIN 41
|
||||
|
||||
// REB trigger PIN
|
||||
#define REB_PIN 42
|
||||
|
||||
#define WATERFALL_ENABLED true
|
||||
#define WATERFALL_START 37
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
|
||||
#ifndef __IMAGES_H__
|
||||
#define __IMAGES_H__
|
||||
|
||||
// Array of all bitmaps for convenience. (Total bytes used to store images in PROGMEM = 1040)
|
||||
|
||||
extern const unsigned char epd_bitmap_ucog [];
|
||||
|
||||
#endif // __IMAGES_H__
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
#ifndef __UI_H__
|
||||
#define __UI_H__
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "SSD1306Wire.h"
|
||||
#include "OLEDDisplayUi.h"
|
||||
|
||||
// #include <heltec_unofficial.h>
|
||||
|
||||
// (optional) major and minor tick-marks at x MHz
|
||||
#define MAJOR_TICKS 10
|
||||
#define MINOR_TICKS 5
|
||||
|
||||
#define ONE_MILLISEC 1
|
||||
|
||||
// Prints debug information and the scan measurement bins from the SX1262 in hex
|
||||
// Change spectrum plot values at once or by line
|
||||
#define ANIMATED_RELOAD false
|
||||
|
||||
#define MAJOR_TICK_LENGTH 2
|
||||
#define MINOR_TICK_LENGTH 1
|
||||
// WEIGHT of the x-axis line
|
||||
#define X_AXIS_WEIGHT 1
|
||||
|
||||
#define ROW_STATUS_TEXT (64 - 10)
|
||||
|
||||
// The number of the spectrum screen lines = width of screen
|
||||
// Resolution of the scan is limited by 128-pixel screen
|
||||
#define STEPS 128
|
||||
|
||||
#define SCREEN_HEIGHT 64 // ???? not used
|
||||
|
||||
// publish functions
|
||||
extern void UI_Init(SSD1306Wire *);
|
||||
extern void UI_displayDecorate(int, int, bool);
|
||||
extern void UI_setLedFlag(bool);
|
||||
extern void UI_clearPlotter(void);
|
||||
extern void UI_drawCursor(int16_t);
|
||||
|
||||
#endif // __UI_H__
|
||||
+2
-2
@@ -15,5 +15,5 @@ framework = arduino
|
||||
upload_speed = 115200
|
||||
monitor_speed = 115200
|
||||
board_build.f_cpu = 240000000
|
||||
lib_deps =
|
||||
ropg/Heltec_ESP32_LoRa_v3@^0.9.1
|
||||
lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1
|
||||
build_flags = -DHELTEC_POWER_BUTTON
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
|
||||
#include "images.h"
|
||||
//'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 = {
|
||||
const unsigned char epd_bitmap_ucog[] = {
|
||||
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,
|
||||
@@ -95,7 +96,7 @@ const unsigned char epd_bitmap_ucog [] PROGMEM = {
|
||||
};
|
||||
|
||||
// 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
|
||||
};
|
||||
// const int epd_bitmap_allArray_LEN = 1;
|
||||
// const unsigned char* epd_bitmap_allArray[1] = {
|
||||
// epd_bitmap_ucog
|
||||
// };
|
||||
+540
-735
File diff suppressed because it is too large
Load Diff
+289
@@ -0,0 +1,289 @@
|
||||
#include "ui.h"
|
||||
#include "images.h"
|
||||
#include "global_config.h"
|
||||
#include "RadioLib.h"
|
||||
|
||||
// -------------------------------------------------
|
||||
// LOCAL DEFINES
|
||||
// Height of the plotter area
|
||||
// -------------------------------------------------
|
||||
|
||||
#define HEIGHT RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE
|
||||
//
|
||||
#define SCALE_TEXT_TOP (HEIGHT + X_AXIS_WEIGHT + MAJOR_TICK_LENGTH)
|
||||
|
||||
static unsigned int start_scan_text = (128 / 2) - 3;
|
||||
// initialized flag
|
||||
static bool ui_initialized = false;
|
||||
static bool led_flag = false;
|
||||
static unsigned short int scan_progress_count = 0;
|
||||
|
||||
//(0x3c, SDA_OLED, SCL_OLED, DISPLAY_GEOMETRY);
|
||||
static SSD1306Wire *display_instance;
|
||||
|
||||
// temporary dirty import ... to be solved durring upcoming refactoring
|
||||
extern unsigned int drone_detection_level;
|
||||
extern unsigned int RANGE_PER_PAGE;
|
||||
extern unsigned int median_frequency;
|
||||
extern unsigned int detection_count;
|
||||
extern bool SOUND_ON;
|
||||
extern unsigned int drone_detected_frequency_start;
|
||||
extern unsigned int drone_detected_frequency_end;
|
||||
extern unsigned int ranges_count;
|
||||
extern int SCAN_RANGES[];
|
||||
extern unsigned int ranges_count;
|
||||
extern unsigned int iterations;
|
||||
extern unsigned int range_item;
|
||||
|
||||
extern uint64_t loop_time;
|
||||
|
||||
|
||||
void UI_Init(SSD1306Wire *display_ptr)
|
||||
{
|
||||
// init pointer to display instance.
|
||||
display_instance = display_ptr;
|
||||
// check for null ???
|
||||
display_instance->clear();
|
||||
// draw the UCOG welcome logo
|
||||
display_instance->drawXbm(0, 2, 128, 64, epd_bitmap_ucog);
|
||||
display_instance->display();
|
||||
}
|
||||
|
||||
void UI_setLedFlag(bool new_status)
|
||||
{
|
||||
led_flag = new_status;
|
||||
}
|
||||
|
||||
void clearStatus(void)
|
||||
{
|
||||
// clear status line
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->fillRect(0, ROW_STATUS_TEXT + 2, 128, 13);
|
||||
display_instance->setColor(WHITE);
|
||||
}
|
||||
|
||||
void UI_clearPlotter(void)
|
||||
{
|
||||
// clear the scan plot rectangle (top part)
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->fillRect(0, 0, STEPS, HEIGHT);
|
||||
display_instance->setColor(WHITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
int first_tick;
|
||||
bool correction;
|
||||
int pixels_per_step;
|
||||
int correction_number;
|
||||
int tick;
|
||||
int tick_minor;
|
||||
int median;
|
||||
|
||||
first_tick = 0;
|
||||
//+ (every - (fr_begin - (int)(fr_begin / every) * every));
|
||||
/*if (first_tick < fr_begin)
|
||||
{
|
||||
first_tick += every;
|
||||
}*/
|
||||
correction = false;
|
||||
pixels_per_step = STEPS / (RANGE_PER_PAGE / every);
|
||||
if (STEPS / RANGE_PER_PAGE != 0)
|
||||
{
|
||||
correction = true;
|
||||
}
|
||||
correction_number = STEPS - (int)(pixels_per_step * (RANGE_PER_PAGE / every));
|
||||
tick = 0;
|
||||
tick_minor = 0;
|
||||
median = (RANGE_PER_PAGE / every) / 2;
|
||||
// TODO: (RANGE_PER_PAGE / every)
|
||||
// * 2 has twice extra steps we need to figureout correct logic or minor ticks is not showing to the end
|
||||
for (int t = 0; t <= (RANGE_PER_PAGE / every) * 2; t++)
|
||||
{
|
||||
// fix if pixels per step is not int and we have shift
|
||||
if (correction && t % 2 != 0 && correction_number > 1)
|
||||
{
|
||||
// pixels_per_step++;
|
||||
correction_number--;
|
||||
}
|
||||
tick += pixels_per_step;
|
||||
tick_minor = tick / 2;
|
||||
if (tick <= 128 - 3)
|
||||
{
|
||||
display_instance->drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick,
|
||||
HEIGHT + X_AXIS_WEIGHT + length);
|
||||
// Central tick
|
||||
if (tick > (128 / 2) - 3 && tick < (128 / 2) + 3)
|
||||
{
|
||||
display_instance->drawLine(tick + 1, HEIGHT + X_AXIS_WEIGHT,
|
||||
tick + 1, HEIGHT + X_AXIS_WEIGHT + length);
|
||||
}
|
||||
}
|
||||
#ifdef MINOR_TICKS
|
||||
// Fix two ticks together
|
||||
if ((tick_minor + 1 != tick) && (tick_minor - 1 != tick) && (tick_minor + 2 != tick) && (tick_minor - 2 != tick))
|
||||
{
|
||||
display_instance->drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT,
|
||||
tick_minor, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH);
|
||||
}
|
||||
// Central tick
|
||||
if (tick_minor > (128 / 2) - 3 && tick_minor < (128 / 2) + 3)
|
||||
{
|
||||
display_instance->drawLine(tick_minor + 1, HEIGHT + X_AXIS_WEIGHT,
|
||||
tick_minor + 1, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void UI_drawCursor(int16_t possition)
|
||||
{
|
||||
// Draw animated cursor on reload process
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->drawVerticalLine(possition, 0, HEIGHT);
|
||||
display_instance->drawVerticalLine(possition + 1, 0, HEIGHT);
|
||||
display_instance->setColor(WHITE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decorates the display: everything but the plot itself.
|
||||
*/
|
||||
void UI_displayDecorate(int begin = 0, int end = 0, bool redraw = false)
|
||||
{
|
||||
if (!ui_initialized)
|
||||
{
|
||||
// Start and end ticks
|
||||
display_instance->fillRect(0, HEIGHT + X_AXIS_WEIGHT, 2,
|
||||
MAJOR_TICK_LENGTH + 1);
|
||||
display_instance->fillRect(126, HEIGHT + X_AXIS_WEIGHT, 2,
|
||||
MAJOR_TICK_LENGTH + 1);
|
||||
// Drone detection level
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, 0, String(drone_detection_level));
|
||||
}
|
||||
if (!ui_initialized || redraw)
|
||||
{
|
||||
// Clear something
|
||||
display_instance->setColor(BLACK);
|
||||
display_instance->fillRect(0, SCALE_TEXT_TOP + 1, 128, 12);
|
||||
display_instance->setColor(WHITE);
|
||||
|
||||
// Drone detection level
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, 0, String(drone_detection_level));
|
||||
// Frequency start
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display_instance->drawString(0, ROW_STATUS_TEXT,
|
||||
(begin == 0) ? String(FREQ_BEGIN) : String(begin));
|
||||
|
||||
// Frequency detected
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
display_instance->drawString(128 / 2, ROW_STATUS_TEXT,
|
||||
(begin == 0) ? String(median_frequency) : String(begin + ((end - begin) / 2)));
|
||||
// Frequency end
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, ROW_STATUS_TEXT,
|
||||
(end == 0) ? String(FREQ_END) : String(end));
|
||||
}
|
||||
|
||||
// Status text block
|
||||
if (led_flag) // 'drone' detected
|
||||
{
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
// clear status line
|
||||
clearStatus();
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
|
||||
String(drone_detected_frequency_start) + ">RF<" + String(drone_detected_frequency_end));
|
||||
} else
|
||||
{
|
||||
// "Scanning"
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
|
||||
// clear status line
|
||||
clearStatus();
|
||||
if (scan_progress_count == 0)
|
||||
{
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
|
||||
"Scan \\");
|
||||
}
|
||||
else if (scan_progress_count == 1)
|
||||
{
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
|
||||
"Scan |");
|
||||
}
|
||||
else if (scan_progress_count == 2)
|
||||
{
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
|
||||
"Scan /");
|
||||
}
|
||||
else if (scan_progress_count == 3)
|
||||
{
|
||||
display_instance->drawString(start_scan_text, ROW_STATUS_TEXT,
|
||||
"Scan -");
|
||||
}
|
||||
scan_progress_count++;
|
||||
if (scan_progress_count >= 4)
|
||||
{
|
||||
scan_progress_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (led_flag == true && detection_count >= 5)
|
||||
{
|
||||
digitalWrite(LED, HIGH);
|
||||
if (SOUND_ON)
|
||||
{
|
||||
tone(BUZZER_PIN, 104, 100);
|
||||
}
|
||||
digitalWrite(REB_PIN, HIGH);
|
||||
led_flag = false;
|
||||
}
|
||||
else if (!redraw)
|
||||
{
|
||||
digitalWrite(LED, LOW);
|
||||
}
|
||||
|
||||
|
||||
if (ranges_count == 0)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display_instance->drawString(0, ROW_STATUS_TEXT,String(loop_time));
|
||||
#else
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display_instance->drawString(0, ROW_STATUS_TEXT, String(FREQ_BEGIN));
|
||||
|
||||
#endif
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, ROW_STATUS_TEXT, String(FREQ_END));
|
||||
|
||||
}
|
||||
else if (ranges_count > 0)
|
||||
{
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
|
||||
display_instance->drawString(0, ROW_STATUS_TEXT,
|
||||
String(SCAN_RANGES[range_item] / 1000) + "-" + String(SCAN_RANGES[range_item] % 1000));
|
||||
if (range_item + 1 < iterations)
|
||||
{
|
||||
display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
|
||||
display_instance->drawString(128, ROW_STATUS_TEXT,
|
||||
String(SCAN_RANGES[range_item + 1] / 1000) + "-" + String(SCAN_RANGES[range_item + 1] % 1000));
|
||||
}
|
||||
}
|
||||
if (ui_initialized == false)
|
||||
{
|
||||
// X-axis
|
||||
display_instance->fillRect(0, HEIGHT, STEPS, X_AXIS_WEIGHT);
|
||||
// ticks
|
||||
#ifdef MAJOR_TICKS
|
||||
drawTicks(MAJOR_TICKS, MAJOR_TICK_LENGTH);
|
||||
#endif
|
||||
}
|
||||
ui_initialized = true;
|
||||
}
|
||||
Reference in New Issue
Block a user