diff --git a/README.md b/README.md
index a52c95e..767c204 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
# Lora SA(Spectrum Analyzer)
-RF Spectrum Analyzer using Lora Radio
+
+## RF Spectrum Analyzer using Lora Radio
@@ -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 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:
+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
+
+
+
-Battery with Wire JT connector :
-https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ
+Battery with Wire JT connector :
+
+
+## 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
+
+
+
+or buy :
+
-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.
diff --git a/include/ui.h b/include/ui.h
index 776bc35..5fb9ca7 100644
--- a/include/ui.h
+++ b/include/ui.h
@@ -8,38 +8,35 @@
// #include
-// (optional) major and minor tickmarks at x MHz
+// (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
-//#define PRINT_DEBUG
+// #define PRINT_DEBUG
// Change spectrum plot values at once or by line
#define ANIMATED_RELOAD true
#define MAJOR_TICK_LENGTH 2
#define MINOR_TICK_LENGTH 1
-// WEIGHT of the x-asix line
+// WEIGHT of the x-axis line
#define X_AXIS_WEIGHT 1
#define STATUS_TEXT_TOP (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
-#define SCREAN_HEIGHT 64
-
-// publish functions
-extern void UI_Init(SSD1306Wire*);
-extern void UI_displayDecorate(int , int , bool );
-extern void UI_setLedFlag( bool);
+// 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_drawCurrsor(int16_t);
+extern void UI_drawCursor(int16_t);
#endif // __UI_H__
-
diff --git a/src/main.cpp b/src/main.cpp
index 27ac455..81f4462 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,7 +22,7 @@
*/
// Turns the 'PRG' button into the power button, long press is off
-// TODO add it to compiller options using -DHELTEC_POWER_BUTTON
+// TODO add it to compiler options using -DHELTEC_POWER_BUTTON
#define HELTEC_POWER_BUTTON // must be before "#include "
#include
@@ -30,25 +30,21 @@
// This file contains a binary patch for the SX1262
#include "modules/SX126x/patches/SX126x_patch_scan.h"
-
-// project components
+// project components
#include "global_config.h"
-#include "images.h"
#include "ui.h"
-
// -----------------------------------------------------------------
// CONFIGURATION OPTIONS
// -----------------------------------------------------------------
-
-
-typedef enum {
- METHOD_RSSI = 0u,
- METHOD_SPECTRAL
+typedef enum
+{
+ METHOD_RSSI = 0u,
+ METHOD_SPECTRAL
} TSCAN_METOD_ENUM;
-#define SCAN_METHOD METHOD_SPECTRAL
+#define SCAN_METHOD METHOD_SPECTRAL
// Feature to scan diapazones. Other frequency settings will be ignored.
int SCAN_RANGES[] = {};
@@ -72,7 +68,7 @@ unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN
// if more than 100 it can freez
#define SAMPLES 100 //(scan time = 1294)
// number of samples for RSSI method
-#define SAMPLES_RSSI 21//
+#define SAMPLES_RSSI 21 //
#define RANGE (int)(FREQ_END - FREQ_BEGIN)
@@ -89,8 +85,6 @@ unsigned int iterations = RANGE / RANGE_PER_PAGE;
// unsigned int range_frequency = FREQ_END - FREQ_BEGIN;
unsigned int median_frequency = FREQ_BEGIN + FREQ_END - FREQ_BEGIN / 2;
-
-
// #define OSD_ENABLED true // unused
// #define DISABLE_PLOT_CHART false // unused
@@ -99,7 +93,7 @@ uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
uint16_t filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE];
// Waterfall array
-bool waterfall[10][STEPS][10]; // 10 - ???
+bool waterfall[10][STEPS][10]; // 10 - ???
// global variable
// Used as a Led Light and Buzzer/count trigger
@@ -114,13 +108,12 @@ unsigned int detection_count = 0;
bool single_page_scan = false;
bool SOUND_ON = true;
-
unsigned int scan_time = 0;
unsigned int scan_start_time = 0;
uint64_t start = 0;
-unsigned int x, y, scan_iterration, w = 0;
+unsigned int x, y, scan_iteration, w = 0;
unsigned int ranges_count = 0;
float freq = 0;
@@ -130,510 +123,482 @@ int result_index = 0;
unsigned int button_pressed_counter = 0;
-
-void setup()
+void setup(void)
{
- pinMode(LED, OUTPUT);
- pinMode(BUZZER_PIN, OUTPUT);
- pinMode(REB_PIN, OUTPUT);
- heltec_setup();
+ float vbat;
+ float resolution;
- UI_Init(&display);
-
- for (int i = 0; i < 200; i++)
- {
- button.update();
- delay(10);
- if (button.pressed())
+ pinMode(LED, OUTPUT);
+ pinMode(BUZZER_PIN, OUTPUT);
+ pinMode(REB_PIN, OUTPUT);
+ heltec_setup();
+ UI_Init(&display);
+ for (int i = 0; i < 200; i++)
{
- SOUND_ON = false;
- tone(BUZZER_PIN, 205, 100);
- delay(50);
- tone(BUZZER_PIN, 205, 100);
- break;
+ button.update();
+ delay(10);
+ if (button.pressed())
+ {
+ SOUND_ON = false;
+ tone(BUZZER_PIN, 205, 100);
+ delay(50);
+ tone(BUZZER_PIN, 205, 100);
+ break;
+ }
}
- }
- // 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 scanning...");
- float vbat = heltec_vbat();
- both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat));
-
- delay(300);
- display.clear();
+ // initialize SX1262 FSK modem at the initial frequency
+ both.println("Init radio");
+ RADIOLIB_OR_HALT(radio.beginFSK(FREQ_BEGIN));
- float resolution = RANGE / STEPS;
- if (RANGE_PER_PAGE == range)
- {
- single_page_scan = true;
- }
- else
- {
- single_page_scan = false;
- }
+ // 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");
- // Adjust range if it is not even to RANGE_PER_PAGE
- if (!single_page_scan && range % RANGE_PER_PAGE != 0)
- {
- // range = range + range % RANGE_PER_PAGE;
- }
+ // 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
- if (single_page_scan)
- {
- both.println("Single Page Screen MODE");
- both.println("Multi Screen View Press P - button");
- both.println("Single Screen Resolution: " + String(resolution) + "Mhz/tick");
- both.println("Curent Resolution: " + String((float)RANGE_PER_PAGE / STEPS) + "Mhz/tick");
+ both.println("Setting up radio");
+ RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH));
- for (int i = 0; i < 500; i++)
+ // and disable the data shaping
+ RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE));
+ both.println("Starting scanning...");
+ vbat = heltec_vbat();
+ both.printf("V battery: %.2fV (%d%%)\n", vbat,
+ heltec_battery_percent(vbat));
+ delay(300);
+ display.clear();
+ resolution = RANGE / STEPS;
+ if (RANGE_PER_PAGE == range)
{
- button.update();
- delay(10);
- both.print(".");
- if (button.pressed())
- {
- RANGE_PER_PAGE = DEFAULT_RANGE_PER_PAGE;
- single_page_scan = false;
- tone(BUZZER_PIN, 205, 100);
- delay(50);
- tone(BUZZER_PIN, 205, 100);
- break;
- }
- }
- }
- else
- {
- both.println("Multi Page Screen MODE");
- both.println("Single screen View Press P - button");
- both.println("Single screen Resolution: " + String(resolution) + "Mhz/tick");
- both.println("Curent Resolution: " + String((float)RANGE_PER_PAGE / STEPS) + "Mhz/tick");
-
- for (int i = 0; i < 500; i++)
- {
- button.update();
- delay(10);
- both.print(".");
- if (button.pressed())
- {
- RANGE_PER_PAGE = range;
single_page_scan = true;
- tone(BUZZER_PIN, 205, 100);
-
- break;
- }
- }
- }
- display.clear();
-
- // waterfall start line y-axis
- w = WATERFALL_START;
-}
-
-void loop()
-{
- UI_displayDecorate(0,0,false); // some default values
- drone_detected = false;
- detection_count = 0;
- drone_detected_frequency_start = 0;
-#ifdef PRINT_PROFILE_TIME
- start = millis();
-#endif
-
- if (!ANIMATED_RELOAD || !single_page_scan)
- {
- // clear the scan plot rectangle
- UI_clearPlotter();
- }
-
- // do the scan
- range = FREQ_END - FREQ_BEGIN;
-
- if (RANGE_PER_PAGE > range)
- {
- RANGE_PER_PAGE = range;
- }
-
- fr_begin = FREQ_BEGIN;
- fr_end = fr_begin;
- // 50 is a single-screen range
- // TODO: Make 50 a variable with the option to show the full range
- iterations = range / RANGE_PER_PAGE;
-
- single_step = RANGE_PER_PAGE / 128;
- if (range % RANGE_PER_PAGE != 0)
- {
- // add more scan
- //++;
- }
-
- if (RANGE_PER_PAGE == range)
- {
- single_page_scan = true;
- }
- else
- {
- single_page_scan = false;
- }
-
- ranges_count = 0;
-
- for (int range : SCAN_RANGES)
- {
- ranges_count++;
- }
-
- if (ranges_count > 0)
- {
- iterations = ranges_count;
- single_page_scan = false;
- }
-
- // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz
- for (scan_iterration = 0; scan_iterration < iterations; scan_iterration++)
- {
- range = RANGE_PER_PAGE;
-
- if (ranges_count == 0)
- {
- fr_begin = (scan_iterration == 0) ? fr_begin : fr_begin += range;
- fr_end = fr_begin + RANGE_PER_PAGE;
}
else
{
- fr_begin = SCAN_RANGES[scan_iterration] / 1000;
- fr_end = SCAN_RANGES[scan_iterration] % 1000;
- range = fr_end - fr_begin;
+ single_page_scan = false;
}
+ // Adjust range if it is not even to RANGE_PER_PAGE
+ if (!single_page_scan && range % RANGE_PER_PAGE != 0)
+ {
+ // range = range + range % RANGE_PER_PAGE;
+ }
+ if (single_page_scan)
+ {
+ both.println("Single Page Screen MODE");
+ both.println("Multi Screen View Press P - button");
+ both.println("Single Screen Resolution: " + String(resolution) + "Mhz/tick");
+ both.println("Curent Resolution: " + String((float)RANGE_PER_PAGE / STEPS) + "Mhz/tick");
+ for (int i = 0; i < 500; i++)
+ {
+ button.update();
+ delay(10);
+ both.print(".");
+ if (button.pressed())
+ {
+ RANGE_PER_PAGE = DEFAULT_RANGE_PER_PAGE;
+ single_page_scan = false;
+ tone(BUZZER_PIN, 205, 100);
+ delay(50);
+ tone(BUZZER_PIN, 205, 100);
+ break;
+ }
+ }
+ }
+ else
+ {
+ both.println("Multi Page Screen MODE");
+ both.println("Single screen View Press P - button");
+ both.println("Single screen Resolution: " + String(resolution) + "Mhz/tick");
+ both.println("Curent Resolution: " + String((float)RANGE_PER_PAGE / STEPS) + "Mhz/tick");
+ for (int i = 0; i < 500; i++)
+ {
+ button.update();
+ delay(10);
+ both.print(".");
+ if (button.pressed())
+ {
+ RANGE_PER_PAGE = range;
+ single_page_scan = true;
+ tone(BUZZER_PIN, 205, 100);
+ break;
+ }
+ }
+ }
+ display.clear();
+ // waterfall start line y-axis
+ w = WATERFALL_START;
+}
+void loop(void)
+{
+ UI_displayDecorate(0, 0, false); // some default values
+ drone_detected = false;
+ detection_count = 0;
+ drone_detected_frequency_start = 0;
+#ifdef PRINT_PROFILE_TIME
+ start = millis();
+#endif
if (!ANIMATED_RELOAD || !single_page_scan)
{
- // clear the scan plot rectangle
- UI_clearPlotter();
+ // clear the scan plot rectangle
+ UI_clearPlotter();
}
-
- if (single_page_scan == false)
+ // do the scan
+ range = FREQ_END - FREQ_BEGIN;
+ if (RANGE_PER_PAGE > range)
{
- UI_displayDecorate(fr_begin, fr_end, true);
+ RANGE_PER_PAGE = range;
}
-
- drone_detected_frequency_start = 0;
-
- display.setTextAlignment(TEXT_ALIGN_RIGHT);
- // horizontal x axis loop
- for (x = 0; x < STEPS; x++)
+ fr_begin = FREQ_BEGIN;
+ fr_end = fr_begin;
+ // 50 is a single-screen range
+ // TODO: Make 50 a variable with the option to show the full range
+ iterations = range / RANGE_PER_PAGE;
+ single_step = RANGE_PER_PAGE / 128;
+ if (range % RANGE_PER_PAGE != 0)
{
- scan_start_time = millis();
-
-#if ANIMATED_RELOAD
- UI_drawCurrsor(x);
-#endif
-
- waterfall[scan_iterration][x][w] = false;
- freq = fr_begin + (range * ((float)x / STEPS));
- radio.setFrequency(freq);
- // TODO: RSSI METHOD
- // Gets RSSI (Recorded Signal Strength Indicator)
- // Restart continuous receive mode on the new frequency
- // state = radio.startReceive();
- // if (state == RADIOLIB_ERR_NONE) {
- // Serial.println(F("Started continuous receive mode"));
- //} else {
- // Serial.print(F("Failed to start receive mode, error code: "));
- // Serial.println(state);
- //}
- // rssi = radio.getRSSI(false);
- // Serial.println(String(rssi) + "db");
- // delay(25);
- // This code will iterate over the specified frequencies, changing the frequency every
- // second and printing the RSSI value for each frequency to the serial monitor. Adjust the frequencies array
- // to include the specific frequencies you're interested in monitoring.
- // A short delay after changing the frequency
- // ensures the module has time to stabilize and get an accurate RSSI reading.
-#ifdef PRINT_DEBUG
- Serial.println();
- Serial.print("step-");
- Serial.print(x);
- Serial.print(" Frequency:");
- Serial.print(freq);
- Serial.println();
-#endif
-
-
- // SpectralScan Method
-#if SCAN_METHOD == METHOD_SPECTRAL
- {
- // start spectral scan third parameter is a sleep interval
- radio.spectralScanStart(SAMPLES, 1);
- // wait for spectral scan to finish
- while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE)
+ // add more scan
+ //++;
+ }
+ if (RANGE_PER_PAGE == range)
+ {
+ single_page_scan = true;
+ }
+ else
+ {
+ single_page_scan = false;
+ }
+ ranges_count = 0;
+ for (int range : SCAN_RANGES)
+ {
+ ranges_count++;
+ }
+ if (ranges_count > 0)
+ {
+ iterations = ranges_count;
+ single_page_scan = false;
+ }
+ // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz
+ for (scan_iteration = 0; scan_iteration < iterations; scan_iteration++)
+ {
+ range = RANGE_PER_PAGE;
+ if (ranges_count == 0)
{
- Serial.print("radio.spectralScanGetStatus ERROR: ");
- Serial.println(radio.spectralScanGetStatus());
- heltec_delay(ONE_MILLISEC);
- }
- // read the results Array to which the results will be saved
- radio.spectralScanGetResult(result);
- }
-#endif
-
-#if SCAN_METHOD == METHOD_RSSI
- // Spectrum analyzer using getRSSI
- {
- state = radio.startReceive(0);
- if (state == RADIOLIB_ERR_NONE)
- {
-#ifdef PRINT_DEBUG
- Serial.println(F("Started continuous receive mode"));
-#endif
+ fr_begin = (scan_iteration == 0) ? fr_begin : fr_begin += range;
+ fr_end = fr_begin + RANGE_PER_PAGE;
}
else
{
- Serial.print(F("Failed to start receive mode, error code: "));
- Serial.println(state);
- }
-
- for (int r = 1; r < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; r++)
- {
- result[r] = 0;
- }
- result_index = 0;
- // N of samples
- for (int r = 1; r < SAMPLES_RSSI; r++)
- {
- rssi = radio.getRSSI(false);
- // delay(ONE_MILLISEC);
- // ToDO: check if 4 is correct value for 33 power bins
- result_index = (abs(rssi) / 4);
-
- // Debug Information
-#ifdef PRINT_DEBUG
- Serial.print("Frequency: ");
- Serial.println(freq);
- Serial.println(rssi);
- Serial.println(result_index);
-#endif
- // Saving max value only rss is negative so smaller is bigger
- if (result[result_index] > rssi)
- {
- result[result_index] = rssi;
- }
- }
- }
-#endif
-
-
- detected = false;
-#ifdef FILTER_SPECTRUM_RESULTS
- // Filter Elements without neighbors
- for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++)
- {
- // if RSSI method actual value is -xxx dB
- if (result[y] && (result[y + 1] != 0 || result[y - 1] != 0))
- {
- // Filling the empty pixel between signals int the level < 27 (noise level)
- /* if (y < 27 && result[y + 1] == 0 && result[y + 2] > 0)
- {
- result[y + 1] = 1;
- filtered_result[y + 1] = 1;
- }*/
- filtered_result[y] = 1;
- }
- else
- {
- filtered_result[y] = 0;
- }
- }
-#endif
- for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++)
- {
-#ifdef PRINT_DEBUG
- Serial.printf("%04X,", result[y]);
-#endif
- if (result[y] || y == drone_detection_level)
- {
- // check if we should alarm about a drone presence
- if (filtered_result[y] == 1 && y <= drone_detection_level)
- {
- drone_detected = true;
-#ifdef WATERFALL_ENABLED
- if (single_page_scan)
- {
- // Drone detection true for waterfall
- waterfall[scan_iterration][x][w] = true;
- display.setColor(WHITE);
- display.setPixel(x, w);
- }
-#endif
- if (drone_detected_frequency_start == 0)
- {
- drone_detected_frequency_start = freq;
- }
- drone_detected_frequency_end = freq;
-
- UI_setLedFlag(true);
-
- // If level is set to sensitive, start beeping every 10th frequency and shorter
- if (drone_detection_level <= 25)
- {
- if (detection_count == 1 && SOUND_ON)
- tone(BUZZER_PIN, 205, 10);
- if (detection_count % 5 == 0 && SOUND_ON)
- tone(BUZZER_PIN, 205, 10);
- }
- else
- {
- if (detection_count % 20 == 0 && SOUND_ON)
- tone(BUZZER_PIN, 205, 10);
- }
- display.setPixel(x, 1);
- display.setPixel(x, 2);
- display.setPixel(x, 3);
- display.setPixel(x, 4);
+ fr_begin = SCAN_RANGES[scan_iteration] / 1000;
+ fr_end = SCAN_RANGES[scan_iteration] % 1000;
+ range = fr_end - fr_begin;
}
-#ifdef WATERFALL_ENABLED
- if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[scan_iterration][x][w] != true)
+ if (!ANIMATED_RELOAD || !single_page_scan)
{
- // If drone not found set dark pixel on the waterfall
- // TODO: make something like scrolling up if possible
- waterfall[scan_iterration][x][w] = false;
- display.setColor(BLACK);
- display.setPixel(x, w);
- display.setColor(WHITE);
+ // clear the scan plot rectangle
+ UI_clearPlotter();
}
+
+ if (single_page_scan == false)
+ {
+ UI_displayDecorate(fr_begin, fr_end, true);
+ }
+
+ drone_detected_frequency_start = 0;
+ display.setTextAlignment(TEXT_ALIGN_RIGHT);
+
+ // horizontal x axis loop
+ for (x = 0; x < STEPS; x++)
+ {
+ scan_start_time = millis();
+
+#if ANIMATED_RELOAD
+ UI_drawCursor(x);
#endif
- if (filtered_result[y] == 1)
- {
- // Set signal level pixel
- display.setPixel(x, y);
- detected = true;
- }
-
- // Draw detection Level line evere 2 pixel
- if (y == drone_detection_level && x % 2 == 0)
- {
- display.setPixel(x, y);
- }
- }
-
+ waterfall[scan_iteration][x][w] = false;
+ freq = fr_begin + (range * ((float)x / STEPS));
+ radio.setFrequency(freq);
+ // TODO: RSSI METHOD
+ // Gets RSSI (Recorded Signal Strength Indicator)
+ // Restart continuous receive mode on the new frequency
+ // state = radio.startReceive();
+ // if (state == RADIOLIB_ERR_NONE) {
+ // Serial.println(F("Started continuous receive mode"));
+ //} else {
+ // Serial.print(F("Failed to start receive mode, error code: "));
+ // Serial.println(state);
+ //}
+ // rssi = radio.getRSSI(false);
+ // Serial.println(String(rssi) + "db");
+ // delay(25);
+ // This code will iterate over the specified frequencies,
+ // changing the frequency every
+ // second and printing the RSSI value for each frequency to the serial monitor. Adjust the frequencies array
+ // to include the specific frequencies you're interested in monitoring.
+ // A short delay after changing the frequency
+ // ensures the module has time to stabilize and get an accurate RSSI reading.
+#ifdef PRINT_DEBUG
+ Serial.println();
+ Serial.print("step-");
+ Serial.print(x);
+ Serial.print(" Frequency:");
+ Serial.print(freq);
+ Serial.println();
+#endif
+ // SpectralScan Method
+#if SCAN_METHOD == METHOD_SPECTRAL
+ {
+ // start spectral scan third parameter is a sleep interval
+ radio.spectralScanStart(SAMPLES, 1);
+ // wait for spectral scan to finish
+ while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE)
+ {
+ Serial.print("radio.spectralScanGetStatus ERROR: ");
+ Serial.println(radio.spectralScanGetStatus());
+ heltec_delay(ONE_MILLISEC);
+ }
+ // read the results Array to which the results will be saved
+ radio.spectralScanGetResult(result);
+ }
+#endif
+#if SCAN_METHOD == METHOD_RSSI
+ // Spectrum analyzer using getRSSI
+ {
+ state = radio.startReceive(0);
+ if (state == RADIOLIB_ERR_NONE)
+ {
+#ifdef PRINT_DEBUG
+ Serial.println(F("Started continuous receive mode"));
+#endif
+ }
+ else
+ {
+ Serial.print(F("Failed to start receive mode, error code: "));
+ Serial.println(state);
+ }
+ for (int r = 1; r < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; r++)
+ {
+ result[r] = 0;
+ }
+ result_index = 0;
+ // N of samples
+ for (int r = 1; r < SAMPLES_RSSI; r++)
+ {
+ rssi = radio.getRSSI(false);
+ // delay(ONE_MILLISEC);
+ // ToDO: check if 4 is correct value for 33 power bins
+ result_index = (abs(rssi) / 4);
+ // Debug Information
+#ifdef PRINT_DEBUG
+ Serial.print("Frequency: ");
+ Serial.println(freq);
+ Serial.println(rssi);
+ Serial.println(result_index);
+#endif
+ // Saving max value only rss is negative so smaller is bigger
+ if (result[result_index] > rssi)
+ {
+ result[result_index] = rssi;
+ }
+ }
+ }
+#endif
+ detected = false;
+#ifdef FILTER_SPECTRUM_RESULTS
+ // Filter Elements without neighbors
+ for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++)
+ {
+ // if RSSI method actual value is -xxx dB
+ if (result[y] && (result[y + 1] != 0 || result[y - 1] != 0))
+ {
+ // Filling the empty pixel between signals int the level < 27 (noise level)
+ /* if (y < 27 && result[y + 1] == 0 && result[y + 2] > 0)
+ {
+ result[y + 1] = 1;
+ filtered_result[y + 1] = 1;
+ }*/
+ filtered_result[y] = 1;
+ }
+ else
+ {
+ filtered_result[y] = 0;
+ }
+ }
+#endif
+ for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++)
+ {
+#ifdef PRINT_DEBUG
+ Serial.printf("%04X,", result[y]);
+#endif
+ if (result[y] || y == drone_detection_level)
+ {
+ // check if we should alarm about a drone presence
+ if (filtered_result[y] == 1 && y <= drone_detection_level)
+ {
+ drone_detected = true;
+#ifdef WATERFALL_ENABLED
+ if (single_page_scan)
+ {
+ // Drone detection true for waterfall
+ waterfall[scan_iteration][x][w] = true;
+ display.setColor(WHITE);
+ display.setPixel(x, w);
+ }
+#endif
+ if (drone_detected_frequency_start == 0)
+ {
+ drone_detected_frequency_start = freq;
+ }
+ drone_detected_frequency_end = freq;
+ UI_setLedFlag(true);
+ // If level is set to sensitive,
+ // start beeping every 10th frequency and shorter
+ if (drone_detection_level <= 25)
+ {
+ if (detection_count == 1 && SOUND_ON)
+ tone(BUZZER_PIN, 205, 10);
+ if (detection_count % 5 == 0 && SOUND_ON)
+ tone(BUZZER_PIN, 205, 10);
+ }
+ else
+ {
+ if (detection_count % 20 == 0 && SOUND_ON)
+ tone(BUZZER_PIN, 205, 10);
+ }
+ display.setPixel(x, 1);
+ display.setPixel(x, 2);
+ display.setPixel(x, 3);
+ display.setPixel(x, 4);
+ }
+#ifdef WATERFALL_ENABLED
+ if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[scan_iteration][x][w] != true)
+ {
+ // If drone not found set dark pixel on the waterfall
+ // TODO: make something like scrolling up if possible
+ waterfall[scan_iteration][x][w] = false;
+ display.setColor(BLACK);
+ display.setPixel(x, w);
+ display.setColor(WHITE);
+ }
+#endif
+ if (filtered_result[y] == 1)
+ {
+ // Set signal level pixel
+ display.setPixel(x, y);
+ detected = true;
+ }
+ // Draw detection Level line evere 2 pixel
+ if (y == drone_detection_level && x % 2 == 0)
+ {
+ display.setPixel(x, y);
+ }
+ }
#ifdef PRINT_PROFILE_TIME
- scan_time = millis() - scan_start_time;
- // Huge performance issue if enable
- // Serial.printf("Single Scan took %lld ms\n", scan_time);
+ scan_time = millis() - scan_start_time;
+ // Huge performance issue if enable
+ // Serial.printf("Single Scan took %lld ms\n", scan_time);
#endif
- }
- if (detected)
- {
- detection_count++;
- }
- detected = false;
+ }
+ if (detected)
+ {
+ detection_count++;
+ }
+ detected = false;
#ifdef PRINT_DEBUG
- Serial.println("....");
+ Serial.println("....");
#endif
- if (first_run || ANIMATED_RELOAD)
- {
- display.display();
- }
-
- // Detection level button short press
- if (button.pressedFor(100))
- {
- button.update();
- button_pressed_counter = 0;
- // if long press stop
- while (button.pressedNow())
- {
- delay(10);
- // Print Curent frequency
- display.setTextAlignment(TEXT_ALIGN_CENTER);
- display.drawString(128 / 2, 0, String(freq));
- display.display();
- button_pressed_counter++;
- if (button_pressed_counter > 150)
- {
- digitalWrite(LED, HIGH);
- delay(150);
- digitalWrite(LED, LOW);
+ if (first_run || ANIMATED_RELOAD)
+ {
+ display.display();
+ }
+ // Detection level button short press
+ if (button.pressedFor(100))
+ {
+ button.update();
+ button_pressed_counter = 0;
+ // if long press stop
+ while (button.pressedNow())
+ {
+ delay(10);
+ // Print Curent frequency
+ display.setTextAlignment(TEXT_ALIGN_CENTER);
+ display.drawString(128 / 2, 0, String(freq));
+ display.display();
+ button_pressed_counter++;
+ if (button_pressed_counter > 150)
+ {
+ digitalWrite(LED, HIGH);
+ delay(150);
+ digitalWrite(LED, LOW);
+ }
+ }
+ if (button_pressed_counter > 150)
+ {
+ // Remove Curent Freqancy Text
+ display.setTextAlignment(TEXT_ALIGN_CENTER);
+ display.setColor(BLACK);
+ display.drawString(128 / 2, 0, String(freq));
+ display.setColor(WHITE);
+ display.display();
+ break;
+ }
+ if (button_pressed_counter > 50 && button_pressed_counter < 150)
+ {
+ // Visually confirm it's off so user releases button
+ display.displayOff();
+ // Deep sleep (has wait for release so we don't wake up immediately)
+ heltec_deep_sleep();
+ break;
+ }
+ button.update();
+ display.setTextAlignment(TEXT_ALIGN_RIGHT);
+ // erase old value
+ display.setColor(BLACK);
+ display.fillRect(128 - 13, 0, 13, 13);
+ display.setColor(WHITE);
+ drone_detection_level++;
+ // print new value
+ display.drawString(128, 0, String(drone_detection_level));
+ tone(BUZZER_PIN, 104, 150);
+ if (drone_detection_level > 30)
+ {
+ drone_detection_level = 1;
+ }
+ }
+ // wait a little bit before the next scan,
+ // otherwise the SX1262 hangs
+ // Add more logic before insead of long delay...
+ // heltec_delay(1);
+ // Loop is needed if heltec_delay(1) not used
+ heltec_loop();
+ }
+ w++;
+ if (w > STATUS_TEXT_TOP + 1)
+ {
+ w = WATERFALL_START;
}
- }
- if (button_pressed_counter > 150)
- {
- // Remove Curent Freqancy Text
- display.setTextAlignment(TEXT_ALIGN_CENTER);
- display.setColor(BLACK);
- display.drawString(128 / 2, 0, String(freq));
- display.setColor(WHITE);
- display.display();
- break;
- }
- if (button_pressed_counter > 50 && button_pressed_counter < 150)
- {
- // Visually confirm it's off so user releases button
- display.displayOff();
- // Deep sleep (has wait for release so we don't wake up immediately)
- heltec_deep_sleep();
- break;
- }
- button.update();
-
- display.setTextAlignment(TEXT_ALIGN_RIGHT);
- // erase old value
- display.setColor(BLACK);
- display.fillRect(128 - 13, 0, 13, 13);
- display.setColor(WHITE);
- drone_detection_level++;
- // print new value
- display.drawString(128, 0, String(drone_detection_level));
-
- tone(BUZZER_PIN, 104, 150);
-
- if (drone_detection_level > 30)
- {
- drone_detection_level = 1;
- }
- }
- // wait a little bit before the next scan, otherwise the SX1262 hangs
- // Add more logic before insead of long delay...
- // heltec_delay(1);
- // Loop is needed if heltec_delay(1) not used
- heltec_loop();
- }
- w++;
- if (w > STATUS_TEXT_TOP + 1)
- {
- w = WATERFALL_START;
- }
#ifdef WATERFALL_ENABLED
- // Draw waterfall position cursor
- if (single_page_scan)
- {
- display.setColor(BLACK);
- display.drawHorizontalLine(0, w, STEPS);
- display.setColor(WHITE);
- }
+ // Draw waterfall position cursor
+ if (single_page_scan)
+ {
+ display.setColor(BLACK);
+ display.drawHorizontalLine(0, w, STEPS);
+ display.setColor(WHITE);
+ }
#endif
- display.display();
-}
-
+ display.display();
+ }
#ifdef PRINT_DEBUG
-Serial.println("----");
+ Serial.println("----");
#endif
// display.display();
#ifdef PRINT_PROFILE_TIME
-scan_time = millis() - start;
-Serial.printf("Scan took %lld ms\n", scan_time);
+ scan_time = millis() - start;
+ Serial.printf("Scan took %lld ms\n", scan_time);
#endif
}
diff --git a/src/ui.cpp b/src/ui.cpp
index a28ede3..7b1fd81 100644
--- a/src/ui.cpp
+++ b/src/ui.cpp
@@ -1,12 +1,10 @@
-
-
#include "ui.h"
#include "images.h"
#include "global_config.h"
#include "RadioLib.h"
// -------------------------------------------------
-// LCOAL DEFINES
+// LOCAL DEFINES
// Height of the plotter area
// -------------------------------------------------
@@ -14,16 +12,14 @@
//
#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;
-
-static SSD1306Wire *display_instance; //(0x3c, SDA_OLED, SCL_OLED, DISPLAY_GEOMETRY);
-// PrintSplitter both(Serial, display);
+//(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;
@@ -33,45 +29,43 @@ extern unsigned int detection_count;
extern bool SOUND_ON;
extern bool drone_detected;
extern unsigned int drone_detected_frequency_start;
-extern unsigned int drone_detected_frequency_end ;
+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 scan_iterration;
+extern unsigned int iterations;
+extern unsigned int scan_iteration;
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();
+ // 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)
+void UI_setLedFlag(bool new_status)
{
- led_flag = new_status;
+ led_flag = new_status;
}
-
void clearStatus(void)
{
- // clear status line
- display_instance->setColor(BLACK);
- display_instance->fillRect(0, STATUS_TEXT_TOP + 2, 128, 13);
- display_instance->setColor(WHITE);
+ // clear status line
+ display_instance->setColor(BLACK);
+ display_instance->fillRect(0, STATUS_TEXT_TOP + 2, 128, 13);
+ display_instance->setColor(WHITE);
}
void UI_clearPlotter(void)
{
- // clear the scan plot rectangle
- display_instance->setColor(BLACK);
- display_instance->fillRect(0, 0, STEPS, HEIGHT);
- display_instance->setColor(WHITE);
+ // clear the scan plot rectangle
+ display_instance->setColor(BLACK);
+ display_instance->fillRect(0, 0, STEPS, HEIGHT);
+ display_instance->setColor(WHITE);
}
/**
@@ -82,189 +76,193 @@ void UI_clearPlotter(void)
*/
void drawTicks(float every, int length)
{
- int first_tick = 0;
- //+ (every - (fr_begin - (int)(fr_begin / every) * every));
- /*if (first_tick < fr_begin)
- {
- first_tick += every;
- }*/
- bool correction = false;
- int pixels_per_step = STEPS / (RANGE_PER_PAGE / every);
- if (STEPS / RANGE_PER_PAGE != 0)
- {
- correction = true;
- }
+ int first_tick;
+ bool correction;
+ int pixels_per_step;
+ int correction_number;
+ int tick;
+ int tick_minor;
+ int median;
- int correction_number = STEPS - (int)(pixels_per_step * (RANGE_PER_PAGE / every));
- int tick = 0;
- int tick_minor = 0;
- int 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)
+ first_tick = 0;
+ //+ (every - (fr_begin - (int)(fr_begin / every) * every));
+ /*if (first_tick < fr_begin)
{
- // pixels_per_step++;
- correction_number--;
- }
-
- tick += pixels_per_step;
- tick_minor = tick / 2;
-
- if (tick <= 128 - 3)
+ first_tick += every;
+ }*/
+ correction = false;
+ pixels_per_step = STEPS / (RANGE_PER_PAGE / every);
+ if (STEPS / RANGE_PER_PAGE != 0)
{
- 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);
- }
+ 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);
- }
+ // 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_drawCurrsor(int16_t possition)
+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);
-
+ // 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, SCALE_TEXT_TOP, (begin == 0) ? String(FREQ_BEGIN) : String(begin));
-
- display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
- display_instance->drawString(128 / 2, SCALE_TEXT_TOP, (begin == 0) ? String(median_frequency) : String(begin + ((end - begin) / 2)));
-
- // Frequency end
- display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
- display_instance->drawString(128, SCALE_TEXT_TOP, (end == 0) ? String(FREQ_END) : String(end));
- }
-
- if (led_flag == true && detection_count >= 5)
- {
- digitalWrite(LED, HIGH);
- if (SOUND_ON)
+ if (!ui_initialized)
{
- tone(BUZZER_PIN, 104, 100);
+ // 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));
}
- digitalWrite(REB_PIN, HIGH);
- led_flag = false;
- }
-
- else if (!redraw)
- {
- digitalWrite(LED, LOW);
- }
- // Status text block
- if (!drone_detected)
- {
- // "Scanning"
- display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
- // clear status line
- clearStatus();
- if (scan_progress_count == 0)
+ if (!ui_initialized || redraw)
{
- display_instance->drawString(start_scan_text, STATUS_TEXT_TOP, "Scan. ");
+ // 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, SCALE_TEXT_TOP,
+ (begin == 0) ? String(FREQ_BEGIN) : String(begin));
+ display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
+ display_instance->drawString(128 / 2, SCALE_TEXT_TOP,
+ (begin == 0) ? String(median_frequency) : String(begin + ((end - begin) / 2)));
+ // Frequency end
+ display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
+ display_instance->drawString(128, SCALE_TEXT_TOP,
+ (end == 0) ? String(FREQ_END) : String(end));
}
- else if (scan_progress_count == 1)
+ if (led_flag == true && detection_count >= 5)
{
- display_instance->drawString(start_scan_text, STATUS_TEXT_TOP, "Scan.. ");
+ digitalWrite(LED, HIGH);
+ if (SOUND_ON)
+ {
+ tone(BUZZER_PIN, 104, 100);
+ }
+ digitalWrite(REB_PIN, HIGH);
+ led_flag = false;
}
- else if (scan_progress_count == 2)
+ else if (!redraw)
{
- display_instance->drawString(start_scan_text, STATUS_TEXT_TOP, "Scan...");
+ digitalWrite(LED, LOW);
}
- scan_progress_count++;
-
- if (scan_progress_count == 3)
+ // Status text block
+ if (!drone_detected)
{
- scan_progress_count = 0;
+ // "Scanning"
+ display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
+ // clear status line
+ clearStatus();
+ if (scan_progress_count == 0)
+ {
+ display_instance->drawString(start_scan_text, STATUS_TEXT_TOP,
+ "Scan. ");
+ }
+ else if (scan_progress_count == 1)
+ {
+ display_instance->drawString(start_scan_text, STATUS_TEXT_TOP,
+ "Scan.. ");
+ }
+ else if (scan_progress_count == 2)
+ {
+ display_instance->drawString(start_scan_text, STATUS_TEXT_TOP,
+ "Scan...");
+ }
+ scan_progress_count++;
+ if (scan_progress_count == 3)
+ {
+ scan_progress_count = 0;
+ }
}
- }
-
- if (drone_detected)
- {
- display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
- // clear status line
- clearStatus();
-
- display_instance->drawString(start_scan_text, STATUS_TEXT_TOP, String(drone_detected_frequency_start) + ">RF<" + String(drone_detected_frequency_end));
- }
-
- if (ranges_count == 0)
- {
- display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
- display_instance->drawString(0, STATUS_TEXT_TOP, String(FREQ_BEGIN));
-
- display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
- display_instance->drawString(128, STATUS_TEXT_TOP, String(FREQ_END));
- }
- else if (ranges_count > 0)
- {
- display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
- display_instance->drawString(0, STATUS_TEXT_TOP, String(SCAN_RANGES[scan_iterration] / 1000) + "-" + String(SCAN_RANGES[scan_iterration] % 1000));
- if (scan_iterration + 1 < iterations)
+ if (drone_detected)
{
- display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
- display_instance->drawString(128, STATUS_TEXT_TOP, String(SCAN_RANGES[scan_iterration + 1] / 1000) + "-" + String(SCAN_RANGES[scan_iterration + 1] % 1000));
+ display_instance->setTextAlignment(TEXT_ALIGN_CENTER);
+ // clear status line
+ clearStatus();
+ display_instance->drawString(start_scan_text, STATUS_TEXT_TOP,
+ String(drone_detected_frequency_start) + ">RF<" + String(drone_detected_frequency_end));
}
- }
-
- if (!ui_initialized)
- {
- // X-axis
- display_instance->fillRect(0, HEIGHT, STEPS, X_AXIS_WEIGHT);
+ if (ranges_count == 0)
+ {
+ display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
+ display_instance->drawString(0, STATUS_TEXT_TOP, String(FREQ_BEGIN));
+ display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
+ display_instance->drawString(128, STATUS_TEXT_TOP, String(FREQ_END));
+ }
+ else if (ranges_count > 0)
+ {
+ display_instance->setTextAlignment(TEXT_ALIGN_LEFT);
+ display_instance->drawString(0, STATUS_TEXT_TOP,
+ String(SCAN_RANGES[scan_iteration] / 1000) + "-" + String(SCAN_RANGES[scan_iteration] % 1000));
+ if (scan_iteration + 1 < iterations)
+ {
+ display_instance->setTextAlignment(TEXT_ALIGN_RIGHT);
+ display_instance->drawString(128, STATUS_TEXT_TOP,
+ String(SCAN_RANGES[scan_iteration + 1] / 1000) + "-" + String(SCAN_RANGES[scan_iteration + 1] % 1000));
+ }
+ }
+ if (!ui_initialized)
+ {
+ // X-axis
+ display_instance->fillRect(0, HEIGHT, STEPS, X_AXIS_WEIGHT);
// ticks
#ifdef MAJOR_TICKS
- drawTicks(MAJOR_TICKS, MAJOR_TICK_LENGTH);
+ drawTicks(MAJOR_TICKS, MAJOR_TICK_LENGTH);
#endif
- }
- ui_initialized = true;
+ }
+ ui_initialized = true;
}