From 0a3344427c39f9b1e4ec7c2694651f856eb5af28 Mon Sep 17 00:00:00 2001 From: YehorShytikovWB <117676856+YehorShytikovWB@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:58:04 -0700 Subject: [PATCH 01/36] Update README.md --- README.md | 35 ++++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7091e31..9fc178d 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,41 @@ 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 +# VSCode Platform.IO development env installation +1. Install VSCode +2. install Platfor.IO extension + ![image](https://github.com/user-attachments/assets/00547068-6153-4c78-9f12-54981b013b06) +3. Connect ESP32 to USB. Install USB drivers for Windows +4. Clone this Git Repo or download zip of the sources + ![image](https://github.com/user-attachments/assets/971b6592-3b71-414c-971c-2ecd20f0f0b7) + ``` + 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 + ![image](https://github.com/user-attachments/assets/5066836b-32ac-4a24-ac03-b5f739a6a658) + ![image](https://github.com/user-attachments/assets/da14488d-7a4a-410e-b754-59598578016d) +7. Select Proper Environment + ![image](https://github.com/user-attachments/assets/a9c6557b-a387-4457-b59b-b3d7242d2826) +8. Select ESP32 USB Device to program +![image](https://github.com/user-attachments/assets/af76c4b1-7122-45e1-b26b-08b59e03ca3b) +Note: It is theoretically possible to program via WiFi and BTH. +9. Programm your ESP32 + ![image](https://github.com/user-attachments/assets/9e67afd8-0522-4a96-82dc-8e1cdb32add5) + +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. + ![image](https://github.com/user-attachments/assets/6796eb5d-6e3f-45bc-b88c-251499f1ad47) +You will have the UCOG SA logo and spectrum analyzing scanning screen when done. + # Hardware +Heltec ESP32 Lora V3: +https://www.amazon.com/Heltec-Development-863-870MHz-ESP32-S3FN8-902-928MHz/dp/B0D1H1FN9Y/ref=asc_df_B0D1H1FN9Y/?tag=hyprod-20&linkCode=df0&hvadid=692875362841&hvpos=&hvnetw=g&hvrand=5065402673437807142&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=9031318&hvtargid=pla-2281435177418&psc=1&mcid=00370fce72f93747a79b8b147a2aa8f1&hvocijid=5065402673437807142-B0D1H1FN9Y-&hvexpln=73&gad_source=1 +Battery with Wire JT connector : +https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ?psc=1&pd_rd_w=mU7Pe&content-id=amzn1.sym.3c1bdb31-a20d-42d0-a8cf-ddadf63cd1a8&pf_rd_p=3c1bdb31-a20d-42d0-a8cf-ddadf63cd1a8&pf_rd_r=55CKD999WT1GWQ396J0K&pd_rd_wg=3ydoN&pd_rd_r=715cbd78-a843-4972-a5d5-e26e2716b910&ref_=sspa_dk_detail_2 # 3D printed case +https://www.thingiverse.com/thing:3125854 +or buy : +https://www.amazon.com/DIYmalls-ESP32-OLED-WiFi-Type-C/dp/B0BR3MQ9BG From 0ca1f7958545eebbb2db2d3735578d92a01b9e93 Mon Sep 17 00:00:00 2001 From: YehorShytikovWB <117676856+YehorShytikovWB@users.noreply.github.com> Date: Mon, 22 Jul 2024 19:58:58 -0700 Subject: [PATCH 02/36] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 9fc178d..c220fa5 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ Note: It is theoretically possible to program via WiFi and BTH. Usually takes 1 minute. The first run is slower. It needs to compile all libraries. ![image](https://github.com/user-attachments/assets/6796eb5d-6e3f-45bc-b88c-251499f1ad47) You will have the UCOG SA logo and spectrum analyzing scanning screen when done. +![image](https://github.com/user-attachments/assets/f86ab32a-cab1-461e-ade9-7021136a0af7) + # Hardware Heltec ESP32 Lora V3: From acc09e44fb47f64cfedb70bf995c8f92affd45c9 Mon Sep 17 00:00:00 2001 From: YehorShytikovWB <117676856+YehorShytikovWB@users.noreply.github.com> Date: Tue, 23 Jul 2024 12:43:09 -0700 Subject: [PATCH 03/36] Update README.md --- README.md | 47 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index c220fa5..40655e4 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,51 @@ 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 +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. -The spectrum analyzer perform power measurements in the configured bandwidth. +# 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 + +The spectrum analyzer performs power measurements in the configured bandwidth. + +The X axis represents frequency in MHZ and Y axis display actual received power in 33 dBm. +In this 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) dBm. To show the results in a plot, run the Python script RadioLib/extras/SX126x_Spectrum_Scan/SpectrumScan.py From 6f83a274eb12704361f80fcf70ebe9cf0c84aa2b Mon Sep 17 00:00:00 2001 From: YehorShytikovWB <117676856+YehorShytikovWB@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:16:17 -0700 Subject: [PATCH 04/36] Update README.md --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 40655e4..3c4c41f 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,15 @@ at that level. 32 -135 33 -139 +Example: +step-13 Frequancy: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, + The spectrum analyzer performs power measurements in the configured bandwidth. -The X axis represents frequency in MHZ and Y axis display actual received power in 33 dBm. +The X axis represents frequency in MHZ and Y axis display actual received power. In this 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) 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 From 9ef9a2ea8600a68b456adf3bf44a5b167733cd6c Mon Sep 17 00:00:00 2001 From: YehorShytikovWB <117676856+YehorShytikovWB@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:18:19 -0700 Subject: [PATCH 05/36] Add central tick and frequency --- src/main.cpp | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0eab6e8..fb08dff 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,8 +22,11 @@ */ // frequency range in MHz to scan -#define FREQ_BEGIN 400.00 -#define FREQ_END 500.00 +#define FREQ_BEGIN 750 +#define FREQ_END 900 + +unsigned int range_freqancy = FREQ_END - FREQ_BEGIN; +unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // 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, @@ -32,7 +35,7 @@ // (optional) major and minor tickmarks at x MHz #define MAJOR_TICKS 10 -// #define MINOR_TICKS 5 +//#define MINOR_TICKS 4 // Turns the 'PRG' button into the power button, long press is off #define HELTEC_POWER_BUTTON // must be before "#include " @@ -109,15 +112,21 @@ void displayDecorate() { // frequencies display.setTextAlignment(TEXT_ALIGN_LEFT); display.drawString(0, SCALE_TEXT_TOP, String(FREQ_BEGIN)); + + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.drawString(128/2, SCALE_TEXT_TOP, String(median_freqancy)); + //Draw Central line + display.drawLine(128/2, HEIGHT + X_AXIS_WEIGHT, 128 / 2 , HEIGHT + X_AXIS_WEIGHT + 4); + display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(127, SCALE_TEXT_TOP, String(FREQ_END)); + display.drawString(128, SCALE_TEXT_TOP, String(FREQ_END)); } - if(led_flag == true){ - digitalWrite(35, HIGH); + if(led_flag == true) { + digitalWrite(LED, HIGH); led_flag = false; } else { - digitalWrite(35, LOW); + digitalWrite(LED, LOW); led_flag = true; } // Status text block @@ -157,7 +166,7 @@ void displayDecorate() { void setup() { - pinMode(35, OUTPUT); + pinMode(LED, OUTPUT); heltec_setup(); display.clear(); // draw the logo @@ -180,8 +189,8 @@ void setup() { 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); + both.printf("V battrry: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); + heltec_delay(100); display.clear(); displayDecorate(); @@ -230,7 +239,7 @@ void loop() { Serial.println(); #endif // wait a little bit before the next scan, otherwise the SX1262 hangs - heltec_delay(4); + heltec_delay(1); } #ifdef PRINT_SCAN_VALUES Serial.println(); From c90c4e4e3734644c24ac4751227729af24cdc90f Mon Sep 17 00:00:00 2001 From: YehorShytikovWB <117676856+YehorShytikovWB@users.noreply.github.com> Date: Tue, 23 Jul 2024 14:21:49 -0700 Subject: [PATCH 06/36] fix led issue --- src/main.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index fb08dff..3867690 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -224,7 +224,6 @@ void loop() { 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++) { From bcd4e525ea4c06cfe2a50532740a76f386f3b35b Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 23 Jul 2024 14:23:56 -0700 Subject: [PATCH 07/36] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3c4c41f..c44c8d3 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ 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. -# in Bin / dBm +N in Bin / dBm 1 -11 2 -15 3 -19 From 221c31dce21f34eaebac4235fab2d6af03519e80 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 23 Jul 2024 16:51:07 -0700 Subject: [PATCH 08/36] Animated Reload --- src/main.cpp | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3867690..ba21d84 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -49,11 +49,13 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // Prints the scan measurement bins from the SX1262 in hex #define PRINT_SCAN_VALUES #define PRINT_PROFILE_TIME +//Change spectrum plot values at once or by line +#define ANIMATED_RELOAD true // 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) +// Number of samples for each freqancy scan. Fewer samples = better temporal resolution. +#define SAMPLES 35 //(scan time = 1294) #define MAJOR_TICK_LENGTH 3 #define MINOR_TICK_LENGTH 1 #define X_AXIS_WEIGHT 2 @@ -71,6 +73,7 @@ unsigned short int scan_var = 0; // initialized flag bool initialized = false; bool led_flag = true; +bool first_run = false; // drone tetection flag unsigned short int drone_detected = 0; @@ -82,6 +85,8 @@ uint64_t start = 0; unsigned int x,y = 0; +float freq = 0; + /** * @brief Draws ticks on the display at regular whole intervals. @@ -201,14 +206,22 @@ void loop() { #ifdef PRINT_PROFILE_TIME start = millis(); #endif + + if (!ANIMATED_RELOAD) { // clear the scan plot rectangle - display.setColor(BLACK); - display.fillRect(0, 0, STEPS, HEIGHT); - display.setColor(WHITE); + 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)); + if (ANIMATED_RELOAD) { + display.setColor(BLACK); + display.drawVerticalLine(x, 0, HEIGHT); + display.setColor(WHITE); + } + freq = FREQ_BEGIN + (RANGE * ((float) x / STEPS)); radio.setFrequency(freq); #ifdef PRINT_SCAN_VALUES Serial.println(); @@ -237,6 +250,9 @@ void loop() { #ifdef PRINT_SCAN_VALUES Serial.println(); #endif + if (first_run || ANIMATED_RELOAD){ + display.display(); + } // wait a little bit before the next scan, otherwise the SX1262 hangs heltec_delay(1); } From 5401ed575c7feefe6809df30f2b7b60532db50b4 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 23 Jul 2024 23:56:07 -0700 Subject: [PATCH 09/36] Update README.md --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c44c8d3..762aabe 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,6 @@ Note: It is theoretically possible to program via WiFi and BTH. ![image](https://github.com/user-attachments/assets/6796eb5d-6e3f-45bc-b88c-251499f1ad47) You will have the UCOG SA logo and spectrum analyzing scanning screen when done. ![image](https://github.com/user-attachments/assets/f86ab32a-cab1-461e-ade9-7021136a0af7) - # Hardware Heltec ESP32 Lora V3: @@ -99,3 +98,7 @@ https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ https://www.thingiverse.com/thing:3125854 or buy : https://www.amazon.com/DIYmalls-ESP32-OLED-WiFi-Type-C/dp/B0BR3MQ9BG + +# Heltec ESP32 Lora v3 Pin Map +![image](https://github.com/user-attachments/assets/a1e00b51-5566-4ff5-98fe-67eaeb5bc81f) +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. From 9a43db394a49cc280e1b0bc69515bf9bbeba1132 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 24 Jul 2024 01:30:51 -0700 Subject: [PATCH 10/36] Drone detection and filter logic --- src/main.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 55 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ba21d84..76aed27 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,7 +55,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // numbers of the spectrum screan lines = width of screan #define STEPS 128 // Number of samples for each freqancy scan. Fewer samples = better temporal resolution. -#define SAMPLES 35 //(scan time = 1294) +#define SAMPLES 50 //(scan time = 1294) #define MAJOR_TICK_LENGTH 3 #define MINOR_TICK_LENGTH 1 #define X_AXIS_WEIGHT 2 @@ -66,16 +66,23 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define RANGE (float)(FREQ_END - FREQ_BEGIN) #define SINGLE_STEP (float)(RANGE / STEPS) +#define DRONE_DETECTION_LEVEL 20 + +#define BUZZZER_PIN 41 + // Array to store the scan results uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; // global variable unsigned short int scan_var = 0; // initialized flag bool initialized = false; -bool led_flag = true; +bool led_flag = false; bool first_run = false; // drone tetection flag -unsigned short int drone_detected = 0; +bool drone_detected = false; +unsigned int drone_detected_freqancy_start = 0; +unsigned int drone_detected_freqancy_end = 0; unsigned int start_scan_text = (128 / 2) - 3; @@ -87,7 +94,6 @@ unsigned int x,y = 0; float freq = 0; - /** * @brief Draws ticks on the display at regular whole intervals. * @@ -105,7 +111,6 @@ void drawTicks(float every, int length) { } } - /** * @brief Decorates the display: everything but the plot itself. */ @@ -117,6 +122,9 @@ void displayDecorate() { // frequencies display.setTextAlignment(TEXT_ALIGN_LEFT); display.drawString(0, SCALE_TEXT_TOP, String(FREQ_BEGIN)); + //drone detection level + display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.drawString(128, 0, String(DRONE_DETECTION_LEVEL)); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(128/2, SCALE_TEXT_TOP, String(median_freqancy)); @@ -129,10 +137,10 @@ void displayDecorate() { if(led_flag == true) { digitalWrite(LED, HIGH); + tone(BUZZZER_PIN, 104, 500); led_flag = false; } else { digitalWrite(LED, LOW); - led_flag = true; } // Status text block if (drone_detected == 0) { @@ -153,6 +161,16 @@ void displayDecorate() { } scan_var++; if (scan_var == 3) scan_var = 0; + } else { + display.setTextAlignment(TEXT_ALIGN_CENTER); + //clear status line + display.setColor(BLACK); + display.fillRect(0, STATUS_TEXT_TOP, 128, 16); + display.setColor(WHITE); + + display.drawString(start_scan_text, STATUS_TEXT_TOP, String(drone_detected_freqancy_start) + "->!UAV!<- " + String(drone_detected_freqancy_end)); + drone_detected_freqancy_start = 0; + drone_detected = 0; } if (!initialized) { @@ -172,6 +190,7 @@ void displayDecorate() { void setup() { pinMode(LED, OUTPUT); + pinMode(BUZZZER_PIN, OUTPUT); heltec_setup(); display.clear(); // draw the logo @@ -214,6 +233,10 @@ void loop() { display.setColor(WHITE); } + display.setTextAlignment(TEXT_ALIGN_RIGHT); + //drone detection level + display.drawString(128, 0, String(DRONE_DETECTION_LEVEL)); + // do the scan for (x = 0; x < STEPS; x++) { if (ANIMATED_RELOAD) { @@ -239,12 +262,36 @@ void loop() { } // read the results Array to which the results will be saved radio.spectralScanGetResult(result); + //Filter Elements without neabors + for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { + if(result[y] && (result[y + 1] > 0 || result[y - 1] > 0 )){ + filtered_result[y] = 1; + } else { + filtered_result[y] = 0; + } + } + 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); + if (result[y] || y == DRONE_DETECTION_LEVEL) { + // check if we shuld alarm the dron + if (filtered_result[y] == 1 && y <= DRONE_DETECTION_LEVEL) { + drone_detected = true; + if(drone_detected_freqancy_start == 0) { + drone_detected_freqancy_start = freq; + } + drone_detected_freqancy_end = freq; + led_flag = true; + tone(BUZZZER_PIN, 205, 10); + display.setPixel(x, 1); + display.setPixel(x, 2); + display.setPixel(x, 3); + } + if(filtered_result[y] == 1 || y == DRONE_DETECTION_LEVEL){ + display.setPixel(x, y); + } } } #ifdef PRINT_SCAN_VALUES From 58385a20e21fbf2326f85c1c29935fb7a25fa030 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 24 Jul 2024 01:31:43 -0700 Subject: [PATCH 11/36] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 762aabe..d4d4a40 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,7 @@ You will have the UCOG SA logo and spectrum analyzing scanning screen when done. # Hardware Heltec ESP32 Lora V3: https://www.amazon.com/Heltec-Development-863-870MHz-ESP32-S3FN8-902-928MHz/dp/B0D1H1FN9Y/ref=asc_df_B0D1H1FN9Y/?tag=hyprod-20&linkCode=df0&hvadid=692875362841&hvpos=&hvnetw=g&hvrand=5065402673437807142&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=9031318&hvtargid=pla-2281435177418&psc=1&mcid=00370fce72f93747a79b8b147a2aa8f1&hvocijid=5065402673437807142-B0D1H1FN9Y-&hvexpln=73&gad_source=1 + Battery with Wire JT connector : https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ?psc=1&pd_rd_w=mU7Pe&content-id=amzn1.sym.3c1bdb31-a20d-42d0-a8cf-ddadf63cd1a8&pf_rd_p=3c1bdb31-a20d-42d0-a8cf-ddadf63cd1a8&pf_rd_r=55CKD999WT1GWQ396J0K&pd_rd_wg=3ydoN&pd_rd_r=715cbd78-a843-4972-a5d5-e26e2716b910&ref_=sspa_dk_detail_2 From 05a8201dfca7f72f66f12bf9f84bdae59f1204e3 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 24 Jul 2024 09:38:21 -0700 Subject: [PATCH 12/36] dot line detection level --- src/main.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 76aed27..0ee82c9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -55,7 +55,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // numbers of the spectrum screan lines = width of screan #define STEPS 128 // Number of samples for each freqancy scan. Fewer samples = better temporal resolution. -#define SAMPLES 50 //(scan time = 1294) +#define SAMPLES 190 //(scan time = 1294) #define MAJOR_TICK_LENGTH 3 #define MINOR_TICK_LENGTH 1 #define X_AXIS_WEIGHT 2 @@ -194,7 +194,7 @@ void setup() { heltec_setup(); display.clear(); // draw the logo - display.drawXbm(0, 0, 128, 64, epd_bitmap_ucog); + display.drawXbm(0, 2, 128, 64, epd_bitmap_ucog); display.display(); heltec_delay(4000); // initialize SX1262 FSK modem at the initial frequency @@ -214,7 +214,7 @@ void setup() { both.println("Starting scaning..."); float vbat = heltec_vbat(); both.printf("V battrry: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); - heltec_delay(100); + heltec_delay(200); display.clear(); displayDecorate(); @@ -242,6 +242,7 @@ void loop() { if (ANIMATED_RELOAD) { display.setColor(BLACK); display.drawVerticalLine(x, 0, HEIGHT); + display.drawVerticalLine(x + 1, 0, HEIGHT); display.setColor(WHITE); } freq = FREQ_BEGIN + (RANGE * ((float) x / STEPS)); @@ -289,9 +290,14 @@ void loop() { display.setPixel(x, 2); display.setPixel(x, 3); } - if(filtered_result[y] == 1 || y == DRONE_DETECTION_LEVEL){ + if(filtered_result[y] == 1){ display.setPixel(x, y); } + + //Detection Level line + if(y == DRONE_DETECTION_LEVEL && x%2 == 0) { + display.setPixel(x, y); + } } } #ifdef PRINT_SCAN_VALUES From 2e8f6c740abcf36f101521ded59cebd3018b86df Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 24 Jul 2024 09:52:52 -0700 Subject: [PATCH 13/36] Update main.cpp --- src/main.cpp | 311 ++++++++++++++++++++++++++++----------------------- 1 file changed, 172 insertions(+), 139 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 0ee82c9..46018ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,24 +1,24 @@ - /** - RadioLib SX126x Spectrum Scan +/** + RadioLib SX126x Spectrum Scan - This code 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. + This code 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 + 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! + 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 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/ + For full API reference, see the GitHub Pages + https://jgromes.github.io/RadioLib/ */ // frequency range in MHz to scan @@ -31,14 +31,14 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // 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 +#define BANDWIDTH 93.8 // 467.0 // (optional) major and minor tickmarks at x MHz #define MAJOR_TICKS 10 -//#define MINOR_TICKS 4 +// #define MINOR_TICKS 4 -// Turns the 'PRG' button into the power button, long press is off -#define HELTEC_POWER_BUTTON // must be before "#include " +// Turns the 'PRG' button into the power button, long press is off +#define HELTEC_POWER_BUTTON // must be before "#include " #include #include #include @@ -49,10 +49,10 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // Prints the scan measurement bins from the SX1262 in hex #define PRINT_SCAN_VALUES #define PRINT_PROFILE_TIME -//Change spectrum plot values at once or by line +// Change spectrum plot values at once or by line #define ANIMATED_RELOAD true -// numbers of the spectrum screan lines = width of screan +// numbers of the spectrum screan lines = width of screan #define STEPS 128 // Number of samples for each freqancy scan. Fewer samples = better temporal resolution. #define SAMPLES 190 //(scan time = 1294) @@ -66,17 +66,19 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define RANGE (float)(FREQ_END - FREQ_BEGIN) #define SINGLE_STEP (float)(RANGE / STEPS) -#define DRONE_DETECTION_LEVEL 20 +// Detection level from the 33 levels +#define DRONE_DETECTION_LEVEL 19 #define BUZZZER_PIN 41 // Array to store the scan results uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; uint16_t filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; -// global variable +// global variable unsigned short int scan_var = 0; // initialized flag bool initialized = false; +// Used as a Led Light and Buzzer/sount trigger bool led_flag = false; bool first_run = false; // drone tetection flag @@ -90,22 +92,25 @@ unsigned int scan_time = 0; uint64_t start = 0; -unsigned int x,y = 0; +unsigned int x, y = 0; float freq = 0; /** * @brief Draws ticks on the display at regular whole intervals. - * - * @param every The interval between ticks in MHz. + * + * @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){ +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) { + 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); } @@ -114,81 +119,94 @@ void drawTicks(float every, int length) { /** * @brief Decorates the display: everything but the plot itself. */ -void displayDecorate() { - if (!initialized) { - // begining and end ticks +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)); - //drone detection level + // drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, 0, String(DRONE_DETECTION_LEVEL)); display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(128/2, SCALE_TEXT_TOP, String(median_freqancy)); - //Draw Central line - display.drawLine(128/2, HEIGHT + X_AXIS_WEIGHT, 128 / 2 , HEIGHT + X_AXIS_WEIGHT + 4); + display.drawString(128 / 2, SCALE_TEXT_TOP, String(median_freqancy)); + // Draw Central line + display.drawLine(128 / 2, HEIGHT + X_AXIS_WEIGHT, 128 / 2, HEIGHT + X_AXIS_WEIGHT + 4); display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, SCALE_TEXT_TOP, String(FREQ_END)); - } - - if(led_flag == true) { + } + + if (led_flag == true) + { digitalWrite(LED, HIGH); tone(BUZZZER_PIN, 104, 500); led_flag = false; - } else { + } + else + { digitalWrite(LED, LOW); } // 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; - } else { - display.setTextAlignment(TEXT_ALIGN_CENTER); - //clear status line - display.setColor(BLACK); - display.fillRect(0, STATUS_TEXT_TOP, 128, 16); - display.setColor(WHITE); - - display.drawString(start_scan_text, STATUS_TEXT_TOP, String(drone_detected_freqancy_start) + "->!UAV!<- " + String(drone_detected_freqancy_end)); - drone_detected_freqancy_start = 0; - drone_detected = 0; + 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; + } + else + { + display.setTextAlignment(TEXT_ALIGN_CENTER); + // clear status line + display.setColor(BLACK); + display.fillRect(0, STATUS_TEXT_TOP, 128, 16); + display.setColor(WHITE); - if (!initialized) { - // X-axis - display.fillRect(0, HEIGHT, STEPS, X_AXIS_WEIGHT); - // ticks - #ifdef MAJOR_TICKS + display.drawString(start_scan_text, STATUS_TEXT_TOP, String(drone_detected_freqancy_start) + ">!UAV!<" + String(drone_detected_freqancy_end)); + drone_detected_freqancy_start = 0; + drone_detected = 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 +#endif +#ifdef MINOR_TICKS drawTicks(MINOR_TICKS, MINOR_TICK_LENGTH); - #endif +#endif } initialized = true; } - -void setup() { +void setup() +{ pinMode(LED, OUTPUT); pinMode(BUZZZER_PIN, OUTPUT); heltec_setup(); @@ -213,75 +231,88 @@ void setup() { RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); both.println("Starting scaning..."); float vbat = heltec_vbat(); - both.printf("V battrry: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); - heltec_delay(200); - + both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); + heltec_delay(300); + display.clear(); displayDecorate(); } -void loop() { +void loop() +{ displayDecorate(); - #ifdef PRINT_PROFILE_TIME - start = millis(); - #endif +#ifdef PRINT_PROFILE_TIME + start = millis(); +#endif - if (!ANIMATED_RELOAD) { - // clear the scan plot rectangle + if (!ANIMATED_RELOAD) + { + // clear the scan plot rectangle display.setColor(BLACK); display.fillRect(0, 0, STEPS, HEIGHT); display.setColor(WHITE); } - display.setTextAlignment(TEXT_ALIGN_RIGHT); - //drone detection level - display.drawString(128, 0, String(DRONE_DETECTION_LEVEL)); + display.setTextAlignment(TEXT_ALIGN_RIGHT); + // drone detection level + display.drawString(128, 0, String(DRONE_DETECTION_LEVEL)); // do the scan - for (x = 0; x < STEPS; x++) { - if (ANIMATED_RELOAD) { - display.setColor(BLACK); - display.drawVerticalLine(x, 0, HEIGHT); - display.drawVerticalLine(x + 1, 0, HEIGHT); - display.setColor(WHITE); + for (x = 0; x < STEPS; x++) + { + if (ANIMATED_RELOAD) + { + display.setColor(BLACK); + display.drawVerticalLine(x, 0, HEIGHT); + display.drawVerticalLine(x + 1, 0, HEIGHT); + display.setColor(WHITE); } - freq = FREQ_BEGIN + (RANGE * ((float) x / STEPS)); + 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 +#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) { + while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) + { heltec_delay(1); } // read the results Array to which the results will be saved radio.spectralScanGetResult(result); - //Filter Elements without neabors - for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { - if(result[y] && (result[y + 1] > 0 || result[y - 1] > 0 )){ + // Filter Elements without neabors + for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { + if (result[y] && (result[y + 1] > 0 || result[y - 1] > 0)) + { filtered_result[y] = 1; - } else { + } + else + { filtered_result[y] = 0; } } - for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { - #ifdef PRINT_SCAN_VALUES - Serial.printf("%04X,", result[y]); - #endif - if (result[y] || y == DRONE_DETECTION_LEVEL) { + for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { +#ifdef PRINT_SCAN_VALUES + Serial.printf("%04X,", result[y]); +#endif + if (result[y] || y == DRONE_DETECTION_LEVEL) + { // check if we shuld alarm the dron - if (filtered_result[y] == 1 && y <= DRONE_DETECTION_LEVEL) { + if (filtered_result[y] == 1 && y <= DRONE_DETECTION_LEVEL) + { drone_detected = true; - if(drone_detected_freqancy_start == 0) { - drone_detected_freqancy_start = freq; + if (drone_detected_freqancy_start == 0) + { + drone_detected_freqancy_start = freq; } drone_detected_freqancy_end = freq; led_flag = true; @@ -290,32 +321,34 @@ void loop() { display.setPixel(x, 2); display.setPixel(x, 3); } - if(filtered_result[y] == 1){ - display.setPixel(x, y); - } + if (filtered_result[y] == 1) + { + display.setPixel(x, y); + } - //Detection Level line - if(y == DRONE_DETECTION_LEVEL && x%2 == 0) { - display.setPixel(x, y); - } + // Detection Level line + if (y == DRONE_DETECTION_LEVEL && x % 2 == 0) + { + display.setPixel(x, y); + } } } - #ifdef PRINT_SCAN_VALUES - Serial.println(); - #endif - if (first_run || ANIMATED_RELOAD){ +#ifdef PRINT_SCAN_VALUES + Serial.println(); +#endif + if (first_run || ANIMATED_RELOAD) + { display.display(); } // wait a little bit before the next scan, otherwise the SX1262 hangs heltec_delay(1); } - #ifdef PRINT_SCAN_VALUES - Serial.println(); - #endif +#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 +#ifdef PRINT_PROFILE_TIME + scan_time = millis() - start; + Serial.printf("Scan took %lld ms\n", scan_time); +#endif } - From 6f50f41b1551c3195f147fc79c927bb8e22357db Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 24 Jul 2024 10:03:34 -0700 Subject: [PATCH 14/36] Update README.md --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d4d4a40..7406cf1 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ NOTE: in you case name will be Just LoraSA. I have LoraSA2 because I already hav 7. Select Proper Environment ![image](https://github.com/user-attachments/assets/a9c6557b-a387-4457-b59b-b3d7242d2826) 8. Select ESP32 USB Device to program -![image](https://github.com/user-attachments/assets/af76c4b1-7122-45e1-b26b-08b59e03ca3b) + ![image](https://github.com/user-attachments/assets/af76c4b1-7122-45e1-b26b-08b59e03ca3b) Note: It is theoretically possible to program via WiFi and BTH. 9. Programm your ESP32 ![image](https://github.com/user-attachments/assets/9e67afd8-0522-4a96-82dc-8e1cdb32add5) @@ -90,13 +90,18 @@ You will have the UCOG SA logo and spectrum analyzing scanning screen when done. # Hardware Heltec ESP32 Lora V3: -https://www.amazon.com/Heltec-Development-863-870MHz-ESP32-S3FN8-902-928MHz/dp/B0D1H1FN9Y/ref=asc_df_B0D1H1FN9Y/?tag=hyprod-20&linkCode=df0&hvadid=692875362841&hvpos=&hvnetw=g&hvrand=5065402673437807142&hvpone=&hvptwo=&hvqmt=&hvdev=c&hvdvcmdl=&hvlocint=&hvlocphy=9031318&hvtargid=pla-2281435177418&psc=1&mcid=00370fce72f93747a79b8b147a2aa8f1&hvocijid=5065402673437807142-B0D1H1FN9Y-&hvexpln=73&gad_source=1 +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?psc=1&pd_rd_w=mU7Pe&content-id=amzn1.sym.3c1bdb31-a20d-42d0-a8cf-ddadf63cd1a8&pf_rd_p=3c1bdb31-a20d-42d0-a8cf-ddadf63cd1a8&pf_rd_r=55CKD999WT1GWQ396J0K&pd_rd_wg=3ydoN&pd_rd_r=715cbd78-a843-4972-a5d5-e26e2716b910&ref_=sspa_dk_detail_2 +https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ # 3D printed case +![image](https://github.com/user-attachments/assets/52ae4e90-5f25-4d72-888e-7586bef9df69) +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 From ec585215f6ddb994ff79ce279f6036b63245eb57 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Thu, 25 Jul 2024 09:43:10 -0700 Subject: [PATCH 15/36] Fix button delay and level draw --- src/main.cpp | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 46018ee..023fdb0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,7 +22,7 @@ */ // frequency range in MHz to scan -#define FREQ_BEGIN 750 +#define FREQ_BEGIN 820 #define FREQ_END 900 unsigned int range_freqancy = FREQ_END - FREQ_BEGIN; @@ -66,8 +66,8 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define RANGE (float)(FREQ_END - FREQ_BEGIN) #define SINGLE_STEP (float)(RANGE / STEPS) -// Detection level from the 33 levels -#define DRONE_DETECTION_LEVEL 19 +// Detection level from the 33 levels. Higher number is more sensative +#define DRONE_DETECTION_LEVEL 21 #define BUZZZER_PIN 41 @@ -83,12 +83,14 @@ bool led_flag = false; bool first_run = false; // drone tetection flag bool drone_detected = false; +unsigned int drone_detection_level = DRONE_DETECTION_LEVEL; unsigned int drone_detected_freqancy_start = 0; unsigned int drone_detected_freqancy_end = 0; unsigned int start_scan_text = (128 / 2) - 3; unsigned int scan_time = 0; +unsigned int scan_start_time = 0; uint64_t start = 0; @@ -131,7 +133,7 @@ void displayDecorate() display.drawString(0, SCALE_TEXT_TOP, String(FREQ_BEGIN)); // drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(128, 0, String(DRONE_DETECTION_LEVEL)); + display.drawString(128, 0, String(drone_detection_level)); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(128 / 2, SCALE_TEXT_TOP, String(median_freqancy)); @@ -214,7 +216,7 @@ void setup() // draw the logo display.drawXbm(0, 2, 128, 64, epd_bitmap_ucog); display.display(); - heltec_delay(4000); + delay(4000); // initialize SX1262 FSK modem at the initial frequency both.println("Init radio"); RADIOLIB_OR_HALT(radio.beginFSK(FREQ_BEGIN)); @@ -232,7 +234,7 @@ void setup() both.println("Starting scaning..."); float vbat = heltec_vbat(); both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); - heltec_delay(300); + delay(300); display.clear(); displayDecorate(); @@ -255,7 +257,7 @@ void loop() display.setTextAlignment(TEXT_ALIGN_RIGHT); // drone detection level - display.drawString(128, 0, String(DRONE_DETECTION_LEVEL)); + display.drawString(128, 0, String(drone_detection_level)); // do the scan for (x = 0; x < STEPS; x++) @@ -277,6 +279,8 @@ void loop() Serial.print(freq); Serial.println(); #endif + +scan_start_time = millis(); // start spectral scan radio.spectralScanStart(SAMPLES, 1); // wait for spectral scan to finish @@ -304,10 +308,10 @@ void loop() #ifdef PRINT_SCAN_VALUES Serial.printf("%04X,", result[y]); #endif - if (result[y] || y == DRONE_DETECTION_LEVEL) + if (result[y] || y == drone_detection_level) { // check if we shuld alarm the dron - if (filtered_result[y] == 1 && y <= DRONE_DETECTION_LEVEL) + if (filtered_result[y] == 1 && y <= drone_detection_level) { drone_detected = true; if (drone_detected_freqancy_start == 0) @@ -320,6 +324,7 @@ void loop() display.setPixel(x, 1); display.setPixel(x, 2); display.setPixel(x, 3); + display.setPixel(x, 4); } if (filtered_result[y] == 1) { @@ -327,7 +332,7 @@ void loop() } // Detection Level line - if (y == DRONE_DETECTION_LEVEL && x % 2 == 0) + if (y == drone_detection_level && x % 2 == 0) { display.setPixel(x, y); } @@ -340,8 +345,29 @@ void loop() { display.display(); } + + // Detection level button short press + if (button.pressedFor(100)) { + display.setTextAlignment(TEXT_ALIGN_RIGHT); + // erase old value + display.setColor(BLACK); + display.fillRect(128-12, 0, 12, 12); + display.setColor(WHITE); + drone_detection_level++; + // print new value + display.drawString(128, 0, String(drone_detection_level)); + if (drone_detection_level > 30) { + drone_detection_level = 0; + } + } // wait a little bit before the next scan, otherwise the SX1262 hangs heltec_delay(1); + +#ifdef PRINT_PROFILE_TIME + scan_time = millis() - scan_start_time; + Serial.printf("Single Scan took %lld ms\n", scan_time); +#endif + } #ifdef PRINT_SCAN_VALUES Serial.println(); From 269a4dc8b5617bb9c46f64a21c27ff5c325d218b Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Thu, 25 Jul 2024 09:57:22 -0700 Subject: [PATCH 16/36] Update main.cpp --- src/main.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 023fdb0..18ca352 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -67,7 +67,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define SINGLE_STEP (float)(RANGE / STEPS) // Detection level from the 33 levels. Higher number is more sensative -#define DRONE_DETECTION_LEVEL 21 +#define DEFAULT_DRONE_DETECTION_LEVEL 21 #define BUZZZER_PIN 41 @@ -83,7 +83,7 @@ bool led_flag = false; bool first_run = false; // drone tetection flag bool drone_detected = false; -unsigned int drone_detection_level = DRONE_DETECTION_LEVEL; +unsigned int drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; unsigned int drone_detected_freqancy_start = 0; unsigned int drone_detected_freqancy_end = 0; @@ -147,7 +147,7 @@ void displayDecorate() if (led_flag == true) { digitalWrite(LED, HIGH); - tone(BUZZZER_PIN, 104, 500); + tone(BUZZZER_PIN, 104, 250); led_flag = false; } else @@ -320,7 +320,14 @@ scan_start_time = millis(); } drone_detected_freqancy_end = freq; led_flag = true; - tone(BUZZZER_PIN, 205, 10); + //if level to sensetive doing beep every 10th freaqancy and shorter + //TODO: make every 10th detection... + if (drone_detection_level < 25){ + tone(BUZZZER_PIN, 205, 10); + } else { + if (x % 10 == 0) + tone(BUZZZER_PIN, 205, 5); + } display.setPixel(x, 1); display.setPixel(x, 2); display.setPixel(x, 3); @@ -351,13 +358,13 @@ scan_start_time = millis(); display.setTextAlignment(TEXT_ALIGN_RIGHT); // erase old value display.setColor(BLACK); - display.fillRect(128-12, 0, 12, 12); + display.fillRect(128-13, 0, 13, 13); display.setColor(WHITE); drone_detection_level++; // print new value display.drawString(128, 0, String(drone_detection_level)); if (drone_detection_level > 30) { - drone_detection_level = 0; + drone_detection_level = 1; } } // wait a little bit before the next scan, otherwise the SX1262 hangs From 68d669af44eeecee03ef084c349ed3b55b4a6d7f Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 30 Jul 2024 08:23:30 -0700 Subject: [PATCH 18/36] add waterfall --- src/main.cpp | 579 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 413 insertions(+), 166 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 18ca352..5ce0050 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,8 +22,31 @@ */ // frequency range in MHz to scan -#define FREQ_BEGIN 820 -#define FREQ_END 900 +#define FREQ_BEGIN 860 +// TODO: if % RANGE_PER_PAGE 1= 0 +#define FREQ_END 960 + +#define UP_FILTER = 5; +#define LOW_FILTER = 3; + +// numbers of the spectrum screen lines = width of screen +#define STEPS 128 +// Number of samples for each frequency scan. Fewer samples = better temporal resolution. +#define SAMPLES 60 //(scan time = 1294) + +#define RANGE (int)(FREQ_END - FREQ_BEGIN) +// MHZ per page +// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 +unsigned int RANGE_PER_PAGE = 100; +#define SINGLE_STEP (float)(RANGE / STEPS) + +unsigned int single_step = SINGLE_STEP; + +unsigned int range = (int)(FREQ_END - FREQ_BEGIN); +unsigned int fr_begin = FREQ_BEGIN; +unsigned int fr_end = FREQ_BEGIN; + +unsigned int iterations = RANGE / RANGE_PER_PAGE; unsigned int range_freqancy = FREQ_END - FREQ_BEGIN; unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; @@ -35,7 +58,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // (optional) major and minor tickmarks at x MHz #define MAJOR_TICKS 10 -// #define MINOR_TICKS 4 +#define MINOR_TICKS 5 // Turns the 'PRG' button into the power button, long press is off #define HELTEC_POWER_BUTTON // must be before "#include " @@ -52,28 +75,31 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // Change spectrum plot values at once or by line #define ANIMATED_RELOAD true -// numbers of the spectrum screan lines = width of screan -#define STEPS 128 -// Number of samples for each freqancy scan. Fewer samples = better temporal resolution. -#define SAMPLES 190 //(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) +#define STATUS_TEXT_TOP (64 - 10) // Detection level from the 33 levels. Higher number is more sensative #define DEFAULT_DRONE_DETECTION_LEVEL 21 #define BUZZZER_PIN 41 +// REB trigger PIN +#define REB_PIN 42 + +#define WATERFALL_START 39 + +#define DISABLE_PLOT_CHART false // Array to store the scan results 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]; // global variable unsigned short int scan_var = 0; // initialized flag @@ -86,6 +112,8 @@ bool drone_detected = false; unsigned int drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; unsigned int drone_detected_freqancy_start = 0; unsigned int drone_detected_freqancy_end = 0; +unsigned int detection_count = 0; +bool single_page_scan = false; unsigned int start_scan_text = (128 / 2) - 3; @@ -94,10 +122,26 @@ unsigned int scan_start_time = 0; uint64_t start = 0; -unsigned int x, y = 0; +unsigned int x, y, i, w = 0; float freq = 0; +void clearStatus() +{ + // clear status line + display.setColor(BLACK); + display.fillRect(0, STATUS_TEXT_TOP + 2, 128, 13); + display.setColor(WHITE); +} + +void clearPloter() +{ + // clear the scan plot rectangle + display.setColor(BLACK); + display.fillRect(0, 0, STEPS, HEIGHT); + display.setColor(WHITE); +} + /** * @brief Draws ticks on the display at regular whole intervals. * @@ -106,92 +150,149 @@ float freq = 0; */ void drawTicks(float every, int length) { - float first_tick = FREQ_BEGIN + (every - (FREQ_BEGIN - (int)(FREQ_BEGIN / every) * every)); - if (first_tick < FREQ_BEGIN) + int first_tick = 0; + //+ (every - (fr_begin - (int)(fr_begin / every) * every)); + /*if (first_tick < fr_begin) { first_tick += every; - } - for (float tick_freq = first_tick; tick_freq <= FREQ_END; tick_freq += every) + }*/ + bool correction = false; + int pixels_per_step = STEPS / (RANGE_PER_PAGE / every); + if (STEPS / RANGE_PER_PAGE != 0) { - int tick = round((tick_freq - FREQ_BEGIN) / SINGLE_STEP); - display.drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick, HEIGHT + X_AXIS_WEIGHT + length); + correction = true; } + 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; + for (int t = 0; t <= (RANGE_PER_PAGE / every) + 1; 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; + Serial.print("tick:"); + Serial.print(tick); + Serial.print("\n"); + + tick_minor = tick - pixels_per_step / 2; + Serial.print("tick_minor:"); + Serial.print(tick_minor); + Serial.print("\n"); + + // Fix double tick at the end ... + if (tick < 128 - 3) + display.drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick, HEIGHT + X_AXIS_WEIGHT + length); + +#ifdef MINOR_TICKS + // Fix two ticks togather + // if(tick_minor + 1 != tick && tick_minor - 1 != tick && tick_minor + 2 != tick && tick_minor - 2 != tick) { + display.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, HEIGHT + X_AXIS_WEIGHT + 2); +//} +#endif + } + + // Draw Central Tick + // display.drawLine(128/2, HEIGHT + X_AXIS_WEIGHT, 128/2, HEIGHT + X_AXIS_WEIGHT + 5); } /** * @brief Decorates the display: everything but the plot itself. */ -void displayDecorate() +void displayDecorate(int begin = 0, int end = 0, bool redraw = false) { 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)); + + // drone detection level + display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.drawString(128, 0, String(drone_detection_level)); + } + + if (!initialized || redraw) + { + // Clear something + display.setColor(BLACK); + display.fillRect(0, SCALE_TEXT_TOP + 1, 128, 12); + display.setColor(WHITE); + // drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, 0, String(drone_detection_level)); - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(128 / 2, SCALE_TEXT_TOP, String(median_freqancy)); - // Draw Central line - display.drawLine(128 / 2, HEIGHT + X_AXIS_WEIGHT, 128 / 2, HEIGHT + X_AXIS_WEIGHT + 4); + // frequency start + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.drawString(0, SCALE_TEXT_TOP, (begin == 0) ? String(FREQ_BEGIN) : String(begin)); + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.drawString(128 / 2, SCALE_TEXT_TOP, (begin == 0) ? String(median_freqancy) : String(begin + ((end - begin) / 2))); + + // frequency end display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(128, SCALE_TEXT_TOP, String(FREQ_END)); + display.drawString(128, SCALE_TEXT_TOP, (end == 0) ? String(FREQ_END) : String(end)); } if (led_flag == true) { digitalWrite(LED, HIGH); tone(BUZZZER_PIN, 104, 250); + digitalWrite(REB_PIN, HIGH); led_flag = false; } - else + + else if (!redraw) { digitalWrite(LED, LOW); } // Status text block - if (drone_detected == 0) + if (!drone_detected) { // "Scanning" display.setTextAlignment(TEXT_ALIGN_CENTER); // clear status line - display.setColor(BLACK); - display.fillRect(0, STATUS_TEXT_TOP, 128, 16); - display.setColor(WHITE); + clearStatus(); if (scan_var == 0) { - display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scanning. "); + display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scan. "); } else if (scan_var == 1) { - display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scanning.. "); + display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scan.. "); } else if (scan_var == 2) { - display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scanning..."); + display.drawString(start_scan_text, STATUS_TEXT_TOP, "Scan..."); } scan_var++; if (scan_var == 3) + { scan_var = 0; + } } - else + + if (drone_detected) { display.setTextAlignment(TEXT_ALIGN_CENTER); // clear status line - display.setColor(BLACK); - display.fillRect(0, STATUS_TEXT_TOP, 128, 16); - display.setColor(WHITE); + clearStatus(); - display.drawString(start_scan_text, STATUS_TEXT_TOP, String(drone_detected_freqancy_start) + ">!UAV!<" + String(drone_detected_freqancy_end)); - drone_detected_freqancy_start = 0; - drone_detected = 0; + display.drawString(start_scan_text, STATUS_TEXT_TOP, String(drone_detected_freqancy_start) + ">RF<" + String(drone_detected_freqancy_end)); } + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.drawString(0, STATUS_TEXT_TOP, String(FREQ_BEGIN)); + + display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.drawString(128, STATUS_TEXT_TOP, String(FREQ_END)); + if (!initialized) { // X-axis @@ -199,9 +300,6 @@ void displayDecorate() // ticks #ifdef MAJOR_TICKS drawTicks(MAJOR_TICKS, MAJOR_TICK_LENGTH); -#endif -#ifdef MINOR_TICKS - drawTicks(MINOR_TICKS, MINOR_TICK_LENGTH); #endif } initialized = true; @@ -211,18 +309,21 @@ void setup() { pinMode(LED, OUTPUT); pinMode(BUZZZER_PIN, OUTPUT); + pinMode(REB_PIN, OUTPUT); heltec_setup(); display.clear(); - // draw the logo + // draw the UCOG welcome logo display.drawXbm(0, 2, 128, 64, epd_bitmap_ucog); display.display(); - delay(4000); + + delay(2000); + // 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 + // 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))); @@ -237,145 +338,291 @@ void setup() delay(300); display.clear(); - displayDecorate(); + // waterfall start line y-asix + w = WATERFALL_START; } void loop() { + if (!initialized) + { + float resolution = RANGE / STEPS; + if (RANGE_PER_PAGE == range) + { + single_page_scan = true; + } + else + { + single_page_scan = false; + } + + if (single_page_scan) + { + both.println("Single Page Screan MODE"); + both.println("To Enable single screan View Press P - button"); + both.println("Single Screan Resolution: " + String(resolution) + "Mhz/tick"); + for (int i = 0; i < 500; i++) + { + delay(10); + both.print("."); + if (button.pressed()) + { + RANGE_PER_PAGE = 50; + single_page_scan = false; + tone(BUZZZER_PIN, 205, 100); + delay(50); + tone(BUZZZER_PIN, 205, 100); + break; + } + } + } + else + { + both.println("Multi Page Screan MODE"); + both.println("To Enable single screan View Press P - button"); + both.println("Single screan Resolution: " + String(resolution) + "Mhz/tick"); + both.println("Curent Resolution: " + String((float)RANGE_PER_PAGE / STEPS) + "Mhz/tick"); + + for (int i = 0; i < 500; i++) + { + delay(10); + both.print("."); + if (button.pressed()) + { + RANGE_PER_PAGE = range; + single_page_scan = true; + tone(BUZZZER_PIN, 205, 100); + delay(50); + tone(BUZZZER_PIN, 205, 100); + break; + } + } + } + display.clear(); + } displayDecorate(); + drone_detected = false; + drone_detected_freqancy_start = 0; #ifdef PRINT_PROFILE_TIME start = millis(); #endif - if (!ANIMATED_RELOAD) + if (!ANIMATED_RELOAD || !single_page_scan) { // clear the scan plot rectangle - display.setColor(BLACK); - display.fillRect(0, 0, STEPS, HEIGHT); - display.setColor(WHITE); + clearPloter(); } - display.setTextAlignment(TEXT_ALIGN_RIGHT); - // drone detection level - display.drawString(128, 0, String(drone_detection_level)); - // do the scan - for (x = 0; x < STEPS; x++) + range = FREQ_END - FREQ_BEGIN; + + if (RANGE_PER_PAGE > range) { - if (ANIMATED_RELOAD) - { - display.setColor(BLACK); - display.drawVerticalLine(x, 0, HEIGHT); - display.drawVerticalLine(x + 1, 0, HEIGHT); - display.setColor(WHITE); - } - 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 - -scan_start_time = millis(); - // start spectral scan - radio.spectralScanStart(SAMPLES, 1); - // wait for spectral scan to finish - while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) - { - heltec_delay(1); - } - // read the results Array to which the results will be saved - radio.spectralScanGetResult(result); - // Filter Elements without neabors - for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) - { - if (result[y] && (result[y + 1] > 0 || result[y - 1] > 0)) - { - filtered_result[y] = 1; - } - else - { - filtered_result[y] = 0; - } - } - - for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) - { -#ifdef PRINT_SCAN_VALUES - Serial.printf("%04X,", result[y]); -#endif - if (result[y] || y == drone_detection_level) - { - // check if we shuld alarm the dron - if (filtered_result[y] == 1 && y <= drone_detection_level) - { - drone_detected = true; - if (drone_detected_freqancy_start == 0) - { - drone_detected_freqancy_start = freq; - } - drone_detected_freqancy_end = freq; - led_flag = true; - //if level to sensetive doing beep every 10th freaqancy and shorter - //TODO: make every 10th detection... - if (drone_detection_level < 25){ - tone(BUZZZER_PIN, 205, 10); - } else { - if (x % 10 == 0) - tone(BUZZZER_PIN, 205, 5); - } - display.setPixel(x, 1); - display.setPixel(x, 2); - display.setPixel(x, 3); - display.setPixel(x, 4); - } - if (filtered_result[y] == 1) - { - display.setPixel(x, y); - } - - // Detection Level line - if (y == drone_detection_level && x % 2 == 0) - { - display.setPixel(x, y); - } - } - } -#ifdef PRINT_SCAN_VALUES - Serial.println(); -#endif - if (first_run || ANIMATED_RELOAD) - { - display.display(); - } - - // Detection level button short press - if (button.pressedFor(100)) { - 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)); - if (drone_detection_level > 30) { - drone_detection_level = 1; - } + RANGE_PER_PAGE = range; } - // wait a little bit before the next scan, otherwise the SX1262 hangs - heltec_delay(1); + + fr_begin = FREQ_BEGIN; + fr_end = fr_begin; + // 50 is a single screan range + // TODO:Make 50 as a variable with the option show 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; + } + + // Iterateing by small ranges by 50 Mhz each pixel is 0.4 Mhz + for (i = 0; i < iterations; i++) + { + range = RANGE_PER_PAGE; + drone_detected_freqancy_start == 0; + + fr_begin = (i == 0) ? fr_begin : fr_begin += range; + fr_end = fr_begin + RANGE_PER_PAGE; + + if (!ANIMATED_RELOAD || !single_page_scan) + { + // clear the scan plot rectangle + clearPloter(); + } + + if (single_page_scan == false) + { + displayDecorate(fr_begin, fr_end, true); + } + + display.setTextAlignment(TEXT_ALIGN_RIGHT); + // horizontal x assix loop + for (x = 0; x < STEPS; x++) + { + if (ANIMATED_RELOAD) + { + // Draw animated cursor on reload process + display.setColor(BLACK); + display.drawVerticalLine(x, 0, HEIGHT); + display.drawVerticalLine(x + 1, 0, HEIGHT); + display.setColor(WHITE); + } + waterfall[i][x][w] = false; + freq = fr_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 + + scan_start_time = millis(); + // start spectral scan + radio.spectralScanStart(SAMPLES, 1); + // wait for spectral scan to finish + while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) + { + heltec_delay(1); + } + // read the results Array to which the results will be saved + radio.spectralScanGetResult(result); + // Filter Elements without neabors + bool detected = false; + for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { + if (result[y] && (result[y + 1] > 0 || result[y - 1] > 0)) + { + filtered_result[y] = 1; + } + else + { + filtered_result[y] = 0; + } + } + + for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { +#ifdef PRINT_SCAN_VALUES + Serial.printf("%04X,", result[y]); +#endif + if (result[y] || y == drone_detection_level) + { + // check if we shuld alarm the dron + if (filtered_result[y] == 1 && y <= drone_detection_level) + { + drone_detected = true; + if (single_page_scan) + { + // Drone detection true for waterfall + waterfall[i][x][w] = true; + display.setColor(WHITE); + display.setPixel(x, w); + } + + if (drone_detected_freqancy_start == 0) + { + drone_detected_freqancy_start = freq; + } + drone_detected_freqancy_end = freq; + led_flag = true; + // if level to sensetive doing beep every 10th freaqancy and shorter + if (drone_detection_level < 25) + { + if (detection_count % 3 == 0) + tone(BUZZZER_PIN, 205, 10); + } + else + { + if (detection_count % 10 == 0) + tone(BUZZZER_PIN, 205, 5); + } + + // TODO: make detection waterfall + display.setPixel(x, 1); + display.setPixel(x, 2); + display.setPixel(x, 3); + display.setPixel(x, 4); + } + else if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[i][x][w] != true) + { + // if drone not found dark pixel on waterfall + waterfall[i][x][w] = false; + display.setColor(BLACK); + display.setPixel(x, w); + display.setColor(WHITE); + } + + if (filtered_result[y] == 1) + { + // Set signal level pixel + display.setPixel(x, y); + detected = true; + } + + // Draw detection Level line + if (y == drone_detection_level && x % 2 == 0) + { + display.setPixel(x, y); + } + } + if (detected) + { + detection_count++; + detected = false; + } + } +#ifdef PRINT_SCAN_VALUES + Serial.println(); +#endif + if (first_run || ANIMATED_RELOAD) + { + display.display(); + } + + // Detection level button short press + if (button.pressedFor(100)) + { + 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(BUZZZER_PIN, 104, 150); + if (drone_detection_level > 30) + { + drone_detection_level = 1; + } + } + // wait a little bit before the next scan, otherwise the SX1262 hangs + heltec_delay(1); #ifdef PRINT_PROFILE_TIME - scan_time = millis() - scan_start_time; - Serial.printf("Single Scan took %lld ms\n", scan_time); + scan_time = millis() - scan_start_time; + Serial.printf("Single Scan took %lld ms\n", scan_time); #endif - + } + w++; + if (w > STATUS_TEXT_TOP + 1) + { + w = WATERFALL_START; + } + display.display(); } + #ifdef PRINT_SCAN_VALUES Serial.println(); #endif From 1105dddfa278881ab85ea39f5ab2e66aa8bda4a4 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 30 Jul 2024 11:29:24 -0700 Subject: [PATCH 19/36] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7406cf1..b83a368 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,8 @@ https://thangs.com/designer/Snake0017/3d-model/Heltec%20LoRa%2032%20Desktop%20%2 or buy : https://www.amazon.com/DIYmalls-ESP32-OLED-WiFi-Type-C/dp/B0BR3MQ9BG +https://www.thingiverse.com/thing:6522462 + # Heltec ESP32 Lora v3 Pin Map ![image](https://github.com/user-attachments/assets/a1e00b51-5566-4ff5-98fe-67eaeb5bc81f) 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. From 7a4412f2653d8c1b987ed4606339c9caf976db4f Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 30 Jul 2024 12:50:21 -0700 Subject: [PATCH 20/36] Update main.cpp --- src/main.cpp | 132 ++++++++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 60 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5ce0050..279ed94 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,14 +22,16 @@ */ // frequency range in MHz to scan -#define FREQ_BEGIN 860 +#define FREQ_BEGIN 830 // TODO: if % RANGE_PER_PAGE 1= 0 #define FREQ_END 960 +//TODO: Ignore power lines #define UP_FILTER = 5; #define LOW_FILTER = 3; // numbers of the spectrum screen lines = width of screen +// resolution of the scan limited by 128 pixel screan #define STEPS 128 // Number of samples for each frequency scan. Fewer samples = better temporal resolution. #define SAMPLES 60 //(scan time = 1294) @@ -37,7 +39,7 @@ #define RANGE (int)(FREQ_END - FREQ_BEGIN) // MHZ per page // to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 -unsigned int RANGE_PER_PAGE = 100; +unsigned int RANGE_PER_PAGE = 130; #define SINGLE_STEP (float)(RANGE / STEPS) unsigned int single_step = SINGLE_STEP; @@ -338,68 +340,78 @@ void setup() delay(300); display.clear(); + + + float resolution = RANGE / STEPS; + if (RANGE_PER_PAGE == range) + { + single_page_scan = true; + } + else + { + 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()) + { + Serial.print("Button pressed"); + RANGE_PER_PAGE = 50; + single_page_scan = false; + tone(BUZZZER_PIN, 205, 100); + delay(50); + tone(BUZZZER_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(BUZZZER_PIN, 205, 100); + + break; + } + } + } + display.clear(); + // waterfall start line y-asix w = WATERFALL_START; } void loop() { - if (!initialized) - { - float resolution = RANGE / STEPS; - if (RANGE_PER_PAGE == range) - { - single_page_scan = true; - } - else - { - single_page_scan = false; - } - - if (single_page_scan) - { - both.println("Single Page Screan MODE"); - both.println("To Enable single screan View Press P - button"); - both.println("Single Screan Resolution: " + String(resolution) + "Mhz/tick"); - for (int i = 0; i < 500; i++) - { - delay(10); - both.print("."); - if (button.pressed()) - { - RANGE_PER_PAGE = 50; - single_page_scan = false; - tone(BUZZZER_PIN, 205, 100); - delay(50); - tone(BUZZZER_PIN, 205, 100); - break; - } - } - } - else - { - both.println("Multi Page Screan MODE"); - both.println("To Enable single screan View Press P - button"); - both.println("Single screan Resolution: " + String(resolution) + "Mhz/tick"); - both.println("Curent Resolution: " + String((float)RANGE_PER_PAGE / STEPS) + "Mhz/tick"); - - for (int i = 0; i < 500; i++) - { - delay(10); - both.print("."); - if (button.pressed()) - { - RANGE_PER_PAGE = range; - single_page_scan = true; - tone(BUZZZER_PIN, 205, 100); - delay(50); - tone(BUZZZER_PIN, 205, 100); - break; - } - } - } - display.clear(); - } displayDecorate(); drone_detected = false; drone_detected_freqancy_start = 0; @@ -423,7 +435,7 @@ void loop() fr_begin = FREQ_BEGIN; fr_end = fr_begin; - // 50 is a single screan range + // 50 is a single screen range // TODO:Make 50 as a variable with the option show full range iterations = range / RANGE_PER_PAGE; @@ -497,8 +509,8 @@ void loop() } // read the results Array to which the results will be saved radio.spectralScanGetResult(result); - // Filter Elements without neabors bool detected = false; + // Filter Elements without neabors for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { if (result[y] && (result[y + 1] > 0 || result[y - 1] > 0)) From a49fbafb5227a945fe0f6448f16c5ff5b1e42f12 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 30 Jul 2024 15:38:26 -0700 Subject: [PATCH 21/36] add waterfall update cursor --- src/main.cpp | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 279ed94..1ea3099 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,11 +22,15 @@ */ // frequency range in MHz to scan -#define FREQ_BEGIN 830 +#define FREQ_BEGIN 850 // TODO: if % RANGE_PER_PAGE 1= 0 -#define FREQ_END 960 +#define FREQ_END 950 -//TODO: Ignore power lines +// MHZ per page +// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 +unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN + +// TODO: Ignore power lines #define UP_FILTER = 5; #define LOW_FILTER = 3; @@ -37,9 +41,7 @@ #define SAMPLES 60 //(scan time = 1294) #define RANGE (int)(FREQ_END - FREQ_BEGIN) -// MHZ per page -// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 -unsigned int RANGE_PER_PAGE = 130; + #define SINGLE_STEP (float)(RANGE / STEPS) unsigned int single_step = SINGLE_STEP; @@ -72,7 +74,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #include "modules/SX126x/patches/SX126x_patch_scan.h" // Prints the scan measurement bins from the SX1262 in hex -#define PRINT_SCAN_VALUES +//#define PRINT_SCAN_VALUES #define PRINT_PROFILE_TIME // Change spectrum plot values at once or by line #define ANIMATED_RELOAD true @@ -242,7 +244,7 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) display.drawString(128, SCALE_TEXT_TOP, (end == 0) ? String(FREQ_END) : String(end)); } - if (led_flag == true) + if (led_flag == true && detection_count > 5) { digitalWrite(LED, HIGH); tone(BUZZZER_PIN, 104, 250); @@ -341,7 +343,6 @@ void setup() display.clear(); - float resolution = RANGE / STEPS; if (RANGE_PER_PAGE == range) { @@ -352,10 +353,10 @@ void setup() single_page_scan = false; } - // Adjust range if it is not even to RANGE_PER_PAGE + // 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; + // range = range + range % RANGE_PER_PAGE; } if (single_page_scan) @@ -414,6 +415,7 @@ void loop() { displayDecorate(); drone_detected = false; + detection_count = 0; drone_detected_freqancy_start = 0; #ifdef PRINT_PROFILE_TIME start = millis(); @@ -559,8 +561,6 @@ void loop() if (detection_count % 10 == 0) tone(BUZZZER_PIN, 205, 5); } - - // TODO: make detection waterfall display.setPixel(x, 1); display.setPixel(x, 2); display.setPixel(x, 3); @@ -569,6 +569,7 @@ void loop() else if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[i][x][w] != true) { // if drone not found dark pixel on waterfall + // TODO: make somethin like scrolling up if possible waterfall[i][x][w] = false; display.setColor(BLACK); display.setPixel(x, w); @@ -632,6 +633,15 @@ void loop() { w = WATERFALL_START; } + + // Draw waterfall position cursor + if (single_page_scan) + { + display.setColor(BLACK); + display.drawHorizontalLine(0, w, STEPS); + display.setColor(WHITE); + } + display.display(); } From 28ff4e6d61ac26f2526b54951b11edd42cd8929c Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 30 Jul 2024 17:15:02 -0700 Subject: [PATCH 22/36] remove serial print --- src/main.cpp | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 1ea3099..fb83eaa 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -180,14 +180,6 @@ void drawTicks(float every, int length) } tick += pixels_per_step; - Serial.print("tick:"); - Serial.print(tick); - Serial.print("\n"); - - tick_minor = tick - pixels_per_step / 2; - Serial.print("tick_minor:"); - Serial.print(tick_minor); - Serial.print("\n"); // Fix double tick at the end ... if (tick < 128 - 3) @@ -373,7 +365,6 @@ void setup() both.print("."); if (button.pressed()) { - Serial.print("Button pressed"); RANGE_PER_PAGE = 50; single_page_scan = false; tone(BUZZZER_PIN, 205, 100); @@ -481,6 +472,7 @@ void loop() // horizontal x assix loop for (x = 0; x < STEPS; x++) { + scan_start_time = millis(); if (ANIMATED_RELOAD) { // Draw animated cursor on reload process @@ -501,7 +493,6 @@ void loop() Serial.println(); #endif - scan_start_time = millis(); // start spectral scan radio.spectralScanStart(SAMPLES, 1); // wait for spectral scan to finish @@ -553,7 +544,9 @@ void loop() // if level to sensetive doing beep every 10th freaqancy and shorter if (drone_detection_level < 25) { - if (detection_count % 3 == 0) + if (detection_count == 1) + tone(BUZZZER_PIN, 205, 10); + if (detection_count % 5 == 0) tone(BUZZZER_PIN, 205, 10); } else @@ -594,6 +587,11 @@ void loop() detection_count++; detected = false; } +#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); +#endif } #ifdef PRINT_SCAN_VALUES Serial.println(); @@ -622,11 +620,6 @@ void loop() } // wait a little bit before the next scan, otherwise the SX1262 hangs heltec_delay(1); - -#ifdef PRINT_PROFILE_TIME - scan_time = millis() - scan_start_time; - Serial.printf("Single Scan took %lld ms\n", scan_time); -#endif } w++; if (w > STATUS_TEXT_TOP + 1) @@ -641,14 +634,13 @@ void loop() display.drawHorizontalLine(0, w, STEPS); display.setColor(WHITE); } - display.display(); } #ifdef PRINT_SCAN_VALUES Serial.println(); #endif - display.display(); + //display.display(); #ifdef PRINT_PROFILE_TIME scan_time = millis() - start; Serial.printf("Scan took %lld ms\n", scan_time); From 007009cb7635c78d97b53722a6bea631a871cfe8 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 30 Jul 2024 20:24:33 -0700 Subject: [PATCH 23/36] Update LICENSE.md --- LICENSE.md | 674 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE.md diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..9e419e0 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file From 2afe07cd9d80cb569e611d64340b2f4e5362df3e Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 09:41:52 -0700 Subject: [PATCH 24/36] Update main.cpp --- src/main.cpp | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fb83eaa..6c92c20 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -70,18 +70,20 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #include #include -// This file contains binary patch for the SX1262 +// This file contaiminins 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_SCAN_VALUES #define PRINT_PROFILE_TIME // Change spectrum plot values at once or by line #define ANIMATED_RELOAD true -#define MAJOR_TICK_LENGTH 3 +#define MAJOR_TICK_LENGTH 2 #define MINOR_TICK_LENGTH 1 -#define X_AXIS_WEIGHT 2 +// WEIGHT of the x-asix line +#define X_AXIS_WEIGHT 1 +// Height of the ploter area #define HEIGHT RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE // #define SCALE_TEXT_TOP (HEIGHT + X_AXIS_WEIGHT + MAJOR_TICK_LENGTH) @@ -94,7 +96,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // REB trigger PIN #define REB_PIN 42 -#define WATERFALL_START 39 +#define WATERFALL_START 37 #define DISABLE_PLOT_CHART false @@ -170,7 +172,8 @@ void drawTicks(float every, int length) int tick = 0; int tick_minor = 0; int median = (RANGE_PER_PAGE / every) / 2; - for (int t = 0; t <= (RANGE_PER_PAGE / every) + 1; t++) + // 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) @@ -180,15 +183,18 @@ void drawTicks(float every, int length) } tick += pixels_per_step; + tick_minor = tick / 2; // Fix double tick at the end ... if (tick < 128 - 3) + { display.drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick, HEIGHT + X_AXIS_WEIGHT + length); + } #ifdef MINOR_TICKS // Fix two ticks togather // if(tick_minor + 1 != tick && tick_minor - 1 != tick && tick_minor + 2 != tick && tick_minor - 2 != tick) { - display.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, HEIGHT + X_AXIS_WEIGHT + 2); + display.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); //} #endif } @@ -205,8 +211,8 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) 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); + display.fillRect(0, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH + 1); + display.fillRect(126, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH + 1); // drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); @@ -545,7 +551,7 @@ void loop() if (drone_detection_level < 25) { if (detection_count == 1) - tone(BUZZZER_PIN, 205, 10); + tone(BUZZZER_PIN, 205, 10); if (detection_count % 5 == 0) tone(BUZZZER_PIN, 205, 10); } @@ -562,7 +568,7 @@ void loop() else if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[i][x][w] != true) { // if drone not found dark pixel on waterfall - // TODO: make somethin like scrolling up if possible + // TODO: make somethin like scrolling up if possible waterfall[i][x][w] = false; display.setColor(BLACK); display.setPixel(x, w); @@ -588,9 +594,9 @@ void loop() detected = false; } #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 } #ifdef PRINT_SCAN_VALUES @@ -640,7 +646,7 @@ void loop() #ifdef PRINT_SCAN_VALUES Serial.println(); #endif - //display.display(); + // display.display(); #ifdef PRINT_PROFILE_TIME scan_time = millis() - start; Serial.printf("Scan took %lld ms\n", scan_time); From d0e78b2c38cb742911b63d5a8c994de75c98997e Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 10:23:49 -0700 Subject: [PATCH 25/36] add thick central tick --- src/main.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6c92c20..07c2901 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,7 +38,7 @@ unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // resolution of the scan limited by 128 pixel screan #define STEPS 128 // Number of samples for each frequency scan. Fewer samples = better temporal resolution. -#define SAMPLES 60 //(scan time = 1294) +#define SAMPLES 200 //(scan time = 1294) #define RANGE (int)(FREQ_END - FREQ_BEGIN) @@ -185,16 +185,25 @@ void drawTicks(float every, int length) tick += pixels_per_step; tick_minor = tick / 2; - // Fix double tick at the end ... if (tick < 128 - 3) { display.drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick, HEIGHT + X_AXIS_WEIGHT + length); + // Central tick + if (tick > (128 / 2) - 3 && tick < (128 / 2) + 3) + { + display.drawLine(tick + 1, HEIGHT + X_AXIS_WEIGHT, tick + 1, HEIGHT + X_AXIS_WEIGHT + length); + } } #ifdef MINOR_TICKS // Fix two ticks togather // if(tick_minor + 1 != tick && tick_minor - 1 != tick && tick_minor + 2 != tick && tick_minor - 2 != tick) { display.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.drawLine(tick_minor + 1, HEIGHT + X_AXIS_WEIGHT, tick_minor + 1, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); + } //} #endif } From 44566f768fbb49f211a2d833d2455e39b48b5e0f Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 10:57:49 -0700 Subject: [PATCH 26/36] remove double tick --- src/main.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 07c2901..fc80cc5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -197,8 +197,10 @@ void drawTicks(float every, int length) #ifdef MINOR_TICKS // Fix two ticks togather - // if(tick_minor + 1 != tick && tick_minor - 1 != tick && tick_minor + 2 != tick && tick_minor - 2 != tick) { - display.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); + if (tick_minor + 1 != tick && tick_minor - 1 != tick && tick_minor + 2 != tick && tick_minor - 2 != tick) + { + display.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) { From 6fa64ddaa219e0bcab898dead334c5583f091e90 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 11:11:27 -0700 Subject: [PATCH 27/36] detection sound logic --- src/main.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index fc80cc5..6e15036 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -115,6 +115,7 @@ bool led_flag = false; bool first_run = false; // drone tetection flag bool drone_detected = false; +bool detected = false; unsigned int drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; unsigned int drone_detected_freqancy_start = 0; unsigned int drone_detected_freqancy_end = 0; @@ -509,7 +510,6 @@ void loop() Serial.print(freq); Serial.println(); #endif - // start spectral scan radio.spectralScanStart(SAMPLES, 1); // wait for spectral scan to finish @@ -519,7 +519,7 @@ void loop() } // read the results Array to which the results will be saved radio.spectralScanGetResult(result); - bool detected = false; + detected = false; // Filter Elements without neabors for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { @@ -568,8 +568,8 @@ void loop() } else { - if (detection_count % 10 == 0) - tone(BUZZZER_PIN, 205, 5); + if (detection_count % 20 == 0) + tone(BUZZZER_PIN, 205, 10); } display.setPixel(x, 1); display.setPixel(x, 2); @@ -602,7 +602,6 @@ void loop() if (detected) { detection_count++; - detected = false; } #ifdef PRINT_PROFILE_TIME scan_time = millis() - scan_start_time; @@ -610,6 +609,7 @@ void loop() // Serial.printf("Single Scan took %lld ms\n", scan_time); #endif } + detected = false; #ifdef PRINT_SCAN_VALUES Serial.println(); #endif From 9e4cd5162d47f4fbb331958b1b659436a9f809e3 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 12:34:34 -0700 Subject: [PATCH 28/36] filter logic --- src/main.cpp | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 6e15036..5e958da 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -38,7 +38,8 @@ unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // resolution of the scan limited by 128 pixel screan #define STEPS 128 // Number of samples for each frequency scan. Fewer samples = better temporal resolution. -#define SAMPLES 200 //(scan time = 1294) +// if more tan 100 it can feez +#define SAMPLES 100 //(scan time = 1294) #define RANGE (int)(FREQ_END - FREQ_BEGIN) @@ -257,7 +258,7 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) if (led_flag == true && detection_count > 5) { digitalWrite(LED, HIGH); - tone(BUZZZER_PIN, 104, 250); + tone(BUZZZER_PIN, 104, 100); digitalWrite(REB_PIN, HIGH); led_flag = false; } @@ -523,8 +524,14 @@ void loop() // Filter Elements without neabors for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { - if (result[y] && (result[y + 1] > 0 || result[y - 1] > 0)) + if (result[y] && (result[y + 1] > 0 || result[y + 2] > 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 @@ -559,7 +566,7 @@ void loop() drone_detected_freqancy_end = freq; led_flag = true; // if level to sensetive doing beep every 10th freaqancy and shorter - if (drone_detection_level < 25) + if (drone_detection_level <= 25) { if (detection_count == 1) tone(BUZZZER_PIN, 205, 10); @@ -599,16 +606,17 @@ void loop() display.setPixel(x, y); } } - if (detected) - { - detection_count++; - } + #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); #endif } + if (detected) + { + detection_count++; + } detected = false; #ifdef PRINT_SCAN_VALUES Serial.println(); From 308c741affbb6f44382825db8e0ec2f44641bf7f Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 19:25:04 -0700 Subject: [PATCH 29/36] add code execution stop --- src/main.cpp | 63 +++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 5e958da..455ec08 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -122,6 +122,7 @@ unsigned int drone_detected_freqancy_start = 0; unsigned int drone_detected_freqancy_end = 0; unsigned int detection_count = 0; bool single_page_scan = false; +bool SOUND_ON = true; unsigned int start_scan_text = (128 / 2) - 3; @@ -133,6 +134,9 @@ uint64_t start = 0; unsigned int x, y, i, w = 0; float freq = 0; +int rssi = 0; + +unsigned int button_pressed_counter = 0; void clearStatus() { @@ -187,7 +191,7 @@ void drawTicks(float every, int length) tick += pixels_per_step; tick_minor = tick / 2; - if (tick < 128 - 3) + if (tick <= 128 - 3) { display.drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick, HEIGHT + X_AXIS_WEIGHT + length); // Central tick @@ -258,7 +262,10 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) if (led_flag == true && detection_count > 5) { digitalWrite(LED, HIGH); - tone(BUZZZER_PIN, 104, 100); + if (SOUND_ON) + { + tone(BUZZZER_PIN, 104, 100); + } digitalWrite(REB_PIN, HIGH); led_flag = false; } @@ -331,7 +338,19 @@ void setup() display.drawXbm(0, 2, 128, 64, epd_bitmap_ucog); display.display(); - delay(2000); + for (int i = 0; i < 200; i++) + { + button.update(); + delay(10); + if (button.pressed()) + { + SOUND_ON = false; + tone(BUZZZER_PIN, 205, 100); + delay(50); + tone(BUZZZER_PIN, 205, 100); + break; + } + } // initialize SX1262 FSK modem at the initial frequency both.println("Init radio"); @@ -503,6 +522,8 @@ void loop() waterfall[i][x][w] = false; freq = fr_begin + (range * ((float)x / STEPS)); radio.setFrequency(freq); + rssi = radio.getRSSI(); + Serial.println(String(rssi) + "db"); #ifdef PRINT_SCAN_VALUES Serial.println(); Serial.print("step-"); @@ -568,14 +589,14 @@ void loop() // if level to sensetive doing beep every 10th freaqancy and shorter if (drone_detection_level <= 25) { - if (detection_count == 1) + if (detection_count == 1 && SOUND_ON) tone(BUZZZER_PIN, 205, 10); - if (detection_count % 5 == 0) + if (detection_count % 5 == 0 && SOUND_ON) tone(BUZZZER_PIN, 205, 10); } else { - if (detection_count % 20 == 0) + if (detection_count % 20 == 0 && SOUND_ON) tone(BUZZZER_PIN, 205, 10); } display.setPixel(x, 1); @@ -629,6 +650,34 @@ void loop() // Detection level button short press if (button.pressedFor(100)) { + button.update(); + button_pressed_counter = 0; + // if long press stop + while (button.pressedNow()) + { + delay(10); + button_pressed_counter++; + if (button_pressed_counter > 200) + { + digitalWrite(LED, HIGH); + delay(50); + digitalWrite(LED, LOW); + } + } + if (button_pressed_counter > 200) + { + break; + } + if (button_pressed_counter > 100 && button_pressed_counter < 200) + { + // 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); @@ -637,7 +686,9 @@ void loop() drone_detection_level++; // print new value display.drawString(128, 0, String(drone_detection_level)); + tone(BUZZZER_PIN, 104, 150); + if (drone_detection_level > 30) { drone_detection_level = 1; From af33a97d41ef4288a05a6e046a461b51242d4136 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 19:31:53 -0700 Subject: [PATCH 30/36] RSSI Method test --- src/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 455ec08..c07e482 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -522,8 +522,9 @@ void loop() waterfall[i][x][w] = false; freq = fr_begin + (range * ((float)x / STEPS)); radio.setFrequency(freq); - rssi = radio.getRSSI(); - Serial.println(String(rssi) + "db"); + //RSSI METHOD + //rssi = radio.getRSSI(false); + //Serial.println(String(rssi) + "db"); #ifdef PRINT_SCAN_VALUES Serial.println(); Serial.print("step-"); From fdd0ba0ba889195087eb8c046aab8c234b1ee91c Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 19:59:19 -0700 Subject: [PATCH 31/36] show curent frequency --- src/main.cpp | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c07e482..ee49ed6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,9 +22,9 @@ */ // frequency range in MHz to scan -#define FREQ_BEGIN 850 +#define FREQ_BEGIN 830 // TODO: if % RANGE_PER_PAGE 1= 0 -#define FREQ_END 950 +#define FREQ_END 930 // MHZ per page // to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 @@ -59,7 +59,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // 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 +#define BANDWIDTH 467.0 // 93.8 // 467.0 // (optional) major and minor tickmarks at x MHz #define MAJOR_TICKS 10 @@ -522,9 +522,9 @@ void loop() waterfall[i][x][w] = false; freq = fr_begin + (range * ((float)x / STEPS)); radio.setFrequency(freq); - //RSSI METHOD - //rssi = radio.getRSSI(false); - //Serial.println(String(rssi) + "db"); + // RSSI METHOD + // rssi = radio.getRSSI(false); + // Serial.println(String(rssi) + "db"); #ifdef PRINT_SCAN_VALUES Serial.println(); Serial.print("step-"); @@ -657,6 +657,10 @@ void loop() 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 > 200) { @@ -667,6 +671,12 @@ void loop() } if (button_pressed_counter > 200) { + // 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 > 100 && button_pressed_counter < 200) From 9f50f002aef658ae2ba97f6018e45622f173847b Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 31 Jul 2024 23:09:56 -0700 Subject: [PATCH 32/36] some fixes --- src/main.cpp | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index ee49ed6..bcf7017 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,17 +22,18 @@ */ // frequency range in MHz to scan -#define FREQ_BEGIN 830 +#define FREQ_BEGIN 850 // TODO: if % RANGE_PER_PAGE 1= 0 -#define FREQ_END 930 +#define FREQ_END 950 // MHZ per page // to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // TODO: Ignore power lines -#define UP_FILTER = 5; -#define LOW_FILTER = 3; +#define UP_FILTER 5 +#define LOW_FILTER 3 +#define FILTER_SPECTRUM_RESULTS true // numbers of the spectrum screen lines = width of screen // resolution of the scan limited by 128 pixel screan @@ -97,6 +98,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; // REB trigger PIN #define REB_PIN 42 +#define WATERFALL_ENABLED true #define WATERFALL_START 37 #define DISABLE_PLOT_CHART false @@ -259,7 +261,7 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) display.drawString(128, SCALE_TEXT_TOP, (end == 0) ? String(FREQ_END) : String(end)); } - if (led_flag == true && detection_count > 5) + if (led_flag == true && detection_count >= 5) { digitalWrite(LED, HIGH); if (SOUND_ON) @@ -523,6 +525,7 @@ void loop() freq = fr_begin + (range * ((float)x / STEPS)); radio.setFrequency(freq); // RSSI METHOD + // Gets RSSI (Recorded Signal Strength Indicator) // rssi = radio.getRSSI(false); // Serial.println(String(rssi) + "db"); #ifdef PRINT_SCAN_VALUES @@ -533,7 +536,7 @@ void loop() Serial.print(freq); Serial.println(); #endif - // start spectral scan + // 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) @@ -543,17 +546,18 @@ void loop() // read the results Array to which the results will be saved radio.spectralScanGetResult(result); detected = false; +#ifdef FILTER_SPECTRUM_RESULTS // Filter Elements without neabors for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { - if (result[y] && (result[y + 1] > 0 || result[y + 2] > 0 || result[y - 1] > 0)) + 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; - } + /* 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 @@ -561,7 +565,7 @@ void loop() filtered_result[y] = 0; } } - +#endif for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { #ifdef PRINT_SCAN_VALUES @@ -665,7 +669,7 @@ void loop() if (button_pressed_counter > 200) { digitalWrite(LED, HIGH); - delay(50); + delay(150); digitalWrite(LED, LOW); } } @@ -679,7 +683,7 @@ void loop() display.display(); break; } - if (button_pressed_counter > 100 && button_pressed_counter < 200) + if (button_pressed_counter > 50 && button_pressed_counter < 200) { // Visually confirm it's off so user releases button display.displayOff(); From ce3f919053cce98129bf5e0ceac0d7d60a5fdf66 Mon Sep 17 00:00:00 2001 From: Oleksii Mandrychenko Date: Thu, 1 Aug 2024 09:41:56 -0700 Subject: [PATCH 33/36] Update README.md --- README.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b83a368..bd006a2 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,16 @@ # Lora SA(Spectrum Analyzer) RF Spectrum Analyzer using Lora Radio -![IMG_5267](https://github.com/user-attachments/assets/4caeb467-1964-4184-ab20-ba68b97144aa) +LORA hardware -RadioLib SX126x Spectrum Scan +Based on 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. 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. - +``` N in Bin / dBm 1 -11 2 -15 @@ -45,15 +45,18 @@ N in Bin / dBm 31 -131 32 -135 33 -139 +``` Example: +``` step-13 Frequancy: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, +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 +``` The spectrum analyzer performs power measurements in the configured bandwidth. -The X axis represents frequency in MHZ and Y axis display actual received power. -In this example above, the frequency span goes from 850 MHz to 950 MHz (that is a 100MHz range), and +The X-axis represents frequency in MHz and Y-axis displays actual 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. To show the results in a plot, run the Python script From 23a9b5cf0bf3420842a7b7ca484f52e98d7622f4 Mon Sep 17 00:00:00 2001 From: Oleksii Mandrychenko Date: Thu, 1 Aug 2024 09:52:56 -0700 Subject: [PATCH 34/36] Fix minor comment issues --- src/main.cpp | 58 ++++++++++++++++++++++++++-------------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bcf7017..41d07f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,7 +27,7 @@ #define FREQ_END 950 // MHZ per page -// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 +// To put everything on one page set RANGE_PER_PAGE = FREQ_END - 800 unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // TODO: Ignore power lines @@ -35,11 +35,11 @@ unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN #define LOW_FILTER 3 #define FILTER_SPECTRUM_RESULTS true -// numbers of the spectrum screen lines = width of screen -// resolution of the scan limited by 128 pixel screan +// The number of the spectrum screen lines = width of screen +// Resolution of the scan is limited by 128-pixel screen #define STEPS 128 // Number of samples for each frequency scan. Fewer samples = better temporal resolution. -// if more tan 100 it can feez +// if more than 100 it can freez #define SAMPLES 100 //(scan time = 1294) #define RANGE (int)(FREQ_END - FREQ_BEGIN) @@ -72,7 +72,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #include #include -// This file contaiminins binary patch for the SX1262 +// This file contains a binary patch for the SX1262 #include "modules/SX126x/patches/SX126x_patch_scan.h" // Prints the scan measurement bins from the SX1262 in hex @@ -85,13 +85,13 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define MINOR_TICK_LENGTH 1 // WEIGHT of the x-asix line #define X_AXIS_WEIGHT 1 -// Height of the ploter area +// Height of the plotter area #define HEIGHT RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE // #define SCALE_TEXT_TOP (HEIGHT + X_AXIS_WEIGHT + MAJOR_TICK_LENGTH) #define STATUS_TEXT_TOP (64 - 10) -// Detection level from the 33 levels. Higher number is more sensative +// Detection level from the 33 levels. The higher number is more sensitive #define DEFAULT_DRONE_DETECTION_LEVEL 21 #define BUZZZER_PIN 41 @@ -113,10 +113,10 @@ bool waterfall[10][STEPS][10]; unsigned short int scan_var = 0; // initialized flag bool initialized = false; -// Used as a Led Light and Buzzer/sount trigger +// Used as a Led Light and Buzzer/count trigger bool led_flag = false; bool first_run = false; -// drone tetection flag +// drone detection flag bool drone_detected = false; bool detected = false; unsigned int drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; @@ -150,14 +150,14 @@ void clearStatus() void clearPloter() { - // clear the scan plot rectangle + //Clear the scan plot rectangle display.setColor(BLACK); display.fillRect(0, 0, STEPS, HEIGHT); display.setColor(WHITE); } /** - * @brief Draws ticks on the display at regular whole intervals. + * @brief Draws ticks on display at regular intervals. * * @param every The interval between ticks in MHz. * @param length The length of each tick in pixels. @@ -180,7 +180,7 @@ void drawTicks(float every, int length) 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 + // TODO: (RANGE_PER_PAGE / every) * 2 has twice extra steps we need to figure out correct logic or minor ticks are 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 @@ -204,7 +204,7 @@ void drawTicks(float every, int length) } #ifdef MINOR_TICKS - // Fix two ticks togather + // Fix two ticks together if (tick_minor + 1 != tick && tick_minor - 1 != tick && tick_minor + 2 != tick && tick_minor - 2 != tick) { display.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); @@ -229,11 +229,11 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) { if (!initialized) { - // begining and end ticks + // Start and end ticks display.fillRect(0, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH + 1); display.fillRect(126, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH + 1); - // drone detection level + // Drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, 0, String(drone_detection_level)); } @@ -245,18 +245,18 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) display.fillRect(0, SCALE_TEXT_TOP + 1, 128, 12); display.setColor(WHITE); - // drone detection level + // Drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, 0, String(drone_detection_level)); - // frequency start + // Frequency start display.setTextAlignment(TEXT_ALIGN_LEFT); display.drawString(0, SCALE_TEXT_TOP, (begin == 0) ? String(FREQ_BEGIN) : String(begin)); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(128 / 2, SCALE_TEXT_TOP, (begin == 0) ? String(median_freqancy) : String(begin + ((end - begin) / 2))); - // frequency end + // Frequency end display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, SCALE_TEXT_TOP, (end == 0) ? String(FREQ_END) : String(end)); } @@ -368,7 +368,7 @@ void setup() RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); // and disable the data shaping RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); - both.println("Starting scaning..."); + both.println("Starting scanning..."); float vbat = heltec_vbat(); both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); delay(300); @@ -438,7 +438,7 @@ void setup() } display.clear(); - // waterfall start line y-asix + // waterfall start line y-axis w = WATERFALL_START; } @@ -468,8 +468,8 @@ void loop() fr_begin = FREQ_BEGIN; fr_end = fr_begin; - // 50 is a single screen range - // TODO:Make 50 as a variable with the option show full range + // 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; @@ -488,7 +488,7 @@ void loop() single_page_scan = false; } - // Iterateing by small ranges by 50 Mhz each pixel is 0.4 Mhz + // Iterating by small ranges of 50 Mhz, each pixel is 0.4 Mhz for (i = 0; i < iterations; i++) { range = RANGE_PER_PAGE; @@ -547,12 +547,12 @@ void loop() radio.spectralScanGetResult(result); detected = false; #ifdef FILTER_SPECTRUM_RESULTS - // Filter Elements without neabors + // Filter Elements without neighbors for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { if (result[y] && (result[y + 1] > 0 && result[y - 1] > 0)) { - // filling the empty pixel between signals int the level < 27 (noise level) + //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; @@ -573,7 +573,7 @@ void loop() #endif if (result[y] || y == drone_detection_level) { - // check if we shuld alarm the dron + // check if we should alarm about a drone presence if (filtered_result[y] == 1 && y <= drone_detection_level) { drone_detected = true; @@ -591,7 +591,7 @@ void loop() } drone_detected_freqancy_end = freq; led_flag = true; - // if level to sensetive doing beep every 10th freaqancy and shorter + //If level is set to sensitive, start beeping every 10th frequency and shorter if (drone_detection_level <= 25) { if (detection_count == 1 && SOUND_ON) @@ -611,8 +611,8 @@ void loop() } else if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[i][x][w] != true) { - // if drone not found dark pixel on waterfall - // TODO: make somethin like scrolling up if possible + // If drone not found set dark pixel on the waterfall + // TODO: make something like scrolling up if possible waterfall[i][x][w] = false; display.setColor(BLACK); display.setPixel(x, w); From 91397aedcd44df5e31526384bcc22c0c8139b08f Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Thu, 1 Aug 2024 11:18:47 -0700 Subject: [PATCH 35/36] add diapasons --- src/main.cpp | 126 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 48 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 41d07f5..019172e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,8 +26,12 @@ // TODO: if % RANGE_PER_PAGE 1= 0 #define FREQ_END 950 +// Feature to scan diapazones. Other frequency settings will be ignored. +//int SCAN_DIAPAZONES[] = {}; +int SCAN_DIAPAZONES[] = {850890, 920950}; + // MHZ per page -// To put everything on one page set RANGE_PER_PAGE = FREQ_END - 800 +// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // TODO: Ignore power lines @@ -35,11 +39,11 @@ unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN #define LOW_FILTER 3 #define FILTER_SPECTRUM_RESULTS true -// The number of the spectrum screen lines = width of screen -// Resolution of the scan is limited by 128-pixel screen +// numbers of the spectrum screen lines = width of screen +// resolution of the scan limited by 128 pixel screan #define STEPS 128 // Number of samples for each frequency scan. Fewer samples = better temporal resolution. -// if more than 100 it can freez +// if more tan 100 it can feez #define SAMPLES 100 //(scan time = 1294) #define RANGE (int)(FREQ_END - FREQ_BEGIN) @@ -72,7 +76,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #include #include -// This file contains a binary patch for the SX1262 +// This file contaiminins binary patch for the SX1262 #include "modules/SX126x/patches/SX126x_patch_scan.h" // Prints the scan measurement bins from the SX1262 in hex @@ -85,13 +89,13 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define MINOR_TICK_LENGTH 1 // WEIGHT of the x-asix line #define X_AXIS_WEIGHT 1 -// Height of the plotter area +// Height of the ploter area #define HEIGHT RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE // #define SCALE_TEXT_TOP (HEIGHT + X_AXIS_WEIGHT + MAJOR_TICK_LENGTH) #define STATUS_TEXT_TOP (64 - 10) -// Detection level from the 33 levels. The higher number is more sensitive +// Detection level from the 33 levels. Higher number is more sensative #define DEFAULT_DRONE_DETECTION_LEVEL 21 #define BUZZZER_PIN 41 @@ -100,6 +104,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define WATERFALL_ENABLED true #define WATERFALL_START 37 +#define OSD_ENABLED true #define DISABLE_PLOT_CHART false @@ -113,10 +118,10 @@ bool waterfall[10][STEPS][10]; unsigned short int scan_var = 0; // initialized flag bool initialized = false; -// Used as a Led Light and Buzzer/count trigger +// Used as a Led Light and Buzzer/sount trigger bool led_flag = false; bool first_run = false; -// drone detection flag +// drone tetection flag bool drone_detected = false; bool detected = false; unsigned int drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; @@ -134,6 +139,7 @@ unsigned int scan_start_time = 0; uint64_t start = 0; unsigned int x, y, i, w = 0; +unsigned int diapazones_count = 0; float freq = 0; int rssi = 0; @@ -150,14 +156,14 @@ void clearStatus() void clearPloter() { - //Clear the scan plot rectangle + // clear the scan plot rectangle display.setColor(BLACK); display.fillRect(0, 0, STEPS, HEIGHT); display.setColor(WHITE); } /** - * @brief Draws ticks on display at regular intervals. + * @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. @@ -180,7 +186,7 @@ void drawTicks(float every, int length) 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 figure out correct logic or minor ticks are not showing to the end + // 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 @@ -204,7 +210,7 @@ void drawTicks(float every, int length) } #ifdef MINOR_TICKS - // Fix two ticks together + // Fix two ticks togather if (tick_minor + 1 != tick && tick_minor - 1 != tick && tick_minor + 2 != tick && tick_minor - 2 != tick) { display.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); @@ -214,12 +220,8 @@ void drawTicks(float every, int length) { display.drawLine(tick_minor + 1, HEIGHT + X_AXIS_WEIGHT, tick_minor + 1, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); } -//} #endif } - - // Draw Central Tick - // display.drawLine(128/2, HEIGHT + X_AXIS_WEIGHT, 128/2, HEIGHT + X_AXIS_WEIGHT + 5); } /** @@ -229,11 +231,11 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) { if (!initialized) { - // Start and end ticks + // begining and end ticks display.fillRect(0, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH + 1); display.fillRect(126, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH + 1); - // Drone detection level + // drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, 0, String(drone_detection_level)); } @@ -245,18 +247,18 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) display.fillRect(0, SCALE_TEXT_TOP + 1, 128, 12); display.setColor(WHITE); - // Drone detection level + // drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, 0, String(drone_detection_level)); - // Frequency start + // frequency start display.setTextAlignment(TEXT_ALIGN_LEFT); display.drawString(0, SCALE_TEXT_TOP, (begin == 0) ? String(FREQ_BEGIN) : String(begin)); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(128 / 2, SCALE_TEXT_TOP, (begin == 0) ? String(median_freqancy) : String(begin + ((end - begin) / 2))); - // Frequency end + // frequency end display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, SCALE_TEXT_TOP, (end == 0) ? String(FREQ_END) : String(end)); } @@ -311,11 +313,14 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) display.drawString(start_scan_text, STATUS_TEXT_TOP, String(drone_detected_freqancy_start) + ">RF<" + String(drone_detected_freqancy_end)); } - display.setTextAlignment(TEXT_ALIGN_LEFT); - display.drawString(0, STATUS_TEXT_TOP, String(FREQ_BEGIN)); + if (diapazones_count == 0) + { + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.drawString(0, STATUS_TEXT_TOP, String(FREQ_BEGIN)); - display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(128, STATUS_TEXT_TOP, String(FREQ_END)); + display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.drawString(128, STATUS_TEXT_TOP, String(FREQ_END)); + } if (!initialized) { @@ -368,7 +373,7 @@ void setup() RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); // and disable the data shaping RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); - both.println("Starting scanning..."); + both.println("Starting scaning..."); float vbat = heltec_vbat(); both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); delay(300); @@ -438,7 +443,7 @@ void setup() } display.clear(); - // waterfall start line y-axis + // waterfall start line y-asix w = WATERFALL_START; } @@ -468,8 +473,8 @@ void loop() 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 + // 50 is a single screen range + // TODO:Make 50 as a variable with the option show full range iterations = range / RANGE_PER_PAGE; single_step = RANGE_PER_PAGE / 128; @@ -488,14 +493,36 @@ void loop() single_page_scan = false; } - // Iterating by small ranges of 50 Mhz, each pixel is 0.4 Mhz + diapazones_count = 0; + + for (int diapazone : SCAN_DIAPAZONES) + { + diapazones_count++; + } + + if (diapazones_count > 0) + { + iterations = diapazones_count; + single_page_scan = false; + } + + // Iterateing by small ranges by 50 Mhz each pixel is 0.4 Mhz for (i = 0; i < iterations; i++) { range = RANGE_PER_PAGE; - drone_detected_freqancy_start == 0; + drone_detected_freqancy_start = 0; - fr_begin = (i == 0) ? fr_begin : fr_begin += range; - fr_end = fr_begin + RANGE_PER_PAGE; + if (diapazones_count == 0) + { + fr_begin = (i == 0) ? fr_begin : fr_begin += range; + fr_end = fr_begin + RANGE_PER_PAGE; + } + else + { + fr_begin = SCAN_DIAPAZONES[i] / 1000; + fr_end = SCAN_DIAPAZONES[i] % 1000; + range = fr_end - fr_begin; + } if (!ANIMATED_RELOAD || !single_page_scan) { @@ -525,7 +552,7 @@ void loop() freq = fr_begin + (range * ((float)x / STEPS)); radio.setFrequency(freq); // RSSI METHOD - // Gets RSSI (Recorded Signal Strength Indicator) + // Get RSSI (Recorded Signal Strength Indicator) // rssi = radio.getRSSI(false); // Serial.println(String(rssi) + "db"); #ifdef PRINT_SCAN_VALUES @@ -547,12 +574,12 @@ void loop() radio.spectralScanGetResult(result); detected = false; #ifdef FILTER_SPECTRUM_RESULTS - // Filter Elements without neighbors + // Filter Elements without neabors for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { if (result[y] && (result[y + 1] > 0 && result[y - 1] > 0)) { - //Filling the empty pixel between signals int the level < 27 (noise level) + // 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; @@ -573,10 +600,11 @@ void loop() #endif if (result[y] || y == drone_detection_level) { - // check if we should alarm about a drone presence + // check if we shuld alarm the dron if (filtered_result[y] == 1 && y <= drone_detection_level) { drone_detected = true; +#ifdef WATERFALL_ENABLED if (single_page_scan) { // Drone detection true for waterfall @@ -584,14 +612,14 @@ void loop() display.setColor(WHITE); display.setPixel(x, w); } - +#endif if (drone_detected_freqancy_start == 0) { drone_detected_freqancy_start = freq; } drone_detected_freqancy_end = freq; led_flag = true; - //If level is set to sensitive, start beeping every 10th frequency and shorter + // if level to sensetive doing beep every 10th freaqancy and shorter if (drone_detection_level <= 25) { if (detection_count == 1 && SOUND_ON) @@ -609,16 +637,17 @@ void loop() display.setPixel(x, 3); display.setPixel(x, 4); } - else if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[i][x][w] != true) +#ifdef WATERFALL_ENABLED + if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[i][x][w] != true) { - // If drone not found set dark pixel on the waterfall - // TODO: make something like scrolling up if possible + // if drone not found dark pixel on waterfall + // TODO: make somethin like scrolling up if possible waterfall[i][x][w] = false; display.setColor(BLACK); display.setPixel(x, w); display.setColor(WHITE); } - +#endif if (filtered_result[y] == 1) { // Set signal level pixel @@ -666,14 +695,14 @@ void loop() display.drawString(128 / 2, 0, String(freq)); display.display(); button_pressed_counter++; - if (button_pressed_counter > 200) + if (button_pressed_counter > 150) { digitalWrite(LED, HIGH); delay(150); digitalWrite(LED, LOW); } } - if (button_pressed_counter > 200) + if (button_pressed_counter > 150) { // Remove Curent Freqancy Text display.setTextAlignment(TEXT_ALIGN_CENTER); @@ -683,7 +712,7 @@ void loop() display.display(); break; } - if (button_pressed_counter > 50 && button_pressed_counter < 200) + if (button_pressed_counter > 50 && button_pressed_counter < 150) { // Visually confirm it's off so user releases button display.displayOff(); @@ -717,7 +746,7 @@ void loop() { w = WATERFALL_START; } - +#ifdef WATERFALL_ENABLED // Draw waterfall position cursor if (single_page_scan) { @@ -725,6 +754,7 @@ void loop() display.drawHorizontalLine(0, w, STEPS); display.setColor(WHITE); } +#endif display.display(); } From b8ce5cf4bdbf8bfd7bdc254aa27301651995b112 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Thu, 1 Aug 2024 12:00:15 -0700 Subject: [PATCH 36/36] Revert "add diapazones" --- src/main.cpp | 126 ++++++++++++++++++++------------------------------- 1 file changed, 48 insertions(+), 78 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 019172e..41d07f5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,12 +26,8 @@ // TODO: if % RANGE_PER_PAGE 1= 0 #define FREQ_END 950 -// Feature to scan diapazones. Other frequency settings will be ignored. -//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 on one page set RANGE_PER_PAGE = FREQ_END - 800 unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // TODO: Ignore power lines @@ -39,11 +35,11 @@ unsigned int RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN #define LOW_FILTER 3 #define FILTER_SPECTRUM_RESULTS true -// numbers of the spectrum screen lines = width of screen -// resolution of the scan limited by 128 pixel screan +// The number of the spectrum screen lines = width of screen +// Resolution of the scan is limited by 128-pixel screen #define STEPS 128 // Number of samples for each frequency scan. Fewer samples = better temporal resolution. -// if more tan 100 it can feez +// if more than 100 it can freez #define SAMPLES 100 //(scan time = 1294) #define RANGE (int)(FREQ_END - FREQ_BEGIN) @@ -76,7 +72,7 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #include #include -// This file contaiminins binary patch for the SX1262 +// This file contains a binary patch for the SX1262 #include "modules/SX126x/patches/SX126x_patch_scan.h" // Prints the scan measurement bins from the SX1262 in hex @@ -89,13 +85,13 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define MINOR_TICK_LENGTH 1 // WEIGHT of the x-asix line #define X_AXIS_WEIGHT 1 -// Height of the ploter area +// Height of the plotter area #define HEIGHT RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE // #define SCALE_TEXT_TOP (HEIGHT + X_AXIS_WEIGHT + MAJOR_TICK_LENGTH) #define STATUS_TEXT_TOP (64 - 10) -// Detection level from the 33 levels. Higher number is more sensative +// Detection level from the 33 levels. The higher number is more sensitive #define DEFAULT_DRONE_DETECTION_LEVEL 21 #define BUZZZER_PIN 41 @@ -104,7 +100,6 @@ unsigned int median_freqancy = FREQ_BEGIN + range_freqancy / 2; #define WATERFALL_ENABLED true #define WATERFALL_START 37 -#define OSD_ENABLED true #define DISABLE_PLOT_CHART false @@ -118,10 +113,10 @@ bool waterfall[10][STEPS][10]; unsigned short int scan_var = 0; // initialized flag bool initialized = false; -// Used as a Led Light and Buzzer/sount trigger +// Used as a Led Light and Buzzer/count trigger bool led_flag = false; bool first_run = false; -// drone tetection flag +// drone detection flag bool drone_detected = false; bool detected = false; unsigned int drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; @@ -139,7 +134,6 @@ unsigned int scan_start_time = 0; uint64_t start = 0; unsigned int x, y, i, w = 0; -unsigned int diapazones_count = 0; float freq = 0; int rssi = 0; @@ -156,14 +150,14 @@ void clearStatus() void clearPloter() { - // clear the scan plot rectangle + //Clear the scan plot rectangle display.setColor(BLACK); display.fillRect(0, 0, STEPS, HEIGHT); display.setColor(WHITE); } /** - * @brief Draws ticks on the display at regular whole intervals. + * @brief Draws ticks on display at regular intervals. * * @param every The interval between ticks in MHz. * @param length The length of each tick in pixels. @@ -186,7 +180,7 @@ void drawTicks(float every, int length) 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 + // TODO: (RANGE_PER_PAGE / every) * 2 has twice extra steps we need to figure out correct logic or minor ticks are 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 @@ -210,7 +204,7 @@ void drawTicks(float every, int length) } #ifdef MINOR_TICKS - // Fix two ticks togather + // Fix two ticks together if (tick_minor + 1 != tick && tick_minor - 1 != tick && tick_minor + 2 != tick && tick_minor - 2 != tick) { display.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); @@ -220,8 +214,12 @@ void drawTicks(float every, int length) { display.drawLine(tick_minor + 1, HEIGHT + X_AXIS_WEIGHT, tick_minor + 1, HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); } +//} #endif } + + // Draw Central Tick + // display.drawLine(128/2, HEIGHT + X_AXIS_WEIGHT, 128/2, HEIGHT + X_AXIS_WEIGHT + 5); } /** @@ -231,11 +229,11 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) { if (!initialized) { - // begining and end ticks + // Start and end ticks display.fillRect(0, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH + 1); display.fillRect(126, HEIGHT + X_AXIS_WEIGHT, 2, MAJOR_TICK_LENGTH + 1); - // drone detection level + // Drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, 0, String(drone_detection_level)); } @@ -247,18 +245,18 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) display.fillRect(0, SCALE_TEXT_TOP + 1, 128, 12); display.setColor(WHITE); - // drone detection level + // Drone detection level display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, 0, String(drone_detection_level)); - // frequency start + // Frequency start display.setTextAlignment(TEXT_ALIGN_LEFT); display.drawString(0, SCALE_TEXT_TOP, (begin == 0) ? String(FREQ_BEGIN) : String(begin)); display.setTextAlignment(TEXT_ALIGN_CENTER); display.drawString(128 / 2, SCALE_TEXT_TOP, (begin == 0) ? String(median_freqancy) : String(begin + ((end - begin) / 2))); - // frequency end + // Frequency end display.setTextAlignment(TEXT_ALIGN_RIGHT); display.drawString(128, SCALE_TEXT_TOP, (end == 0) ? String(FREQ_END) : String(end)); } @@ -313,14 +311,11 @@ void displayDecorate(int begin = 0, int end = 0, bool redraw = false) display.drawString(start_scan_text, STATUS_TEXT_TOP, String(drone_detected_freqancy_start) + ">RF<" + String(drone_detected_freqancy_end)); } - if (diapazones_count == 0) - { - display.setTextAlignment(TEXT_ALIGN_LEFT); - display.drawString(0, STATUS_TEXT_TOP, String(FREQ_BEGIN)); + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.drawString(0, STATUS_TEXT_TOP, String(FREQ_BEGIN)); - display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(128, STATUS_TEXT_TOP, String(FREQ_END)); - } + display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.drawString(128, STATUS_TEXT_TOP, String(FREQ_END)); if (!initialized) { @@ -373,7 +368,7 @@ void setup() RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); // and disable the data shaping RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); - both.println("Starting scaning..."); + both.println("Starting scanning..."); float vbat = heltec_vbat(); both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); delay(300); @@ -443,7 +438,7 @@ void setup() } display.clear(); - // waterfall start line y-asix + // waterfall start line y-axis w = WATERFALL_START; } @@ -473,8 +468,8 @@ void loop() fr_begin = FREQ_BEGIN; fr_end = fr_begin; - // 50 is a single screen range - // TODO:Make 50 as a variable with the option show full range + // 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; @@ -493,36 +488,14 @@ void loop() single_page_scan = false; } - diapazones_count = 0; - - for (int diapazone : SCAN_DIAPAZONES) - { - diapazones_count++; - } - - if (diapazones_count > 0) - { - iterations = diapazones_count; - single_page_scan = false; - } - - // Iterateing by small ranges by 50 Mhz each pixel is 0.4 Mhz + // Iterating by small ranges of 50 Mhz, each pixel is 0.4 Mhz for (i = 0; i < iterations; i++) { range = RANGE_PER_PAGE; - drone_detected_freqancy_start = 0; + drone_detected_freqancy_start == 0; - if (diapazones_count == 0) - { - fr_begin = (i == 0) ? fr_begin : fr_begin += range; - fr_end = fr_begin + RANGE_PER_PAGE; - } - else - { - fr_begin = SCAN_DIAPAZONES[i] / 1000; - fr_end = SCAN_DIAPAZONES[i] % 1000; - range = fr_end - fr_begin; - } + fr_begin = (i == 0) ? fr_begin : fr_begin += range; + fr_end = fr_begin + RANGE_PER_PAGE; if (!ANIMATED_RELOAD || !single_page_scan) { @@ -552,7 +525,7 @@ void loop() freq = fr_begin + (range * ((float)x / STEPS)); radio.setFrequency(freq); // RSSI METHOD - // Get RSSI (Recorded Signal Strength Indicator) + // Gets RSSI (Recorded Signal Strength Indicator) // rssi = radio.getRSSI(false); // Serial.println(String(rssi) + "db"); #ifdef PRINT_SCAN_VALUES @@ -574,12 +547,12 @@ void loop() radio.spectralScanGetResult(result); detected = false; #ifdef FILTER_SPECTRUM_RESULTS - // Filter Elements without neabors + // Filter Elements without neighbors for (y = 1; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { if (result[y] && (result[y + 1] > 0 && result[y - 1] > 0)) { - // filling the empty pixel between signals int the level < 27 (noise level) + //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; @@ -600,11 +573,10 @@ void loop() #endif if (result[y] || y == drone_detection_level) { - // check if we shuld alarm the dron + // 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 @@ -612,14 +584,14 @@ void loop() display.setColor(WHITE); display.setPixel(x, w); } -#endif + if (drone_detected_freqancy_start == 0) { drone_detected_freqancy_start = freq; } drone_detected_freqancy_end = freq; led_flag = true; - // if level to sensetive doing beep every 10th freaqancy and shorter + //If level is set to sensitive, start beeping every 10th frequency and shorter if (drone_detection_level <= 25) { if (detection_count == 1 && SOUND_ON) @@ -637,17 +609,16 @@ void loop() display.setPixel(x, 3); display.setPixel(x, 4); } -#ifdef WATERFALL_ENABLED - if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[i][x][w] != true) + else if (filtered_result[y] == 1 && y > drone_detection_level && single_page_scan && waterfall[i][x][w] != true) { - // if drone not found dark pixel on waterfall - // TODO: make somethin like scrolling up if possible + // If drone not found set dark pixel on the waterfall + // TODO: make something like scrolling up if possible waterfall[i][x][w] = false; display.setColor(BLACK); display.setPixel(x, w); display.setColor(WHITE); } -#endif + if (filtered_result[y] == 1) { // Set signal level pixel @@ -695,14 +666,14 @@ void loop() display.drawString(128 / 2, 0, String(freq)); display.display(); button_pressed_counter++; - if (button_pressed_counter > 150) + if (button_pressed_counter > 200) { digitalWrite(LED, HIGH); delay(150); digitalWrite(LED, LOW); } } - if (button_pressed_counter > 150) + if (button_pressed_counter > 200) { // Remove Curent Freqancy Text display.setTextAlignment(TEXT_ALIGN_CENTER); @@ -712,7 +683,7 @@ void loop() display.display(); break; } - if (button_pressed_counter > 50 && button_pressed_counter < 150) + if (button_pressed_counter > 50 && button_pressed_counter < 200) { // Visually confirm it's off so user releases button display.displayOff(); @@ -746,7 +717,7 @@ void loop() { w = WATERFALL_START; } -#ifdef WATERFALL_ENABLED + // Draw waterfall position cursor if (single_page_scan) { @@ -754,7 +725,6 @@ void loop() display.drawHorizontalLine(0, w, STEPS); display.setColor(WHITE); } -#endif display.display(); }