From 14d8be069d8897eead25bcb2bc4ec337f7b7df84 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sat, 24 Aug 2024 01:01:33 -0700 Subject: [PATCH 01/17] e-ink --- elink_src/images.h | 102 ++++++++++ elink_src/main.cpp | 456 +++++++++++++++++++++++++++++++++++++++++++++ include/ui.h | 9 +- platformio.ini | 34 +++- src/main.cpp | 58 +++--- src/ui.cpp | 20 +- 6 files changed, 651 insertions(+), 28 deletions(-) create mode 100644 elink_src/images.h create mode 100644 elink_src/main.cpp diff --git a/elink_src/images.h b/elink_src/images.h new file mode 100644 index 0000000..e33c6c3 --- /dev/null +++ b/elink_src/images.h @@ -0,0 +1,102 @@ +#define WiFi_Logo_width 60 +#define WiFi_Logo_height 36 +const uint8_t WiFi_Logo_bits[] PROGMEM = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, + 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, + 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF, + 0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00, 0xC0, 0xFF, + 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C, 0xFC, 0x77, 0x08, 0x00, + 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00, 0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, + 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, + 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, + 0x70, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, + 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C, 0x1C, 0x70, + 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00, 0xC0, 0xFF, 0xFF, 0x1F, + 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, + 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, + 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, + 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, + 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +const unsigned char epd_bitmap_ucog[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x10, 0x84, 0xC3, 0x81, 0x03, 0x00, 0x60, 0x00, 0xCC, 0x07, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x30, 0xE6, 0xF3, 0xE3, 0x07, 0x00, 0x60, 0x00, 0x0C, 0x3E, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x30, 0x66, 0x10, 0x36, 0x00, 0x00, 0x60, 0x00, 0x06, 0xF8, + 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x30, 0x26, 0x18, 0x36, 0x00, 0x00, 0x60, 0x00, + 0x07, 0xE0, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x26, 0x18, 0x36, 0x07, 0x00, + 0x60, 0x00, 0x03, 0x00, 0x1F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x30, 0x26, 0x18, 0x36, + 0x06, 0x00, 0x60, 0x80, 0x01, 0x00, 0x7C, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x30, 0x66, + 0x38, 0x76, 0x06, 0x0C, 0x60, 0xC0, 0x01, 0x00, 0xF0, 0x01, 0x78, 0x00, 0x00, 0x00, + 0xE0, 0xE3, 0xF3, 0xE3, 0x07, 0x0E, 0x60, 0xC0, 0x03, 0x00, 0x80, 0x0F, 0x1C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x60, 0xE0, 0x07, 0x00, 0x00, 0x3E, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x60, 0x60, 0x0E, 0x00, + 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x60, 0x70, + 0x1C, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, + 0x60, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x60, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x00, 0xF0, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xFC, 0x0D, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x67, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x61, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, + 0x60, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x60, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7E, 0xE0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x67, 0xE0, 0x83, 0x03, 0x00, 0x00, 0xE0, 0xFF, 0xE1, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x63, 0x60, 0x07, 0x07, 0x00, 0xC0, 0xFF, + 0x03, 0x80, 0x03, 0x00, 0x00, 0x08, 0x00, 0x02, 0xF0, 0x61, 0x60, 0x1C, 0x1F, 0x80, + 0xFF, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xF8, + 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x18, 0x00, 0x02, 0xF0, 0x7F, + 0x60, 0xDC, 0x1F, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xD0, 0x61, 0x60, 0x07, 0x0F, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x90, 0x67, 0xE0, 0x83, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xC1, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xE0, 0xC1, 0x01, 0x00, 0x00, 0x00, 0xF8, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x61, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x67, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xEE, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1C, 0x00, 0xFC, 0x0D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xF0, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x18, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x60, 0x30, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x60, 0x70, + 0x3C, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, + 0x60, 0x60, 0x1E, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x07, 0x60, 0xE0, 0x0F, 0x00, 0x00, 0x3E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x03, 0x00, 0x0F, 0x60, 0xC0, 0x03, 0x00, 0x80, 0x0F, 0x1C, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x01, 0x07, 0x00, 0x0C, 0x60, 0xC0, 0x01, 0x00, 0xF0, 0x01, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x81, 0x05, 0x00, 0x08, 0x60, 0xC0, 0x01, 0x00, 0x7C, 0x00, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, + 0x1F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x0C, 0x00, 0x00, 0x60, 0x00, + 0x07, 0xE0, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x0F, 0x00, 0x00, + 0x60, 0x00, 0x06, 0xF8, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1F, + 0x00, 0x00, 0x60, 0x00, 0x0E, 0x3E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x80, + 0x67, 0x18, 0x00, 0x00, 0x60, 0x00, 0xCC, 0x07, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0xE0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xFC, 0x01, 0x00, 0x00, + 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, +}; diff --git a/elink_src/main.cpp b/elink_src/main.cpp new file mode 100644 index 0000000..4829431 --- /dev/null +++ b/elink_src/main.cpp @@ -0,0 +1,456 @@ +/* Heltec Automation Ink screen example + * NOTE!!!: to upload we neew code you need to press button BOOT and RESET or you will + * have serial error. After upload you need reset device... + * + * Function: + * 1. Ink screen full brush demonstration + * + * Description: + * 1.Inherited from ssd1306 for drawing points, lines, and functions + * + * */ + +#include "HT_DEPG0290BxS800FxX_BW.h" +#include "global_config.h" +#include "images.h" +#include "ui.h" +#include + +// Disabling default lib display +#define HELTEC_NO_DISPLAY +#define DISPLAY_WIDTH 296 +#define DISPLAY_HEIGHT 128 +// Without this line Lora Radio doesn't work +#define ARDUINO_heltec_wifi_32_lora_V3 +#include "heltec_unofficial.h" +#include "modules/SX126x/patches/SX126x_patch_scan.h" + +// <--- Spectrum display Varriables START +#define SCAN_METHOD +#define METHOD_SPECTRAL +// numbers of the spectrum screan lines = width of screan +#define STEPS 296 // 128 +// Number of samples for each scan. Fewer samples = better temporal resolution. +#define MAX_POWER_LEVELS 33 +// multiplies STEPS * N to increase scan resolution. +#define SCAN_RBW_FACTOR 1 // 2 +// Print spectrum values pixels at once or by line +bool ANIMATED_RELOAD = false; +// Remove reading without neighbors +#define FILTER_SPECTRUM_RESULTS true +#define FILTER_SAMPLES_MIN +constexpr bool DRAW_DETECTION_TICKS = true; +// Number of samples for each frequency scan. Fewer samples = better temporal resolution. +// if more than 100 it can freez +#define SAMPLES 35 //(scan time = 1294) +// number of samples for RSSI method +#define SAMPLES_RSSI 30 // 21 // + +#define FREQ_BEGIN 750 + +#define RANGE (int)(FREQ_END - FREQ_BEGIN) + +#define SINGLE_STEP (float)(RANGE / (STEPS * SCAN_RBW_FACTOR)) + +uint64_t range = (int)(FREQ_END - FREQ_BEGIN); +uint64_t fr_begin = FREQ_BEGIN; +uint64_t fr_end = FREQ_BEGIN; + +// Feature to scan diapazones. Other frequency settings will be ignored. +// int SCAN_RANGES[] = {850890, 920950}; +int SCAN_RANGES[] = {}; + +// MHZ per page +// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 +// uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN + +// Override or e-ink +uint64_t RANGE_PER_PAGE = FREQ_BEGIN + DISPLAY_WIDTH; + +uint64_t iterations = RANGE / RANGE_PER_PAGE; + +// uint64_t range_frequency = FREQ_END - FREQ_BEGIN; +uint64_t median_frequency = FREQ_BEGIN + FREQ_END - FREQ_BEGIN / 2; + +// #define DISABLE_PLOT_CHART false // unused + +// Array to store the scan results +uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t result_display_set[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t result_detections[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; + +// Waterfall array +bool waterfall[STEPS], detected_y[STEPS]; // 20 - ??? steps of the waterfall + +// global variable + +// Used as a Led Light and Buzzer/count trigger +bool first_run, new_pixel, detected_x = false; +// drone detection flag +bool detected = false; +uint64_t drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; +uint64_t drone_detected_frequency_start = 0; +uint64_t drone_detected_frequency_end = 0; +uint64_t detection_count = 0; +bool single_page_scan = false; +bool SOUND_ON = false; + +// #define PRINT_DEBUG +#define PRINT_PROFILE_TIME + +#ifdef PRINT_PROFILE_TIME +uint64_t loop_start = 0; +uint64_t loop_time = 0; +uint64_t scan_time = 0; +uint64_t scan_start_time = 0; +#endif + +uint64_t x, y, range_item, w = WATERFALL_START, i = 0; +int osd_x = 1, osd_y = 2, col = 0, max_bin = 32; +uint64_t ranges_count = 0; + +float freq = 0; +int rssi = 0; +int state = 0; + +#ifdef METHOD_SPECTRAL +constexpr int samples = SAMPLES; +#endif +#ifdef METHOD_RSSI +constexpr int samples = SAMPLES_RSSI; +#endif + +uint8_t result_index = 0; +uint8_t button_pressed_counter = 0; +uint64_t loop_cnt = 0; +// <--- Spectrum display Varriables END + +// Initialize the display +DEPG0290BxS800FxX_BW display(5, 4, 3, 6, 2, 1, -1, + 6000000); // rst,dc,cs,busy,sck,mosi,miso,frequency +typedef void (*Demo)(void); +/* screen rotation + * ANGLE_0_DEGREE + * ANGLE_90_DEGREE + * ANGLE_180_DEGREE + * ANGLE_270_DEGREE + */ +#define DIRECTION ANGLE_0_DEGREE +int demoMode = 0; + +void init_radio() +{ + // initialize SX1262 FSK modem at the initial frequency + Serial.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 + Serial.println("Upload SX1262 patch"); + + // Upload binary patch into the SX126x device RAM. Patch is needed to e.g., + // enable spectral scan and must be uploaded again on every power cycle. + RADIOLIB_OR_HALT(radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan))); + // configure scan bandwidth and disable the data shaping + + Serial.println("Setting up radio"); + RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); + + // and disable the data shaping + RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); + Serial.println("Starting scanning..."); + + // calibrate only once ,,, at startup + // TODO: check documentation (9.2.1) if we must calibrate in certain ranges + radio.setFrequency(FREQ_BEGIN, true); + delay(50); +} + +#define HEIGHT 4 +DEPG0290BxS800FxX_BW display_instance = display; +/** + * @brief Draws ticks on the display at regular whole intervals. + * + * @param every The interval between ticks in MHz. + * @param length The length of each tick in pixels. + */ +void drawTicks(float every, int length) +{ + int first_tick; + bool correction; + int pixels_per_step; + int correction_number; + int tick; + int tick_minor; + int median; + + first_tick = 0; + //+ (every - (fr_begin - (int)(fr_begin / every) * every)); + /*if (first_tick < fr_begin) + { + first_tick += every; + }*/ + correction = false; + pixels_per_step = STEPS / (RANGE_PER_PAGE / every); + if (STEPS / RANGE_PER_PAGE != 0) + { + correction = true; + } + correction_number = STEPS - (int)(pixels_per_step * (RANGE_PER_PAGE / every)); + tick = 0; + tick_minor = 0; + median = (RANGE_PER_PAGE / every) / 2; + // TODO: (RANGE_PER_PAGE / every) + // * 2 has twice extra steps we need to figureout correct logic or minor + // ticks is not showing to the end + for (int t = 0; t <= (RANGE_PER_PAGE / every) * 2; t++) + { + // fix if pixels per step is not int and we have shift + if (correction && t % 2 != 0 && correction_number > 1) + { + // pixels_per_step++; + correction_number--; + } + tick += pixels_per_step; + tick_minor = tick / 2; + if (tick <= 128 - 3) + { + display_instance.drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick, + HEIGHT + X_AXIS_WEIGHT + length); + // Central tick + if (tick > (128 / 2) - 3 && tick < (128 / 2) + 3) + { + display_instance.drawLine(tick + 1, HEIGHT + X_AXIS_WEIGHT, tick + 1, + HEIGHT + X_AXIS_WEIGHT + length); + } + } +#ifdef MINOR_TICKS + // Fix two ticks together + if ((tick_minor + 1 != tick) && (tick_minor - 1 != tick) && + (tick_minor + 2 != tick) && (tick_minor - 2 != tick)) + { + display_instance.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, + HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); + } + // Central tick + if (tick_minor > (128 / 2) - 3 && tick_minor < (128 / 2) + 3) + { + display_instance.drawLine(tick_minor + 1, HEIGHT + X_AXIS_WEIGHT, + tick_minor + 1, + HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); + } +#endif + } +} + +void drawFontFaceDemo() +{ + // Font Demo1 + // create more fonts at http://oleddisplay.squix.ch/ + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.setFont(ArialMT_Plain_10); + display.drawString(0, 0, "Spectrum Analizer Lora SA"); + display.setFont(ArialMT_Plain_16); + display.drawString(0, 10, "SX 1262"); + display.setFont(ArialMT_Plain_24); + display.drawString(0, 26, "e-ink display"); +} +void drawTextFlowDemo() +{ + display.setFont(ArialMT_Plain_10); + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.drawStringMaxWidth( + 0, 0, DISPLAY_HEIGHT, + "Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy " + "eirmod tempor invidunt ut labore."); +} +void drawTextAlignmentDemo() +{ + // Text alignment demo + char str[30]; + int x = 0; + int y = 0; + display.setFont(ArialMT_Plain_10); + // The coordinates define the left starting point of the text + display.setTextAlignment(TEXT_ALIGN_LEFT); + display.drawString(x, y, "Left aligned (0,0)"); + // The coordinates define the center of the text + display.setTextAlignment(TEXT_ALIGN_CENTER); + x = display.width() / 2; + y = display.height() / 2 - 5; + sprintf(str, "Center aligned (%d,%d)", x, y); + display.drawString(x, y, str); + // The coordinates define the right end of the text + display.setTextAlignment(TEXT_ALIGN_RIGHT); + x = display.width(); + y = display.height() - 12; + sprintf(str, "Right aligned (%d,%d)", x, y); + display.drawString(x, y, str); +} +void drawRectDemo() +{ + // Draw a pixel at given position + for (int i = 0; i < 10; i++) + { + display.setPixel(i, i); + display.setPixel(10 - i, i); + } + display.drawRect(12, 12, 20, 20); + // Fill the rectangle + display.fillRect(14, 14, 17, 17); + // Draw a line horizontally + display.drawHorizontalLine(0, 40, 20); + // Draw a line horizontally + display.drawVerticalLine(40, 0, 20); +} +void drawCircleDemo() +{ + int x = display.width() / 4; + int y = display.height() / 2; + for (int i = 1; i < 8; i++) + { + display.setColor(WHITE); + display.drawCircle(x, y, i * 3); + if (i % 2 == 0) + { + display.setColor(BLACK); + } + int x = display.width() / 4 * 3; + display.fillCircle(x, y, 32 - i * 3); + } +} +void drawImageDemo() +{ + // see http://blog.squix.org/2015/05/esp8266-nodemcu-how-to-create-xbm.html + // on how to create xbm files + int x = display.width() / 2 - WiFi_Logo_width / 2; + int y = display.height() / 2 - WiFi_Logo_height / 2; + display.drawXbm(x, y, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits); +} +void VextON(void) +{ + pinMode(18, OUTPUT); + digitalWrite(18, HIGH); +} +void VextOFF(void) // Vext default OFF +{ + pinMode(18, OUTPUT); + digitalWrite(18, LOW); +} + +int lower_level = 108; +int up_level = 40; +int rssiToPix(int rssi) +{ + // Bigger is lower signal + if (abs(rssi) >= lower_level) + { + return lower_level - 1; + } + if (abs(rssi) <= up_level) + { + return up_level; + } + return abs(rssi); +} + +Demo demos[] = {drawFontFaceDemo, drawTextFlowDemo, drawTextAlignmentDemo, + drawRectDemo, drawCircleDemo, drawImageDemo}; +int demoLength = (sizeof(demos) / sizeof(Demo)); +long timeSinceLastModeSwitch = 0; + +float fr = FREQ_BEGIN; +int rssi2 = 0; +int x1 = 0, y2 = 0; +unsigned int loop_counter = 1; +void loop() +{ + radio.setFrequency(fr, false); // false = no calibration need here + for (int i = 0; i < SAMPLES_RSSI; i++) + { + if (i % 2 == 0) + radio.setFrequency((float)fr + 0.33, false); + else if (i % 3 == 0) + radio.setFrequency((float)fr + 0.33, false); + rssi2 = radio.getRSSI(false); + if (rssi2 > lower_level) + continue; + // Serial.println(String(fr) + ":" + String(rssi2)); + // display.drawString(x1, (int)y2, String(fr) + ":" + String(rssi2)); + display.setPixel(x1, rssiToPix(rssi2)); + } + + fr++; + x1++; + if (x1 >= STEPS) + { + if (loop_counter > STEPS * 5) + { + loop_counter = 0; + // Draw a line horizontally + display.drawHorizontalLine(0, lower_level + 1, DISPLAY_WIDTH); + for (int x = 0; x < DISPLAY_WIDTH; x++) + { + if (x % (DISPLAY_WIDTH / 2) == 0 && x > 5) + { + display.drawVerticalLine(x, lower_level + 1, 8); + display.drawVerticalLine(x - 1, lower_level + 1, 8); + display.drawVerticalLine(x + 1, lower_level + 1, 8); + } + if (x % 10 == 0 || x == 0) + display.drawVerticalLine(x, lower_level + 1, 6); + if (x % 5 == 0) + display.drawVerticalLine(x, lower_level + 1, 3); + } + display.setFont(ArialMT_Plain_10); + + display.drawString(1, DISPLAY_HEIGHT - 10, String(FREQ_BEGIN)); + display.drawString(DISPLAY_WIDTH - 24, DISPLAY_HEIGHT - 10, String(fr)); + display.drawString((DISPLAY_WIDTH / 2) - 10, DISPLAY_HEIGHT - 10, + String(FREQ_BEGIN + ((fr - FREQ_BEGIN) / 2))); + + display.display(); + // delay(2000); + if (loop_counter == 0) + { + display.clear(); + } + } + fr = FREQ_BEGIN; + x1 = 0; + } + loop_counter++; +} + +void setup() +{ + // Initialising the UI will init the display too. + display.init(); + display.screenRotate(DIRECTION); + display.setFont(ArialMT_Plain_10); + display.clear(); + display.drawXbm((DISPLAY_WIDTH / 3) - 10, DISPLAY_HEIGHT / 4, 128, 60, + epd_bitmap_ucog); + display.display(); + delay(2000); + display.clear(); + Serial.begin(115200); + w = WATERFALL_START; + init_radio(); + state = radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_NONE); + if (state != RADIOLIB_ERR_NONE) + { + Serial.print(F("Failed to start receive mode, error code: ")); + Serial.println(state); + } + heltec_setup(); + Serial.println(); + Serial.println(); + drawFontFaceDemo(); + display.display(); + delay(1000); + VextON(); + display.clear(); +} diff --git a/include/ui.h b/include/ui.h index 2dcaa96..2ca7525 100644 --- a/include/ui.h +++ b/include/ui.h @@ -1,9 +1,12 @@ - #pragma once +#ifdef Vision_Master_E290 +#include "HT_DEPG0290BxS800FxX_BW.h" +#else #include "OLEDDisplayUi.h" #include "SSD1306Wire.h" #include +#endif // #include @@ -29,7 +32,11 @@ #define SCREEN_HEIGHT 64 // ???? not used // publish functions +#ifdef Vision_Master_E290 +extern void UI_Init(DEPG0290BxS800FxX_BW *); +#else extern void UI_Init(SSD1306Wire *); +#endif extern void UI_displayDecorate(int, int, bool); extern void UI_setLedFlag(bool); extern void UI_clearPlotter(void); diff --git a/platformio.ini b/platformio.ini index 5c24979..634c9a4 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,6 +8,12 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html +[platformio] +;; for env:vision-master-e290 +;;src_dir = elink_src +;; for env:heltec_wifi_lora_32_V3 +;;src_dir = src + [env:heltec_wifi_lora_32_V3] platform = espressif32 board = heltec_wifi_lora_32_V3 @@ -15,5 +21,31 @@ framework = arduino upload_speed = 115200 monitor_speed = 115200 board_build.f_cpu = 240000000 -lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 +lib_deps = + ropg/Heltec_ESP32_LoRa_v3@^0.9.1 build_flags = -DHELTEC_POWER_BUTTON + +[env:vision-master-e290] +platform = espressif32 +board = heltec_wifi_lora_32_V3 +framework = arduino +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder +board_upload.use_1200bps_touch = true +build_flags = + -D HELTEC_BOARD=37 + -D SLOW_CLK_TPYE=1 + -D ARDUINO_USB_CDC_ON_BOOT=1 + -D LoRaWAN_DEBUG_LEVEL=0 + -D E290 + -D ESP32 + -D Vision_Master_E290 + -D RADIOLIB_EXCLUDE_CC1101=1 + -D RADIOLIB_EXCLUDE_LR11x0=1 +lib_deps = + SPI + Wire + adafruit/Adafruit BusIO @ 1.9.6 + https://github.com/HelTecAutomation/Heltec_ESP32/ + adafruit/Adafruit GFX Library@^1.11.10 + ropg/Heltec_ESP32_LoRa_v3@^0.9.1 diff --git a/src/main.cpp b/src/main.cpp index 6d3d619..be47549 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,6 +21,8 @@ https://jgromes.github.io/RadioLib/ */ +// #define HELTEC_NO_DISPLAY + #include #include // This file contains a binary patch for the SX1262 @@ -241,7 +243,7 @@ uint64_t scan_time = 0; uint64_t scan_start_time = 0; #endif -uint64_t x, y, range_item, w, i = 0; +uint64_t x, y, range_item, w = WATERFALL_START, i = 0; int osd_x = 1, osd_y = 2, col = 0, max_bin = 32; uint64_t ranges_count = 0; @@ -473,6 +475,35 @@ void osdProcess() } #endif +void init_radio() +{ + // initialize SX1262 FSK modem at the initial frequency + both.println("Init radio"); + RADIOLIB_OR_HALT(radio.beginFSK(FREQ_BEGIN)); + + // upload a patch to the SX1262 to enable spectral scan + // NOTE: this patch is uploaded into volatile memory, + // and must be re-uploaded on every power up + both.println("Upload SX1262 patch"); + + // Upload binary patch into the SX126x device RAM. Patch is needed to e.g., + // enable spectral scan and must be uploaded again on every power cycle. + RADIOLIB_OR_HALT(radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan))); + // configure scan bandwidth and disable the data shaping + + both.println("Setting up radio"); + RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); + + // and disable the data shaping + RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); + both.println("Starting scanning..."); + + // calibrate only once ,,, at startup + // TODO: check documentation (9.2.1) if we must calibrate in certain ranges + radio.setFrequency(FREQ_BEGIN, true); + delay(50); +} + void setup(void) { // LED brightness @@ -517,26 +548,8 @@ void setup(void) } } - // initialize SX1262 FSK modem at the initial frequency - both.println("Init radio"); - RADIOLIB_OR_HALT(radio.beginFSK(FREQ_BEGIN)); + init_radio(); - // upload a patch to the SX1262 to enable spectral scan - // NOTE: this patch is uploaded into volatile memory, - // and must be re-uploaded on every power up - both.println("Upload SX1262 patch"); - - // Upload binary patch into the SX126x device RAM. Patch is needed to e.g., - // enable spectral scan and must be uploaded again on every power cycle. - RADIOLIB_OR_HALT(radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan))); - // configure scan bandwidth and disable the data shaping - - both.println("Setting up radio"); - RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); - - // and disable the data shaping - RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); - both.println("Starting scanning..."); vbat = heltec_vbat(); both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); #ifdef WIFI_SCANNING_ENABLED @@ -610,11 +623,6 @@ void setup(void) display.clear(); Serial.println(); - // calibrate only once ,,, at startup - // TODO: check documentation (9.2.1) if we must calibrate in certain ranges - radio.setFrequency(FREQ_BEGIN, true); - delay(50); - #ifdef METHOD_RSSI // TODO: try RADIOLIB_SX126X_RX_TIMEOUT_INF state = radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_NONE); diff --git a/src/ui.cpp b/src/ui.cpp index 2760253..48a7bf1 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -18,9 +18,12 @@ static bool ui_initialized = false; static bool led_flag = false; static unsigned short int scan_progress_count = 0; +#ifdef Vision_Master_E290 +static DEPG0290BxS800FxX_BW *display_instance; +#else //(0x3c, SDA_OLED, SCL_OLED, DISPLAY_GEOMETRY); static SSD1306Wire *display_instance; - +#endif // temporary dirty import ... to be solved durring upcoming refactoring extern unsigned int drone_detection_level; extern unsigned int RANGE_PER_PAGE; @@ -37,6 +40,7 @@ extern unsigned int range_item; extern uint64_t loop_time; +#ifndef Vision_Master_E290 void UI_Init(SSD1306Wire *display_ptr) { // init pointer to display instance. @@ -47,6 +51,20 @@ void UI_Init(SSD1306Wire *display_ptr) display_instance->drawXbm(0, 2, 128, 64, epd_bitmap_ucog); display_instance->display(); } +#endif + +#ifdef Vision_Master_E290 +void UI_Init(DEPG0290BxS800FxX_BW *display_ptr) +{ + // init pointer to display instance. + display_instance = display_ptr; + // check for null ??? + display_instance->clear(); + // draw the UCOG welcome logo + display_instance->drawXbm(0, 2, 128, 64, epd_bitmap_ucog); + display_instance->display(); +} +#endif void UI_setLedFlag(bool new_status) { led_flag = new_status; } From 0fb87c657939a199e44fce0bf7b4ddd1f21de0c7 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sat, 24 Aug 2024 12:25:57 -0700 Subject: [PATCH 02/17] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index d0a843e..cddbbe7 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,16 @@ Heltec ESP32 Lora V3: +Or Heltec Wireless Stick. The same hardware but without or with a smaller display +https://heltec.org/project/wireless-stick-v3/ +https://heltec.org/project/wireless-stick-lite-v2/ + +Heltec Vision Master E290 - With large e-ink display 293x128: + +https://heltec.org/project/vision-master-e290/ +https://www.aliexpress.us/item/3256807048047234.html +**NOTE: to upload a new code, you need to press BOOT + RESET button** + Battery with Wire JT connector : From 183a7c4ea307ef7b62c9f28b2f2734bef857add0 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sun, 25 Aug 2024 15:34:16 -0700 Subject: [PATCH 03/17] Update README.md --- README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index cddbbe7..f1b3dfc 100644 --- a/README.md +++ b/README.md @@ -147,8 +147,11 @@ If less, ESP32 will turn off. Fast pressing(less than 0.5 second) P button chang 1. Install VSCode 2. install Platform.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 +3. Connect ESP32 to USB. Install USB CP2101 drivers for Windows or other OS + https://docs.heltec.org/general/establish_serial_connection.html#for-windows + https://www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers?tab=downloads + +5. Clone this Git Repo or download zip of the sources ![image](https://github.com/user-attachments/assets/971b6592-3b71-414c-971c-2ecd20f0f0b7) ```bash @@ -157,19 +160,19 @@ If less, ESP32 will turn off. Fast pressing(less than 0.5 second) P button chang NOTE: in you case name will be Just LoraSA. I have LoraSA2 because I already have LoraSA folder -5. Open the Project with the VS code Platform.IO +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) -6. Select Proper Environment +7. Select Proper Environment ![image](https://github.com/user-attachments/assets/a9c6557b-a387-4457-b59b-b3d7242d2826) -7. Select ESP32 USB Device to program +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. -8. Program your ESP32 +9. Program your ESP32 ![image](https://github.com/user-attachments/assets/9e67afd8-0522-4a96-82dc-8e1cdb32add5) -9. Wait until you are done with the compilation and upload. +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. From 6ca43b68eaca1295c9c07f9cb8b46cb512c57cd9 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sun, 25 Aug 2024 15:40:27 -0700 Subject: [PATCH 04/17] some fixes --- include/global_config.h | 2 +- src/main.cpp | 17 ++++++----------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/include/global_config.h b/include/global_config.h index 115bf4a..ded70ae 100644 --- a/include/global_config.h +++ b/include/global_config.h @@ -12,7 +12,7 @@ #define BANDWIDTH 467.0 // Detection level from the 33 levels. The higher number is more sensitive -#define DEFAULT_DRONE_DETECTION_LEVEL 20 +#define DEFAULT_DRONE_DETECTION_LEVEL 18 #define BUZZER_PIN 41 diff --git a/src/main.cpp b/src/main.cpp index 6d3d619..4fcf4f8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -25,7 +25,7 @@ #include // This file contains a binary patch for the SX1262 #include "modules/SX126x/patches/SX126x_patch_scan.h" -// #define OSD_ENABLED true +// #define OSD_ENABLED true // #define WIFI_SCANNING_ENABLED true // #define BT_SCANNING_ENABLED true @@ -41,9 +41,9 @@ bool scanFinished = true; uint64_t wf_start = 0; uint64_t bt_start = 0; -#ifndef OSD_ENABLED -#include "DFRobot_OSD.h" #define MAX_POWER_LEVELS 33 +#ifdef OSD_ENABLED +#include "DFRobot_OSD.h" #define OSD_SIDE_BAR true static constexpr uint16_t levels[10] = { @@ -380,14 +380,14 @@ unsigned short selectFreqChar(int bin, int start_level = 0) void osdPrintSignalLevelChart(int col, int signal_value) { // Third line - if (signal_value <= 9) + if (signal_value <= 9 && signal_value <= drone_detection_level) { osd.displayChar(13, col + 2, 0x100); osd.displayChar(14, col + 2, 0x100); osd.displayChar(12, col + 2, selectFreqChar(signal_value, drone_detection_level)); } // Second line - else if (signal_value < 19) + else if (signal_value < 19 && signal_value <= drone_detection_level) { osd.displayChar(12, col + 2, 0x100); osd.displayChar(14, col + 2, 0x100); @@ -419,7 +419,7 @@ void osdProcess() // filter if (result[i] > 0 #if FILTER_SPECTRUM_RESULTS - && ((result[i + 1] != 0 && result[i + 2] != 0) || result[i - 1] != 0) + && ((result[i + 1] != 0 /*&& result[i + 2] != 0*/) || result[i - 1] != 0) #endif ) { @@ -443,11 +443,6 @@ void osdProcess() // Going to the next OSD step if (x % osd_steps == 0 && col < OSD_WIDTH) { - // some issue when median = 0 - if (max_step_range == 0) - { - max_step_range = OSD_WIDTH - 1; - } // OSD SIDE BAR with frequency log #ifdef OSD_SIDE_BAR { From aa30042beceb4b57b656b522365152926e7f1a14 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Mon, 26 Aug 2024 00:32:56 -0700 Subject: [PATCH 05/17] DB output --- {elink_src => eink_src}/images.h | 61 +++--- {elink_src => eink_src}/main.cpp | 314 ++++++++++++++----------------- platformio.ini | 40 ++-- src/images.cpp | 4 +- 4 files changed, 202 insertions(+), 217 deletions(-) rename {elink_src => eink_src}/images.h (76%) rename {elink_src => eink_src}/main.cpp (57%) diff --git a/elink_src/images.h b/eink_src/images.h similarity index 76% rename from elink_src/images.h rename to eink_src/images.h index e33c6c3..5021a8f 100644 --- a/elink_src/images.h +++ b/eink_src/images.h @@ -1,30 +1,4 @@ -#define WiFi_Logo_width 60 -#define WiFi_Logo_height 36 -const uint8_t WiFi_Logo_bits[] PROGMEM = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, - 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, 0x00, 0x00, - 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, - 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 0x83, 0x01, 0x80, 0xFF, 0xFF, 0xFF, - 0x01, 0x00, 0x07, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x0C, 0x00, 0xC0, 0xFF, - 0xFF, 0x7C, 0x00, 0x60, 0x0C, 0x00, 0xC0, 0x31, 0x46, 0x7C, 0xFC, 0x77, 0x08, 0x00, - 0xE0, 0x23, 0xC6, 0x3C, 0xFC, 0x67, 0x18, 0x00, 0xE0, 0x23, 0xE4, 0x3F, 0x1C, 0x00, - 0x18, 0x00, 0xE0, 0x23, 0x60, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x03, 0x60, 0x3C, - 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x07, 0x60, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, - 0x70, 0x3C, 0xFC, 0x73, 0x18, 0x00, 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, - 0xE0, 0x87, 0x70, 0x3C, 0x1C, 0x70, 0x18, 0x00, 0xE0, 0x8F, 0x71, 0x3C, 0x1C, 0x70, - 0x18, 0x00, 0xC0, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x08, 0x00, 0xC0, 0xFF, 0xFF, 0x1F, - 0x00, 0x00, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x00, 0x00, 0x06, 0x00, 0x80, 0xFF, - 0xFF, 0x0F, 0x00, 0x00, 0x07, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, - 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFF, 0x01, - 0x00, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, - 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x80, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -}; - -const unsigned char epd_bitmap_ucog[] = { +constexpr unsigned char epd_bitmap_ucog[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -100,3 +74,36 @@ const unsigned char epd_bitmap_ucog[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; + +const uint8_t batteryfull[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery6[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery5[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0xF8, 0x03, 0xF8, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery4[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0xF8, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery3[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery2[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, + 0x03, 0x18, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery1[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, + 0x03, 0x18, 0x03, 0x18, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery0[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, + 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; diff --git a/elink_src/main.cpp b/eink_src/main.cpp similarity index 57% rename from elink_src/main.cpp rename to eink_src/main.cpp index 4829431..791b6d1 100644 --- a/elink_src/main.cpp +++ b/eink_src/main.cpp @@ -2,29 +2,35 @@ * NOTE!!!: to upload we neew code you need to press button BOOT and RESET or you will * have serial error. After upload you need reset device... * - * Function: - * 1. Ink screen full brush demonstration - * * Description: * 1.Inherited from ssd1306 for drawing points, lines, and functions * + * All code e link examples you cand find here: * */ - +// Varriables requred to boot Heltec E290 defined at platformio.ini +// #define HELTEC_BOARD 37 +// #define SLOW_CLK_TPYE 1 +// #define ARDUINO_USB_CDC_ON_BOOT 1 +// #define LoRaWAN_DEBUG_LEVEL 0 #include "HT_DEPG0290BxS800FxX_BW.h" #include "global_config.h" #include "images.h" #include "ui.h" #include -// Disabling default lib display +// Disabling default Heltec lib OLED display #define HELTEC_NO_DISPLAY #define DISPLAY_WIDTH 296 #define DISPLAY_HEIGHT 128 -// Without this line Lora Radio doesn't work +// Without this line Lora Radio doesn't work with heltec lib #define ARDUINO_heltec_wifi_32_lora_V3 #include "heltec_unofficial.h" -#include "modules/SX126x/patches/SX126x_patch_scan.h" +// We are not using spectral scan here only RSSI method +// #include "modules/SX126x/patches/SX126x_patch_scan.h" +#define PRINT_DEBUG + +// TODO: move varriables to common file // <--- Spectrum display Varriables START #define SCAN_METHOD #define METHOD_SPECTRAL @@ -56,12 +62,12 @@ uint64_t range = (int)(FREQ_END - FREQ_BEGIN); uint64_t fr_begin = FREQ_BEGIN; uint64_t fr_end = FREQ_BEGIN; -// Feature to scan diapazones. Other frequency settings will be ignored. +// Feature to scan diapasones. Other frequency settings will be ignored. // int SCAN_RANGES[] = {850890, 920950}; int SCAN_RANGES[] = {}; // MHZ per page -// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 +// to put everything into one page set RANGE_PER_PAGE = FREQ_END - 800 // uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // Override or e-ink @@ -89,7 +95,7 @@ bool waterfall[STEPS], detected_y[STEPS]; // 20 - ??? steps of the waterfall bool first_run, new_pixel, detected_x = false; // drone detection flag bool detected = false; -uint64_t drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; +uint64_t drone_detection_level = 90; uint64_t drone_detected_frequency_start = 0; uint64_t drone_detected_frequency_end = 0; uint64_t detection_count = 0; @@ -124,12 +130,11 @@ constexpr int samples = SAMPLES_RSSI; uint8_t result_index = 0; uint8_t button_pressed_counter = 0; uint64_t loop_cnt = 0; -// <--- Spectrum display Varriables END +// <--- Spectrum display Variables END // Initialize the display DEPG0290BxS800FxX_BW display(5, 4, 3, 6, 2, 1, -1, 6000000); // rst,dc,cs,busy,sck,mosi,miso,frequency -typedef void (*Demo)(void); /* screen rotation * ANGLE_0_DEGREE * ANGLE_90_DEGREE @@ -137,8 +142,8 @@ typedef void (*Demo)(void); * ANGLE_270_DEGREE */ #define DIRECTION ANGLE_0_DEGREE -int demoMode = 0; +// TODO: move to common file void init_radio() { // initialize SX1262 FSK modem at the initial frequency @@ -152,7 +157,7 @@ void init_radio() // 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))); + // RADIOLIB_OR_HALT(radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan))); // configure scan bandwidth and disable the data shaping Serial.println("Setting up radio"); @@ -169,166 +174,69 @@ void init_radio() } #define HEIGHT 4 -DEPG0290BxS800FxX_BW display_instance = display; -/** - * @brief Draws ticks on the display at regular whole intervals. - * - * @param every The interval between ticks in MHz. - * @param length The length of each tick in pixels. - */ -void drawTicks(float every, int length) -{ - int first_tick; - bool correction; - int pixels_per_step; - int correction_number; - int tick; - int tick_minor; - int median; - first_tick = 0; - //+ (every - (fr_begin - (int)(fr_begin / every) * every)); - /*if (first_tick < fr_begin) - { - first_tick += every; - }*/ - correction = false; - pixels_per_step = STEPS / (RANGE_PER_PAGE / every); - if (STEPS / RANGE_PER_PAGE != 0) - { - correction = true; - } - correction_number = STEPS - (int)(pixels_per_step * (RANGE_PER_PAGE / every)); - tick = 0; - tick_minor = 0; - median = (RANGE_PER_PAGE / every) / 2; - // TODO: (RANGE_PER_PAGE / every) - // * 2 has twice extra steps we need to figureout correct logic or minor - // ticks is not showing to the end - for (int t = 0; t <= (RANGE_PER_PAGE / every) * 2; t++) - { - // fix if pixels per step is not int and we have shift - if (correction && t % 2 != 0 && correction_number > 1) - { - // pixels_per_step++; - correction_number--; - } - tick += pixels_per_step; - tick_minor = tick / 2; - if (tick <= 128 - 3) - { - display_instance.drawLine(tick, HEIGHT + X_AXIS_WEIGHT, tick, - HEIGHT + X_AXIS_WEIGHT + length); - // Central tick - if (tick > (128 / 2) - 3 && tick < (128 / 2) + 3) - { - display_instance.drawLine(tick + 1, HEIGHT + X_AXIS_WEIGHT, tick + 1, - HEIGHT + X_AXIS_WEIGHT + length); - } - } -#ifdef MINOR_TICKS - // Fix two ticks together - if ((tick_minor + 1 != tick) && (tick_minor - 1 != tick) && - (tick_minor + 2 != tick) && (tick_minor - 2 != tick)) - { - display_instance.drawLine(tick_minor, HEIGHT + X_AXIS_WEIGHT, tick_minor, - HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); - } - // Central tick - if (tick_minor > (128 / 2) - 3 && tick_minor < (128 / 2) + 3) - { - display_instance.drawLine(tick_minor + 1, HEIGHT + X_AXIS_WEIGHT, - tick_minor + 1, - HEIGHT + X_AXIS_WEIGHT + MINOR_TICK_LENGTH); - } -#endif - } -} - -void drawFontFaceDemo() +void drawSetupText() { - // Font Demo1 // create more fonts at http://oleddisplay.squix.ch/ display.setTextAlignment(TEXT_ALIGN_LEFT); display.setFont(ArialMT_Plain_10); - display.drawString(0, 0, "Spectrum Analizer Lora SA"); + display.drawString(0, 0, "Spectrum Analyzer Lora SA"); display.setFont(ArialMT_Plain_16); display.drawString(0, 10, "SX 1262"); display.setFont(ArialMT_Plain_24); display.drawString(0, 26, "e-ink display"); + display.drawString(0, 56, "RF Spectrum X-Ray"); + display.setFont(ArialMT_Plain_24); } -void drawTextFlowDemo() + +#define battery_w 13 +#define battery_h 13 +#define BATTERY_PIN 7 + +void battery() { - display.setFont(ArialMT_Plain_10); - display.setTextAlignment(TEXT_ALIGN_LEFT); - display.drawStringMaxWidth( - 0, 0, DISPLAY_HEIGHT, - "Lorem ipsum\n dolor sit amet, consetetur sadipscing elitr, sed diam nonumy " - "eirmod tempor invidunt ut labore."); -} -void drawTextAlignmentDemo() -{ - // Text alignment demo - char str[30]; - int x = 0; - int y = 0; - display.setFont(ArialMT_Plain_10); - // The coordinates define the left starting point of the text - display.setTextAlignment(TEXT_ALIGN_LEFT); - display.drawString(x, y, "Left aligned (0,0)"); - // The coordinates define the center of the text - display.setTextAlignment(TEXT_ALIGN_CENTER); - x = display.width() / 2; - y = display.height() / 2 - 5; - sprintf(str, "Center aligned (%d,%d)", x, y); - display.drawString(x, y, str); - // The coordinates define the right end of the text - display.setTextAlignment(TEXT_ALIGN_RIGHT); - x = display.width(); - y = display.height() - 12; - sprintf(str, "Right aligned (%d,%d)", x, y); - display.drawString(x, y, str); -} -void drawRectDemo() -{ - // Draw a pixel at given position - for (int i = 0; i < 10; i++) + analogReadResolution(12); + int battery_levl = analogRead(BATTERY_PIN) / 238.7; // battary/4096*3.3* coefficient + float battery_one = 0.4125; +#ifdef PRINT_DEBUG + Serial.printf("ADC analog value = %.2f\n", battery_levl); +#endif + display.drawString(257, 0, String(heltec_battery_percent(battery_levl)) + "%"); + // TODO: battery voltage doesn't work + if (battery_levl < battery_one) { - display.setPixel(i, i); - display.setPixel(10 - i, i); + display.drawXbm(275, 0, battery_w, battery_h, battery0); } - display.drawRect(12, 12, 20, 20); - // Fill the rectangle - display.fillRect(14, 14, 17, 17); - // Draw a line horizontally - display.drawHorizontalLine(0, 40, 20); - // Draw a line horizontally - display.drawVerticalLine(40, 0, 20); -} -void drawCircleDemo() -{ - int x = display.width() / 4; - int y = display.height() / 2; - for (int i = 1; i < 8; i++) + else if (battery_levl < 2 * battery_one && battery_levl > battery_one) { - display.setColor(WHITE); - display.drawCircle(x, y, i * 3); - if (i % 2 == 0) - { - display.setColor(BLACK); - } - int x = display.width() / 4 * 3; - display.fillCircle(x, y, 32 - i * 3); + display.drawXbm(285, 0, battery_w, battery_h, battery1); + } + else if (battery_levl < 3 * battery_one && battery_levl > 2 * battery_one) + { + display.drawXbm(285, 0, battery_w, battery_h, battery2); + } + else if (battery_levl < 4 * battery_one && battery_levl > 3 * battery_one) + { + display.drawXbm(285, 0, battery_w, battery_h, battery3); + } + else if (battery_levl < 5 * battery_one && battery_levl > 4 * battery_one) + { + display.drawXbm(285, 0, battery_w, battery_h, battery4); + } + else if (battery_levl < 6 * battery_one && battery_levl > 5 * battery_one) + { + display.drawXbm(285, 0, battery_w, battery_h, battery5); + } + else if (battery_levl < 7 * battery_one && battery_levl > 6 * battery_one) + { + display.drawXbm(285, 0, battery_w, battery_h, battery6); + } + else if (battery_levl < 7 * battery_one && battery_levl > 6 * battery_one) + { + display.drawXbm(285, 0, battery_w, battery_h, batteryfull); } } -void drawImageDemo() -{ - // see http://blog.squix.org/2015/05/esp8266-nodemcu-how-to-create-xbm.html - // on how to create xbm files - int x = display.width() / 2 - WiFi_Logo_width / 2; - int y = display.height() / 2 - WiFi_Logo_height / 2; - display.drawXbm(x, y, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits); -} + void VextON(void) { pinMode(18, OUTPUT); @@ -356,17 +264,29 @@ int rssiToPix(int rssi) return abs(rssi); } -Demo demos[] = {drawFontFaceDemo, drawTextFlowDemo, drawTextAlignmentDemo, - drawRectDemo, drawCircleDemo, drawImageDemo}; -int demoLength = (sizeof(demos) / sizeof(Demo)); long timeSinceLastModeSwitch = 0; -float fr = FREQ_BEGIN; +float fr = FREQ_BEGIN, vbat = 0; int rssi2 = 0; int x1 = 0, y2 = 0; -unsigned int loop_counter = 1; +unsigned int screen_update_loop_counter = 0; +unsigned int x_screan_update = 0; +int rssi_printed = 0; +constexpr int rssi_window_size = 30; +int max_i_rssi = -999; +long display_scan_start = 0; +long display_scan_end = 0; +int scan_iterations = 0; + +constexpr unsigned int SCANS_PER_DISPLAY = 5; +constexpr unsigned int STATUS_BAR_HEIGHT = 5; + void loop() { + if (screen_update_loop_counter == 0) + { + display_scan_start = millis(); + } radio.setFrequency(fr, false); // false = no calibration need here for (int i = 0; i < SAMPLES_RSSI; i++) { @@ -375,22 +295,57 @@ void loop() else if (i % 3 == 0) radio.setFrequency((float)fr + 0.33, false); rssi2 = radio.getRSSI(false); + scan_iterations++; if (rssi2 > lower_level) continue; - // Serial.println(String(fr) + ":" + String(rssi2)); - // display.drawString(x1, (int)y2, String(fr) + ":" + String(rssi2)); +#ifdef PRINT_DEBUG + Serial.println(String(fr) + ":" + String(rssi2)); +#endif + // display.drawString(x1, (int)y2, String(fr) + ":" + String(rssi2)); display.setPixel(x1, rssiToPix(rssi2)); + + if (max_i_rssi < rssi2) + { + max_i_rssi = rssi2; + } } + if (abs(max_i_rssi) < drone_detection_level && x1 - rssi_printed > rssi_window_size && + (x1 > rssi_window_size / 2 && x1 < STEPS - rssi_window_size / 2)) + { + rssi_printed = x1; + + y2 = (screen_update_loop_counter + 1) * 10; + + display.setFont(ArialMT_Plain_10); + display.drawStringMaxWidth(x1 - (rssi_window_size / 2), y2, rssi_window_size, + String(max_i_rssi) + "dB"); + } + max_i_rssi = -999; + + // drone detection level line + if (x1 % 2 == 0) + { + display.setPixel(x1, rssiToPix(drone_detection_level)); + } fr++; x1++; + // Main N x-axis full loop end logic if (x1 >= STEPS) { - if (loop_counter > STEPS * 5) + if (screen_update_loop_counter == SCANS_PER_DISPLAY) { - loop_counter = 0; + display_scan_end = millis(); + + display.drawString( + 1, 1, "T:" + String((display_scan_end - display_scan_start) / 1000)); + + battery(); // Draw a line horizontally + display.drawString(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2), 1, + "i:" + String(scan_iterations)); display.drawHorizontalLine(0, lower_level + 1, DISPLAY_WIDTH); + // Generate Ticks for (int x = 0; x < DISPLAY_WIDTH; x++) { if (x % (DISPLAY_WIDTH / 2) == 0 && x > 5) @@ -412,29 +367,35 @@ void loop() String(FREQ_BEGIN + ((fr - FREQ_BEGIN) / 2))); display.display(); - // delay(2000); - if (loop_counter == 0) - { - display.clear(); - } + // display will be cleared next scan iteration. it is just buffer clear + // memset(buffer, 0, displayBufferSize); + display.clear(); + screen_update_loop_counter = 0; + scan_iterations = 0; } fr = FREQ_BEGIN; x1 = 0; + rssi_printed = 0; + screen_update_loop_counter++; } - loop_counter++; +#ifdef PRINT_DEBUG + Serial.println("Full Scan:" + String(screen_update_loop_counter)); +#endif } void setup() { // Initialising the UI will init the display too. display.init(); + // Of not this screen doesn't work + VextON(); display.screenRotate(DIRECTION); display.setFont(ArialMT_Plain_10); display.clear(); display.drawXbm((DISPLAY_WIDTH / 3) - 10, DISPLAY_HEIGHT / 4, 128, 60, epd_bitmap_ucog); display.display(); - delay(2000); + delay(1000); display.clear(); Serial.begin(115200); w = WATERFALL_START; @@ -448,9 +409,8 @@ void setup() heltec_setup(); Serial.println(); Serial.println(); - drawFontFaceDemo(); + drawSetupText(); display.display(); - delay(1000); - VextON(); display.clear(); + delay(1000); } diff --git a/platformio.ini b/platformio.ini index 634c9a4..e7d2dec 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,9 +10,9 @@ [platformio] ;; for env:vision-master-e290 -;;src_dir = elink_src +;;src_dir = eink_src ;; for env:heltec_wifi_lora_32_V3 -;;src_dir = src +;;src_dir = src ;;Default [env:heltec_wifi_lora_32_V3] platform = espressif32 @@ -25,6 +25,17 @@ lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 build_flags = -DHELTEC_POWER_BUTTON +[env:heltec_wifi_lora_32_V3-test-signal-generator] +platform = espressif32 +board = heltec_wifi_lora_32_V3 +framework = arduino +upload_speed = 115200 +monitor_speed = 115200 +board_build.f_cpu = 240000000 +lib_deps = + ropg/Heltec_ESP32_LoRa_v3@^0.9.1 +build_flags = -DHELTEC_POWER_BUTTON + [env:vision-master-e290] platform = espressif32 board = heltec_wifi_lora_32_V3 @@ -33,15 +44,22 @@ monitor_speed = 115200 monitor_filters = esp32_exception_decoder board_upload.use_1200bps_touch = true build_flags = - -D HELTEC_BOARD=37 - -D SLOW_CLK_TPYE=1 - -D ARDUINO_USB_CDC_ON_BOOT=1 - -D LoRaWAN_DEBUG_LEVEL=0 - -D E290 - -D ESP32 - -D Vision_Master_E290 - -D RADIOLIB_EXCLUDE_CC1101=1 - -D RADIOLIB_EXCLUDE_LR11x0=1 + -DHELTEC_BOARD=37 + -DSLOW_CLK_TPYE=1 + -DARDUINO_USB_CDC_ON_BOOT=1 + -DLoRaWAN_DEBUG_LEVEL=0 + -DE290 + -DESP32 + -DVision_Master_E290 + -DRADIOLIB_EXCLUDE_CC1101=true + -DRADIOLIB_EXCLUDE_LR11x0=true + -DRADIOLIB_EXCLUDE_NRF24=true + -DRADIOLIB_EXCLUDE_RF69=true + -DRADIOLIB_EXCLUDE_RFM2X=true + -DRADIOLIB_EXCLUDE_SI443X=true + -DRADIOLIB_EXCLUDE_SX1231=true + -DRADIOLIB_EXCLUDE_SX127X=true + -DRADIOLIB_EXCLUDE_SX128X=true lib_deps = SPI Wire diff --git a/src/images.cpp b/src/images.cpp index ab61f38..d2ab5f7 100644 --- a/src/images.cpp +++ b/src/images.cpp @@ -3,8 +3,8 @@ //'Logo_UCOG', 128x64px // https://www.online-utility.org/image/convert/to/XBM // https://javl.github.io/image2cpp/ -//#define 1721604660673_width 128 -//#define 1721604660673_height 64 +// #define 1721604660673_width 128 +// #define 1721604660673_height 64 const unsigned char epd_bitmap_ucog[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, From 91ea5eb7f5a5c117bb29fc1f527d10a325cf8b5c Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 27 Aug 2024 16:23:49 -0700 Subject: [PATCH 06/17] add Mhz to max output --- eink_src/main.cpp | 101 +++++++++++++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 29 deletions(-) diff --git a/eink_src/main.cpp b/eink_src/main.cpp index 791b6d1..99d760b 100644 --- a/eink_src/main.cpp +++ b/eink_src/main.cpp @@ -1,5 +1,5 @@ /* Heltec Automation Ink screen example - * NOTE!!!: to upload we neew code you need to press button BOOT and RESET or you will + * NOTE!!!: to upload we new code you need to press button BOOT and RESET or you will * have serial error. After upload you need reset device... * * Description: @@ -7,7 +7,7 @@ * * All code e link examples you cand find here: * */ -// Varriables requred to boot Heltec E290 defined at platformio.ini +// Variables required to boot Heltec E290 defined at platformio.ini // #define HELTEC_BOARD 37 // #define SLOW_CLK_TPYE 1 // #define ARDUINO_USB_CDC_ON_BOOT 1 @@ -28,13 +28,13 @@ // We are not using spectral scan here only RSSI method // #include "modules/SX126x/patches/SX126x_patch_scan.h" -#define PRINT_DEBUG +// #define PRINT_DEBUG -// TODO: move varriables to common file -// <--- Spectrum display Varriables START +// TODO: move variables to common file +// <--- Spectrum display Variables START #define SCAN_METHOD #define METHOD_SPECTRAL -// numbers of the spectrum screan lines = width of screan +// numbers of the spectrum screen lines = width of screen #define STEPS 296 // 128 // Number of samples for each scan. Fewer samples = better temporal resolution. #define MAX_POWER_LEVELS 33 @@ -266,7 +266,7 @@ int rssiToPix(int rssi) long timeSinceLastModeSwitch = 0; -float fr = FREQ_BEGIN, vbat = 0; +float fr = FREQ_BEGIN, fr_x[STEPS + 5], vbat = 0; int rssi2 = 0; int x1 = 0, y2 = 0; unsigned int screen_update_loop_counter = 0; @@ -274,6 +274,9 @@ unsigned int x_screan_update = 0; int rssi_printed = 0; constexpr int rssi_window_size = 30; int max_i_rssi = -999; +int window_max_rssi = -999; +int window_max_fr = -999; +int max_scan_rssi[STEPS + 2]; long display_scan_start = 0; long display_scan_end = 0; int scan_iterations = 0; @@ -285,9 +288,15 @@ void loop() { if (screen_update_loop_counter == 0) { + for (int i = 0; i < STEPS; i++) + { + fr_x[x1] = 0; + max_scan_rssi[i] = -999; + } display_scan_start = millis(); } radio.setFrequency(fr, false); // false = no calibration need here + fr_x[x1] = fr; for (int i = 0; i < SAMPLES_RSSI; i++) { if (i % 2 == 0) @@ -304,25 +313,12 @@ void loop() // display.drawString(x1, (int)y2, String(fr) + ":" + String(rssi2)); display.setPixel(x1, rssiToPix(rssi2)); - if (max_i_rssi < rssi2) + if (max_scan_rssi[x1] < rssi2) { - max_i_rssi = rssi2; + max_scan_rssi[x1] = rssi2; } } - if (abs(max_i_rssi) < drone_detection_level && x1 - rssi_printed > rssi_window_size && - (x1 > rssi_window_size / 2 && x1 < STEPS - rssi_window_size / 2)) - { - rssi_printed = x1; - - y2 = (screen_update_loop_counter + 1) * 10; - - display.setFont(ArialMT_Plain_10); - display.drawStringMaxWidth(x1 - (rssi_window_size / 2), y2, rssi_window_size, - String(max_i_rssi) + "dB"); - } - max_i_rssi = -999; - // drone detection level line if (x1 % 2 == 0) { @@ -335,14 +331,47 @@ void loop() { if (screen_update_loop_counter == SCANS_PER_DISPLAY) { - display_scan_end = millis(); + // max Mhz and dB in window + for (int i = 0; i < STEPS; i++) + { + // Max dB in window + if (window_max_rssi < max_scan_rssi[i]) + { + // Max Mhz in window + window_max_fr = fr_x[i]; + window_max_rssi = max_scan_rssi[i]; + } + if (i % rssi_window_size == 0) + { - display.drawString( - 1, 1, "T:" + String((display_scan_end - display_scan_start) / 1000)); + if (abs(window_max_rssi) < drone_detection_level) + { + y2 = 10; + + display.setFont(ArialMT_Plain_10); + display.drawStringMaxWidth(i - rssi_window_size, y2, + rssi_window_size, + String(window_max_rssi) + "dB"); + display.drawString(i - rssi_window_size + 5, y2 + 10, + String(window_max_fr)); + // Vertical lines between windows + for (int l = y2; l < 100; l += 4) + { + display.setPixel(i, l); + } + } + window_max_rssi = -999; + } + } + + display_scan_end = millis(); + display.setFont(ArialMT_Plain_10); + display.drawString(0, 0, + "T:" + String(display_scan_end - display_scan_start)); battery(); // Draw a line horizontally - display.drawString(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2), 1, + display.drawString(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2), 0, "i:" + String(scan_iterations)); display.drawHorizontalLine(0, lower_level + 1, DISPLAY_WIDTH); // Generate Ticks @@ -361,10 +390,20 @@ void loop() } display.setFont(ArialMT_Plain_10); + // Begin Mhz display.drawString(1, DISPLAY_HEIGHT - 10, String(FREQ_BEGIN)); - display.drawString(DISPLAY_WIDTH - 24, DISPLAY_HEIGHT - 10, String(fr)); + // Median -1/2 Mhz + display.drawString((DISPLAY_WIDTH / 4) - 10, DISPLAY_HEIGHT - 10, + String(FREQ_BEGIN + ((fr - FREQ_BEGIN) / 4))); + // Median Mhz display.drawString((DISPLAY_WIDTH / 2) - 10, DISPLAY_HEIGHT - 10, String(FREQ_BEGIN + ((fr - FREQ_BEGIN) / 2))); + // Median + 1/2 Mhz + display.drawString( + (DISPLAY_WIDTH - (DISPLAY_WIDTH / 4)) - 10, DISPLAY_HEIGHT - 10, + String(FREQ_BEGIN + ((fr - FREQ_BEGIN) - (fr - FREQ_BEGIN) / 4))); + // End Mhz + display.drawString(DISPLAY_WIDTH - 24, DISPLAY_HEIGHT - 10, String(fr)); display.display(); // display will be cleared next scan iteration. it is just buffer clear @@ -376,7 +415,11 @@ void loop() fr = FREQ_BEGIN; x1 = 0; rssi_printed = 0; - screen_update_loop_counter++; + // Prevent screen_update_loop_counter++ when it is just nulled + if (scan_iterations > 0) + { + screen_update_loop_counter++; + } } #ifdef PRINT_DEBUG Serial.println("Full Scan:" + String(screen_update_loop_counter)); @@ -412,5 +455,5 @@ void setup() drawSetupText(); display.display(); display.clear(); - delay(1000); + delay(500); } From 97e1ac7b5104f0cfbf34c87bae5db7e7cb2ee4f5 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Wed, 28 Aug 2024 01:58:33 -0700 Subject: [PATCH 07/17] steps optimization --- eink_src/main.cpp | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/eink_src/main.cpp b/eink_src/main.cpp index 99d760b..60c1f06 100644 --- a/eink_src/main.cpp +++ b/eink_src/main.cpp @@ -52,7 +52,7 @@ constexpr bool DRAW_DETECTION_TICKS = true; // number of samples for RSSI method #define SAMPLES_RSSI 30 // 21 // -#define FREQ_BEGIN 750 +#define FREQ_BEGIN 650 #define RANGE (int)(FREQ_END - FREQ_BEGIN) @@ -267,6 +267,12 @@ int rssiToPix(int rssi) long timeSinceLastModeSwitch = 0; float fr = FREQ_BEGIN, fr_x[STEPS + 5], vbat = 0; +// MHz in one screen pix step +// END will be Begin + 289 * mhz_step +int mhz_step = 1; +// TODO: make end_freq +// Measure RSS every step +float rssi_mhz_step = 0.33; int rssi2 = 0; int x1 = 0, y2 = 0; unsigned int screen_update_loop_counter = 0; @@ -288,6 +294,7 @@ void loop() { if (screen_update_loop_counter == 0) { + // Zero arrays for (int i = 0; i < STEPS; i++) { fr_x[x1] = 0; @@ -295,14 +302,19 @@ void loop() } display_scan_start = millis(); } - radio.setFrequency(fr, false); // false = no calibration need here fr_x[x1] = fr; + int u = 0; for (int i = 0; i < SAMPLES_RSSI; i++) { - if (i % 2 == 0) - radio.setFrequency((float)fr + 0.33, false); - else if (i % 3 == 0) - radio.setFrequency((float)fr + 0.33, false); + + radio.setFrequency((float)fr + (float)(rssi_mhz_step * u), + false); // false = no calibration need here + u++; + if (rssi_mhz_step * u >= mhz_step) + { + u = 0; + } + rssi2 = radio.getRSSI(false); scan_iterations++; if (rssi2 > lower_level) @@ -324,7 +336,7 @@ void loop() { display.setPixel(x1, rssiToPix(drone_detection_level)); } - fr++; + fr += mhz_step; x1++; // Main N x-axis full loop end logic if (x1 >= STEPS) From baaac4d45dcb2872d860acb5795aa291469a51d6 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Thu, 29 Aug 2024 12:18:07 -0700 Subject: [PATCH 08/17] add some fixes --- eink_src/main.cpp | 56 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/eink_src/main.cpp b/eink_src/main.cpp index 60c1f06..9a4b300 100644 --- a/eink_src/main.cpp +++ b/eink_src/main.cpp @@ -276,7 +276,7 @@ float rssi_mhz_step = 0.33; int rssi2 = 0; int x1 = 0, y2 = 0; unsigned int screen_update_loop_counter = 0; -unsigned int x_screan_update = 0; +unsigned int x_screen_update = 0; int rssi_printed = 0; constexpr int rssi_window_size = 30; int max_i_rssi = -999; @@ -285,6 +285,7 @@ int window_max_fr = -999; int max_scan_rssi[STEPS + 2]; long display_scan_start = 0; long display_scan_end = 0; +long display_scan_i_end = 0; int scan_iterations = 0; constexpr unsigned int SCANS_PER_DISPLAY = 5; @@ -338,6 +339,10 @@ void loop() } fr += mhz_step; x1++; + if (display_scan_i_end == 0) + { + display_scan_i_end = millis(); + } // Main N x-axis full loop end logic if (x1 >= STEPS) { @@ -353,7 +358,7 @@ void loop() window_max_fr = fr_x[i]; window_max_rssi = max_scan_rssi[i]; } - if (i % rssi_window_size == 0) + if (i % rssi_window_size == 0 || (i % (DISPLAY_WIDTH - 1)) == 0) { if (abs(window_max_rssi) < drone_detection_level) @@ -377,23 +382,42 @@ void loop() } display_scan_end = millis(); + display.setFont(ArialMT_Plain_10); display.drawString(0, 0, - "T:" + String(display_scan_end - display_scan_start)); + "T:" + String(display_scan_end - display_scan_start) + + "/" + String(display_scan_i_end - display_scan_start)); + + // some issues with the performance. + // TODO: fix this issue + if (display_scan_end - display_scan_start > 20000) + { + esp_restart(); + } battery(); + // iteration full scan / samples pixel step / numbers of scan per display + display.drawString(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2) - 5, 0, + "i:" + String(scan_iterations) + "/" + String(SAMPLES) + + "/" + String(SCANS_PER_DISPLAY)); + // Scan resolution + display.drawString(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2) - 35, 0, + "r:" + String(rssi_mhz_step)); + // Mhz in pixel + display.drawString(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2) - 55, 0, + "s:" + String(mhz_step)); + // Draw a line horizontally - display.drawString(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2), 0, - "i:" + String(scan_iterations)); display.drawHorizontalLine(0, lower_level + 1, DISPLAY_WIDTH); // Generate Ticks for (int x = 0; x < DISPLAY_WIDTH; x++) { if (x % (DISPLAY_WIDTH / 2) == 0 && x > 5) { - display.drawVerticalLine(x, lower_level + 1, 8); - display.drawVerticalLine(x - 1, lower_level + 1, 8); - display.drawVerticalLine(x + 1, lower_level + 1, 8); + display.drawVerticalLine(x, lower_level + 1, 11); + // central tick width + // display.drawVerticalLine(x - 1, lower_level + 1, 8); + // display.drawVerticalLine(x + 1, lower_level + 1, 8); } if (x % 10 == 0 || x == 0) display.drawVerticalLine(x, lower_level + 1, 6); @@ -406,16 +430,17 @@ void loop() display.drawString(1, DISPLAY_HEIGHT - 10, String(FREQ_BEGIN)); // Median -1/2 Mhz display.drawString((DISPLAY_WIDTH / 4) - 10, DISPLAY_HEIGHT - 10, - String(FREQ_BEGIN + ((fr - FREQ_BEGIN) / 4))); + String(FREQ_BEGIN + (((int)fr - FREQ_BEGIN) / 4))); // Median Mhz display.drawString((DISPLAY_WIDTH / 2) - 10, DISPLAY_HEIGHT - 10, - String(FREQ_BEGIN + ((fr - FREQ_BEGIN) / 2))); + String(FREQ_BEGIN + (((int)fr - FREQ_BEGIN) / 2))); // Median + 1/2 Mhz - display.drawString( - (DISPLAY_WIDTH - (DISPLAY_WIDTH / 4)) - 10, DISPLAY_HEIGHT - 10, - String(FREQ_BEGIN + ((fr - FREQ_BEGIN) - (fr - FREQ_BEGIN) / 4))); + display.drawString((DISPLAY_WIDTH - (DISPLAY_WIDTH / 4)) - 10, + DISPLAY_HEIGHT - 10, + String(FREQ_BEGIN + (((int)fr - FREQ_BEGIN) - + ((int)fr - FREQ_BEGIN) / 4))); // End Mhz - display.drawString(DISPLAY_WIDTH - 24, DISPLAY_HEIGHT - 10, String(fr)); + display.drawString(DISPLAY_WIDTH - 24, DISPLAY_HEIGHT - 10, String((int)fr)); display.display(); // display will be cleared next scan iteration. it is just buffer clear @@ -423,6 +448,7 @@ void loop() display.clear(); screen_update_loop_counter = 0; scan_iterations = 0; + display_scan_i_end = 0; } fr = FREQ_BEGIN; x1 = 0; @@ -467,5 +493,5 @@ void setup() drawSetupText(); display.display(); display.clear(); - delay(500); + delay(100); } From 3e78ebc9816ac145a59e11c3e2afc28f5fba83d5 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Thu, 29 Aug 2024 18:34:15 -0700 Subject: [PATCH 09/17] small refactor --- eink_src/main.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/eink_src/main.cpp b/eink_src/main.cpp index 9a4b300..a87ece8 100644 --- a/eink_src/main.cpp +++ b/eink_src/main.cpp @@ -248,8 +248,8 @@ void VextOFF(void) // Vext default OFF digitalWrite(18, LOW); } -int lower_level = 108; -int up_level = 40; +constexpr int lower_level = 108; +constexpr int up_level = 40; int rssiToPix(int rssi) { // Bigger is lower signal @@ -269,10 +269,10 @@ long timeSinceLastModeSwitch = 0; float fr = FREQ_BEGIN, fr_x[STEPS + 5], vbat = 0; // MHz in one screen pix step // END will be Begin + 289 * mhz_step -int mhz_step = 1; +constexpr int mhz_step = 1; // TODO: make end_freq // Measure RSS every step -float rssi_mhz_step = 0.33; +constexpr float rssi_mhz_step = 0.33; int rssi2 = 0; int x1 = 0, y2 = 0; unsigned int screen_update_loop_counter = 0; @@ -386,7 +386,8 @@ void loop() display.setFont(ArialMT_Plain_10); display.drawString(0, 0, "T:" + String(display_scan_end - display_scan_start) + - "/" + String(display_scan_i_end - display_scan_start)); + "/" + String(display_scan_i_end - display_scan_start) + + " L:-" + String(drone_detection_level) + "dB"); // some issues with the performance. // TODO: fix this issue @@ -488,8 +489,7 @@ void setup() Serial.println(state); } heltec_setup(); - Serial.println(); - Serial.println(); + drawSetupText(); display.display(); display.clear(); From 4e309ba57e0eee1d46c05578bbca96948cb2604c Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Fri, 30 Aug 2024 02:19:15 -0700 Subject: [PATCH 10/17] add joystick --- src/main.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 59cde10..2af2d09 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -179,9 +179,10 @@ constexpr int OSD_PIXELS_PER_CHAR = (STEPS * SCAN_RBW_FACTOR) / OSD_CHART_WIDTH; // Print spectrum values pixels at once or by line bool ANIMATED_RELOAD = false; -// TODO: Ignore power lines +// TODO: Ignore max power lines #define UP_FILTER 5 -#define LOW_FILTER 3 +// Trim low signals - nose level +#define START_LOW 6 // Remove reading without neighbors #define FILTER_SPECTRUM_RESULTS true #define FILTER_SAMPLES_MIN @@ -262,6 +263,67 @@ uint8_t result_index = 0; uint8_t button_pressed_counter = 0; uint64_t loop_cnt = 0; +// Joystick integration +constexpr int JOY_X_PIN = 19; +int cursor_x_position = 0; +// Not integrated yet constexpr int JOY_Y_PIN = N/A; +constexpr int JOY_BTN_PIN = 46; + +bool joy_btn_click() +{ + // is the output from the pushbutton inside the joystick. It’s normally open. If we + // use a pull-up resistor in this pin, the SW pin will be HIGH + // when it is not pressed, and LOW when Pressed. + return digitalRead(JOY_BTN_PIN) == HIGH ? false : true; +} + +int joyXMid = 0; +int cal_X = 0, cal_Y = 0; + +void calibrate_joy() +{ + for (int i = 0; i < 100; i++) + { + cal_X += analogRead(JOY_X_PIN); + } + // calibrate center + joyXMid = cal_X / 100; +} + +int MID = 100; // 10 mid point delta arduino, use 4 for attiny +int get_joy_x(bool logical = false) +{ + int joyX = analogRead(JOY_X_PIN); + + /* + Serial.print("Calibrated_X_Voltage = "); + Serial.print(joyXMid); + Serial.print("X_Voltage = "); + Serial.print(joyX); + Serial.print("\t"); + */ + + if (logical) + { + // 4095 + if (joyX < joyXMid - MID) + { + return -1; + } + // 0-5 + else if (joyX > joyXMid + MID) + { + return 1; + } + else + { + return 0; + } + } + + return joyX; +} + #ifdef WIFI_SCANNING_ENABLED // WiFi Scan // TODO: Make Async Scan @@ -524,10 +586,12 @@ void setup(void) bt_start = millis(); wf_start = millis(); + pinMode(JOY_BTN_PIN, INPUT_PULLUP); pinMode(LED, OUTPUT); pinMode(BUZZER_PIN, OUTPUT); pinMode(REB_PIN, OUTPUT); heltec_setup(); + calibrate_joy(); UI_Init(&display); for (int i = 0; i < 200; i++) { @@ -957,12 +1021,11 @@ void loop(void) // frequencies if (!detected_y[dispaly_x]) { - display.drawLine(dispaly_x, 1, dispaly_x, 6); + display.drawLine(dispaly_x, 1, dispaly_x, 4); detected_y[dispaly_x] = true; } } } - #if (WATERFALL_ENABLED == true) if ((filtered_result[y] == 1) && (y <= drone_detection_level) && (single_page_scan) && (waterfall[dispaly_x] != true) && new_pixel) @@ -988,7 +1051,10 @@ void loop(void) ":" + String(y) + ","); #endif // Set signal level pixel - display.setPixel(dispaly_x, y); + if (y < MAX_POWER_LEVELS - START_LOW) + { + display.setPixel(dispaly_x, y + START_LOW); + } if (!detected) { detected = true; @@ -1005,12 +1071,17 @@ void loop(void) { display.setColor(INVERSE); } - display.setPixel(dispaly_x, y); - display.setPixel(dispaly_x, y - 1); // 2 px wide + display.setPixel(dispaly_x, y + START_LOW); + // display.setPixel(dispaly_x, y + START_LOW - 1); // 2 px wide display.setColor(WHITE); } } + if (dispaly_x == cursor_x_position) + { + display.drawString(dispaly_x, 0, String((int)freq)); + display.drawLine(dispaly_x, 1, dispaly_x, 10); + } #ifdef PRINT_PROFILE_TIME scan_time += (millis() - scan_start_time); @@ -1030,12 +1101,12 @@ void loop(void) } // Detection level button short press - if (button.pressedFor(100)) + if (button.pressedFor(100) || joy_btn_click()) { button.update(); button_pressed_counter = 0; // if long press stop - while (button.pressedNow()) + while (button.pressedNow() || joy_btn_click()) { delay(10); // Print Curent frequency @@ -1111,6 +1182,32 @@ void loop(void) // TODO: move osd logic here as a dalay ;) // Loop is needed if heltec_delay(1) not used heltec_loop(); + // Move joystick + int joy_x_pressed = get_joy_x(true); + if (joy_x_pressed > 0) + { + cursor_x_position--; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } + else if (joy_x_pressed < 0) + { + cursor_x_position++; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } + if (cursor_x_position > DISPLAY_WIDTH || cursor_x_position < 0) + { + cursor_x_position = 0; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } } w++; if (w > ROW_STATUS_TEXT + 1) From 2236d71bcdb953fc86e856c25227530e11c9298d Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Fri, 30 Aug 2024 02:29:11 -0700 Subject: [PATCH 11/17] disable joystick --- src/main.cpp | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 2af2d09..c9fba04 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -268,6 +268,7 @@ constexpr int JOY_X_PIN = 19; int cursor_x_position = 0; // Not integrated yet constexpr int JOY_Y_PIN = N/A; constexpr int JOY_BTN_PIN = 46; +// #define JOYSTICK_ENABLED bool joy_btn_click() { @@ -586,12 +587,14 @@ void setup(void) bt_start = millis(); wf_start = millis(); - pinMode(JOY_BTN_PIN, INPUT_PULLUP); pinMode(LED, OUTPUT); pinMode(BUZZER_PIN, OUTPUT); pinMode(REB_PIN, OUTPUT); heltec_setup(); +#ifdef JOYSTICK_ENABLED calibrate_joy(); + pinMode(JOY_BTN_PIN, INPUT_PULLUP); +#endif UI_Init(&display); for (int i = 0; i < 200; i++) { @@ -1077,11 +1080,13 @@ void loop(void) display.setColor(WHITE); } } +#ifdef JOYSTICK_ENABLED if (dispaly_x == cursor_x_position) { display.drawString(dispaly_x, 0, String((int)freq)); display.drawLine(dispaly_x, 1, dispaly_x, 10); } +#endif #ifdef PRINT_PROFILE_TIME scan_time += (millis() - scan_start_time); @@ -1101,12 +1106,20 @@ void loop(void) } // Detection level button short press - if (button.pressedFor(100) || joy_btn_click()) + if (button.pressedFor(100) +#ifdef JOYSTICK_ENABLED + || joy_btn_click() +#endif + ) { button.update(); button_pressed_counter = 0; // if long press stop - while (button.pressedNow() || joy_btn_click()) + while (button.pressedNow() +#ifdef JOYSTICK_ENABLED + || joy_btn_click() +#endif + ) { delay(10); // Print Curent frequency @@ -1182,7 +1195,8 @@ void loop(void) // TODO: move osd logic here as a dalay ;) // Loop is needed if heltec_delay(1) not used heltec_loop(); - // Move joystick +// Move joystick +#ifdef JOYSTICK_ENABLED int joy_x_pressed = get_joy_x(true); if (joy_x_pressed > 0) { @@ -1208,6 +1222,7 @@ void loop(void) display.display(); delay(10); } +#endif } w++; if (w > ROW_STATUS_TEXT + 1) From b4e975b789956f2d178268b80d77e01e21914259 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Fri, 30 Aug 2024 15:06:24 -0700 Subject: [PATCH 12/17] add joystic cursor dB --- src/main.cpp | 84 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 30 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index c9fba04..d6f50e8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -268,10 +268,12 @@ constexpr int JOY_X_PIN = 19; int cursor_x_position = 0; // Not integrated yet constexpr int JOY_Y_PIN = N/A; constexpr int JOY_BTN_PIN = 46; -// #define JOYSTICK_ENABLED +bool joy_btn_clicked = false; +#define JOYSTICK_ENABLED bool joy_btn_click() { + joy_btn_clicked = true; // is the output from the pushbutton inside the joystick. It’s normally open. If we // use a pull-up resistor in this pin, the SW pin will be HIGH // when it is not pressed, and LOW when Pressed. @@ -708,6 +710,8 @@ int binToRSSI(int bin) return 11 + (bin * 4); } +// MAX Frequency RSSI value of the samples +int max_rssi_x = 999; void loop(void) { UI_displayDecorate(0, 0, false); // some default values @@ -835,8 +839,8 @@ void loop(void) // Real display pixel x - axis. // Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore // x > STEPS on SCAN_RBW_FACTOR - int dispaly_x = x / SCAN_RBW_FACTOR; - waterfall[dispaly_x] = false; + int display_x = x / SCAN_RBW_FACTOR; + waterfall[display_x] = false; float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); freq = fr_begin + step; @@ -905,17 +909,25 @@ void loop(void) #endif // SCAN_METHOD == METHOD_RSSI // if this code is not executed LORA radio doesn't work - // basicaly SX1262 requers delay + // basically SX1262 requires delay // osd.displayString(12, 1, String(FREQ_BEGIN)); // osd.displayString(12, 30 - 8, String(FREQ_END)); // delay(2); #ifdef OSD_ENABLED osdProcess(); +#endif +#ifdef JOYSTICK_ENABLED + if (display_x == cursor_x_position) + { + display.setColor(BLACK); + display.fillRect(display_x - 20, 3, 36, 11); + display.setColor(WHITE); + } #endif detected = false; - detected_y[dispaly_x] = false; - + detected_y[display_x] = false; + max_rssi_x = 999; for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) { @@ -967,7 +979,7 @@ void loop(void) // check if we should alarm about a drone presence if ((filtered_result[y] == 1) // we have some data and && (y <= drone_detection_level) && - detected_y[dispaly_x] == false) // detection threshold match + detected_y[display_x] == false) // detection threshold match { // Set LED to ON (filtered in UI component) UI_setLedFlag(true); @@ -976,11 +988,11 @@ void loop(void) if (single_page_scan) { // Drone detection true for waterfall - if (!waterfall[dispaly_x]) + if (!waterfall[display_x]) { - waterfall[dispaly_x] = true; + waterfall[display_x] = true; display.setColor(WHITE); - display.setPixel(dispaly_x, w); + display.setPixel(display_x, w); } } #endif @@ -1022,22 +1034,22 @@ void loop(void) { // draw vertical line on top of display for "drone detected" // frequencies - if (!detected_y[dispaly_x]) + if (!detected_y[display_x]) { - display.drawLine(dispaly_x, 1, dispaly_x, 4); - detected_y[dispaly_x] = true; + display.drawLine(display_x, 1, display_x, 4); + detected_y[display_x] = true; } } } #if (WATERFALL_ENABLED == true) if ((filtered_result[y] == 1) && (y <= drone_detection_level) && - (single_page_scan) && (waterfall[dispaly_x] != true) && new_pixel) + (single_page_scan) && (waterfall[display_x] != true) && new_pixel) { // If drone not found set dark pixel on the waterfall // TODO: make something like scrolling up if possible - waterfall[dispaly_x] = false; + waterfall[display_x] = false; display.setColor(BLACK); - display.setPixel(dispaly_x, w); + display.setPixel(display_x, w); display.setColor(WHITE); } #endif @@ -1050,13 +1062,17 @@ void loop(void) if (filtered_result[y] == 1) { #ifdef PRINT_DEBUG - Serial.print("Pixel:" + String(dispaly_x) + "(" + String(x) + ")" + + Serial.print("Pixel:" + String(display_x) + "(" + String(x) + ")" + ":" + String(y) + ","); #endif + if (max_rssi_x > y) + { + max_rssi_x = y; + } // Set signal level pixel if (y < MAX_POWER_LEVELS - START_LOW) { - display.setPixel(dispaly_x, y + START_LOW); + display.setPixel(display_x, y + START_LOW); } if (!detected) { @@ -1067,24 +1083,27 @@ void loop(void) // ------------------------------------------------------------- // Draw "Detection Level line" every 2 pixel // ------------------------------------------------------------- - if ((y == drone_detection_level) && (dispaly_x % 2 == 0)) + if ((y == drone_detection_level) && (display_x % 2 == 0)) { display.setColor(WHITE); if (filtered_result[y] == 1) { display.setColor(INVERSE); } - display.setPixel(dispaly_x, y + START_LOW); - // display.setPixel(dispaly_x, y + START_LOW - 1); // 2 px wide + display.setPixel(display_x, y + START_LOW); + // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide display.setColor(WHITE); } } #ifdef JOYSTICK_ENABLED - if (dispaly_x == cursor_x_position) + if (display_x == cursor_x_position) { - display.drawString(dispaly_x, 0, String((int)freq)); - display.drawLine(dispaly_x, 1, dispaly_x, 10); + + display.drawString(display_x - 1, 0, String((int)freq)); + display.drawLine(display_x, 1, display_x, 12); + // if method scan RSSI we can get exact RSSI value + display.drawString(display_x + 17, 0, "-" + String((int)max_rssi_x * 4)); } #endif @@ -1136,7 +1155,7 @@ void loop(void) } if (button_pressed_counter > 150) { - // Remove Curent Freqancy Text + // Remove Curent Frequency Text display.setTextAlignment(TEXT_ALIGN_CENTER); display.setColor(BLACK); display.drawString(128 / 2, 0, String(freq)); @@ -1146,11 +1165,15 @@ void loop(void) } if (button_pressed_counter > 50 && button_pressed_counter < 150) { - // Visually confirm it's off so user releases button - display.displayOff(); - // Deep sleep (has wait for release so we don't wake up - // immediately) - heltec_deep_sleep(); + + if (!joy_btn_clicked) + { + // 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(); @@ -1262,6 +1285,7 @@ void loop(void) #endif loop_time = millis() - loop_start; + joy_btn_clicked = false; #ifdef PRINT_PROFILE_TIME Serial.printf("LOOP: %lld ms; SCAN: %lld ms;\n ", loop_time, scan_time); From 4ed29ce7861d3e70d41eede4248aee3553e92994 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sat, 7 Sep 2024 00:03:53 -0700 Subject: [PATCH 13/17] add Board LilyGO --- boards/t3_s3_v1_x.json | 45 ++ include/BT_WIFI_scan.h | 52 +- include/LiLyGo.h | 167 ++++++ include/LoRaBoards.cpp | 929 +++++++++++++++++++++++++++++++++ include/LoRaBoards.h | 97 ++++ include/global_config.h | 3 + include/joyStick.h | 63 +++ include/utilities.h | 551 ++++++++++++++++++++ platformio.ini | 28 +- src/main.cpp | 1100 ++++++++++++++++++++------------------- 10 files changed, 2503 insertions(+), 532 deletions(-) create mode 100644 boards/t3_s3_v1_x.json create mode 100644 include/LiLyGo.h create mode 100644 include/LoRaBoards.cpp create mode 100644 include/LoRaBoards.h create mode 100644 include/joyStick.h create mode 100644 include/utilities.h diff --git a/boards/t3_s3_v1_x.json b/boards/t3_s3_v1_x.json new file mode 100644 index 0000000..2ecfff8 --- /dev/null +++ b/boards/t3_s3_v1_x.json @@ -0,0 +1,45 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "partitions": "default.csv", + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": [ + "-DARDUINO_LILYGO_T3_S3_V1_X", + "-DBOARD_HAS_PSRAM", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1", + "-DARDUINO_USB_MODE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": [ + "wifi" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "LilyGo T3-S3 Radio", + "upload": { + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "use_1200bps_touch": true, + "wait_for_upload_port": true, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://www.lilygo.cc", + "vendor": "LilyGo" +} diff --git a/include/BT_WIFI_scan.h b/include/BT_WIFI_scan.h index 5a4722b..8313111 100644 --- a/include/BT_WIFI_scan.h +++ b/include/BT_WIFI_scan.h @@ -1,4 +1,52 @@ #pragma once -extern void scanWiFiWithOSDOut(); -extern void scanBTWithOSDOut(); +#ifdef WIFI_SCANNING_ENABLED +#include "WiFi.h" +#endif +#ifdef BT_SCANNING_ENABLED +#include +#include +#include +#include +#endif +#include "DFRobot_OSD.h" + +void setOSD() {} +// TODO: Make Async Scan +// https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/scan-examples.html#async-scan +void scanWiFi(void) +{ + osd.clear(); + osd.displayString(14, 2, "Scanning WiFi.."); + int n = WiFi.scanNetworks(); +#ifdef PRINT_DEBUG + Serial.println("scan done"); + if (n == 0) + { + Serial.println("no networks found"); + } +#endif + if (n > 0) + { +#ifdef PRINT_DEBUG + Serial.print(n); + Serial.println(" networks found"); +#endif + for (int i = 0; i < n; ++i) + { +// Print SSID and RSSI for each network found +#ifdef PRINT_DEBUG + Serial.print(i + 1); + Serial.print(": "); + Serial.print(WiFi.SSID(i)); + Serial.print(" ("); + Serial.print(WiFi.RSSI(i)); + Serial.print(")"); + Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*"); +#endif + osd.displayString(i + 1, 1, + "WF:" + String((WiFi.SSID(i) + ":" + WiFi.RSSI(i)))); + } + } + osd.displayChar(14, 1, 0x10f); +} diff --git a/include/LiLyGo.h b/include/LiLyGo.h new file mode 100644 index 0000000..ec8754c --- /dev/null +++ b/include/LiLyGo.h @@ -0,0 +1,167 @@ + +#define UNUSED_PIN (0) +// LilyGo defined + +#define I2C_SDA 18 +#define I2C_SCL 17 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 3 +#define RADIO_MOSI_PIN 6 +#define RADIO_CS_PIN 7 + +#define SDCARD_MOSI 11 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 37 +#define LED_ON HIGH + +#define BUTTON_PIN 0 +#define ADC_PIN 1 + +#define RADIO_RST_PIN 8 + +#define RADIO_DIO1_PIN 33 +#define RADIO_BUSY_PIN 34 + +// Define for our code +#define RST_OLED UNUSED_PIN +#define LED BOARD_LED + +#include "RadioLib.h" +// make sure the power off button works when using RADIOLIB_OR_HALT +// (See RadioLib_convenience.h) +#define RADIOLIB_DO_DURING_HALT heltec_delay(10) +#include "RadioLib_convenience.h" +#ifdef HELTEC_NO_DISPLAY +#define HELTEC_NO_DISPLAY_INSTANCE +#else +#define DISPLAY_WIDTH 128 +#define DISPLAY_HEIGHT 64 +#include "OLEDDisplayUi.h" +#include "SSD1306Wire.h" +#endif +#define ARDUINO_heltec_wifi_32_lora_V3 +#ifndef HELTEC_NO_RADIO_INSTANCE +#ifndef ARDUINO_heltec_wifi_32_lora_V3 +// Assume MISO and MOSI being wrong when not using Heltec's board definition +// and use hspi to make it work anyway. See heltec_setup() for the actual SPI setup. +#include +SPIClass *hspi = new SPIClass(2); +SX1262 radio = new Module(SS, DIO1, RST_LoRa, BUSY_LoRa, *hspi); +#else +// Default SPI on pins from pins_arduino.h +SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN); +#endif +#endif + +void heltec_loop() {} + +void heltec_led(int led) {} + +void heltec_deep_sleep() {} + +void heltec_delay(int millisec) { delay(millisec); } + +#ifndef HELTEC_NO_DISPLAY_INSTANCE +/** + * @class PrintSplitter + * @brief A class that splits the output of the Print class to two different + * Print objects. + * + * The PrintSplitter class is used to split the output of the Print class to two + * different Print objects. It overrides the write() function to write the data + * to both Print objects. + */ +class PrintSplitter : public Print +{ + public: + PrintSplitter(Print &_a, Print &_b) : a(_a), b(_b) {} + size_t write(uint8_t c) + { + a.write(c); + return b.write(c); + } + size_t write(const char *str) + { + a.write(str); + return b.write(str); + } + + private: + Print &a; + Print &b; +}; + +#ifdef HELTEC_WIRELESS_STICK +#define DISPLAY_GEOMETRY GEOMETRY_64_32 +#else +#define DISPLAY_GEOMETRY GEOMETRY_128_64 +#endif +SSD1306Wire display(0x3c, 18, 17, DISPLAY_GEOMETRY); +PrintSplitter both(Serial, display); +#else +Print &both = Serial; +#endif +// some fake pin +#define BUTTON 38 +#include "HotButton.h" +HotButton button(BUTTON); + +// This file contains a binary patch for the SX1262 +#include "modules/SX126x/patches/SX126x_patch_scan.h" + +void heltec_display_power(bool on) +{ +#ifndef HELTEC_NO_DISPLAY_INSTANCE + if (on) + { +#ifdef HELTEC_WIRELESS_STICK + // They hooked the display to "external" power, and didn't tell anyone + heltec_ve(true); + delay(5); +#endif + pinMode(RST_OLED, OUTPUT); + digitalWrite(RST_OLED, HIGH); + delay(1); + digitalWrite(RST_OLED, LOW); + delay(20); + digitalWrite(RST_OLED, HIGH); + } + else + { +#ifdef HELTEC_WIRELESS_STICK + heltec_ve(false); +#else + display.displayOff(); +#endif + } +#endif +} +void heltec_setup() +{ + Serial.begin(115200); + Serial.println("LILYGO BOARD"); + +#if defined(ARDUINO_ARCH_ESP32) + SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN); +#elif defined(ARDUINO_ARCH_STM32) + SPI.setMISO(RADIO_MISO_PIN); + SPI.setMOSI(RADIO_MOSI_PIN); + SPI.setSCLK(RADIO_SCLK_PIN); + SPI.begin(); +#endif + +#ifndef ARDUINO_heltec_wifi_32_lora_V3 + hspi->begin(SCK, MISO, MOSI, SS); +#endif +#ifndef HELTEC_NO_DISPLAY_INSTANCE + heltec_display_power(true); + display.init(); + display.setContrast(200); + display.flipScreenVertically(); +#endif +} diff --git a/include/LoRaBoards.cpp b/include/LoRaBoards.cpp new file mode 100644 index 0000000..04c93a6 --- /dev/null +++ b/include/LoRaBoards.cpp @@ -0,0 +1,929 @@ +/** + * @file boards.cpp + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd + * @date 2024-04-24 + * @last-update 2024-08-07 + * + */ + +#include "LoRaBoards.h" + +#if defined(HAS_SDCARD) +SPIClass SDCardSPI(HSPI); +#endif + +#if defined(ARDUINO_ARCH_STM32) +HardwareSerial SerialGPS(GPS_RX_PIN, GPS_TX_PIN); +#endif + +#if defined(ARDUINO_ARCH_ESP32) +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "hal/gpio_hal.h" +#endif +#include "driver/gpio.h" +#endif // ARDUINO_ARCH_ESP32 + +DISPLAY_MODEL *u8g2 = NULL; +static DevInfo_t devInfo; + +#ifdef HAS_GPS +static bool find_gps = false; +#endif + +#ifdef HAS_PMU +XPowersLibInterface *PMU = NULL; +bool pmuInterrupt; + +static void setPmuFlag() { pmuInterrupt = true; } +#endif + +bool beginPower() +{ +#ifdef HAS_PMU + if (!PMU) + { + PMU = new XPowersAXP2101(PMU_WIRE_PORT); + if (!PMU->init()) + { + Serial.println("Warning: Failed to find AXP2101 power management"); + delete PMU; + PMU = NULL; + } + else + { + Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU"); + } + } + + if (!PMU) + { + PMU = new XPowersAXP192(PMU_WIRE_PORT); + if (!PMU->init()) + { + Serial.println("Warning: Failed to find AXP192 power management"); + delete PMU; + PMU = NULL; + } + else + { + Serial.println("AXP192 PMU init succeeded, using AXP192 PMU"); + } + } + + if (!PMU) + { + return false; + } + + PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); + + pinMode(PMU_IRQ, INPUT_PULLUP); + attachInterrupt(PMU_IRQ, setPmuFlag, FALLING); + + if (PMU->getChipModel() == XPOWERS_AXP192) + { + + PMU->setProtectedChannel(XPOWERS_DCDC3); + + // lora + PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300); + // gps + PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300); + // oled + PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300); + + PMU->enablePowerOutput(XPOWERS_LDO2); + PMU->enablePowerOutput(XPOWERS_LDO3); + + // protected oled power source + PMU->setProtectedChannel(XPOWERS_DCDC1); + // protected esp32 power source + PMU->setProtectedChannel(XPOWERS_DCDC3); + // enable oled power + PMU->enablePowerOutput(XPOWERS_DCDC1); + + // disable not use channel + PMU->disablePowerOutput(XPOWERS_DCDC2); + + PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ); + + PMU->enableIRQ(XPOWERS_AXP192_VBUS_REMOVE_IRQ | XPOWERS_AXP192_VBUS_INSERT_IRQ | + XPOWERS_AXP192_BAT_CHG_DONE_IRQ | + XPOWERS_AXP192_BAT_CHG_START_IRQ | XPOWERS_AXP192_BAT_REMOVE_IRQ | + XPOWERS_AXP192_BAT_INSERT_IRQ | XPOWERS_AXP192_PKEY_SHORT_IRQ); + } + else if (PMU->getChipModel() == XPOWERS_AXP2101) + { + +#if defined(CONFIG_IDF_TARGET_ESP32) + // Unuse power channel + PMU->disablePowerOutput(XPOWERS_DCDC2); + PMU->disablePowerOutput(XPOWERS_DCDC3); + PMU->disablePowerOutput(XPOWERS_DCDC4); + PMU->disablePowerOutput(XPOWERS_DCDC5); + PMU->disablePowerOutput(XPOWERS_ALDO1); + PMU->disablePowerOutput(XPOWERS_ALDO4); + PMU->disablePowerOutput(XPOWERS_BLDO1); + PMU->disablePowerOutput(XPOWERS_BLDO2); + PMU->disablePowerOutput(XPOWERS_DLDO1); + PMU->disablePowerOutput(XPOWERS_DLDO2); + + // GNSS RTC PowerVDD 3300mV + PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300); + PMU->enablePowerOutput(XPOWERS_VBACKUP); + + // ESP32 VDD 3300mV + // ! No need to set, automatically open , Don't close it + // PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300); + // PMU->setProtectedChannel(XPOWERS_DCDC1); + PMU->setProtectedChannel(XPOWERS_DCDC1); + + // LoRa VDD 3300mV + PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO2); + + // GNSS VDD 3300mV + PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO3); + +#endif /*CONFIG_IDF_TARGET_ESP32*/ + +#if defined(T_BEAM_S3_SUPREME) + + // t-beam m.2 inface + // gps + PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO4); + + // lora + PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO3); + + // In order to avoid bus occupation, during initialization, the SD card and QMC + // sensor are powered off and restarted + if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) + { + Serial.println("Power off and restart ALDO BLDO.."); + PMU->disablePowerOutput(XPOWERS_ALDO1); + PMU->disablePowerOutput(XPOWERS_ALDO2); + PMU->disablePowerOutput(XPOWERS_BLDO1); + delay(250); + } + + // Sensor + PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO1); + + PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO2); + + // Sdcard + + PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300); + PMU->enablePowerOutput(XPOWERS_BLDO1); + + PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300); + PMU->enablePowerOutput(XPOWERS_BLDO2); + + // face m.2 + PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC3); + + PMU->setPowerChannelVoltage(XPOWERS_DCDC4, XPOWERS_AXP2101_DCDC4_VOL2_MAX); + PMU->enablePowerOutput(XPOWERS_DCDC4); + + PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC5); + + // not use channel + PMU->disablePowerOutput(XPOWERS_DCDC2); + // PMU->disablePowerOutput(XPOWERS_DCDC4); + // PMU->disablePowerOutput(XPOWERS_DCDC5); + PMU->disablePowerOutput(XPOWERS_DLDO1); + PMU->disablePowerOutput(XPOWERS_DLDO2); + PMU->disablePowerOutput(XPOWERS_VBACKUP); + +#elif defined(T_BEAM_S3_BPF) + + // gps + PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO4); + + // Sdcard + PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO2); + + // Extern Power source + PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC3); + + PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC5); + + PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO1); + + // not use channel + PMU->disablePowerOutput(XPOWERS_BLDO1); + PMU->disablePowerOutput(XPOWERS_BLDO2); + PMU->disablePowerOutput(XPOWERS_DCDC4); + PMU->disablePowerOutput(XPOWERS_DCDC2); + PMU->disablePowerOutput(XPOWERS_DCDC4); + PMU->disablePowerOutput(XPOWERS_DCDC5); + PMU->disablePowerOutput(XPOWERS_DLDO1); + PMU->disablePowerOutput(XPOWERS_DLDO2); + PMU->disablePowerOutput(XPOWERS_VBACKUP); + +#endif + + // Set constant current charge current limit + PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA); + + // Set charge cut-off voltage + PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); + + // Disable all interrupts + PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + // Clear all interrupt flags + PMU->clearIrqStatus(); + // Enable the required interrupt function + PMU->enableIRQ( + XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // BATTERY + XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS + XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // POWER KEY + XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // CHARGE + // XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | + // //POWER KEY + ); + } + + PMU->enableSystemVoltageMeasure(); + PMU->enableVbusVoltageMeasure(); + PMU->enableBattVoltageMeasure(); + + Serial.printf("=========================================\n"); + if (PMU->isChannelAvailable(XPOWERS_DCDC1)) + { + Serial.printf("DC1 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC1)); + } + if (PMU->isChannelAvailable(XPOWERS_DCDC2)) + { + Serial.printf("DC2 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC2)); + } + if (PMU->isChannelAvailable(XPOWERS_DCDC3)) + { + Serial.printf("DC3 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC3)); + } + if (PMU->isChannelAvailable(XPOWERS_DCDC4)) + { + Serial.printf("DC4 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC4)); + } + if (PMU->isChannelAvailable(XPOWERS_DCDC5)) + { + Serial.printf("DC5 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC5) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC5)); + } + if (PMU->isChannelAvailable(XPOWERS_LDO2)) + { + Serial.printf("LDO2 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_LDO2)); + } + if (PMU->isChannelAvailable(XPOWERS_LDO3)) + { + Serial.printf("LDO3 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_LDO3)); + } + if (PMU->isChannelAvailable(XPOWERS_ALDO1)) + { + Serial.printf("ALDO1: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_ALDO1)); + } + if (PMU->isChannelAvailable(XPOWERS_ALDO2)) + { + Serial.printf("ALDO2: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_ALDO2)); + } + if (PMU->isChannelAvailable(XPOWERS_ALDO3)) + { + Serial.printf("ALDO3: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_ALDO3)); + } + if (PMU->isChannelAvailable(XPOWERS_ALDO4)) + { + Serial.printf("ALDO4: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_ALDO4)); + } + if (PMU->isChannelAvailable(XPOWERS_BLDO1)) + { + Serial.printf("BLDO1: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_BLDO1)); + } + if (PMU->isChannelAvailable(XPOWERS_BLDO2)) + { + Serial.printf("BLDO2: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_BLDO2)); + } + Serial.printf("=========================================\n"); + + // Set the time of pressing the button to turn off + PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); + uint8_t opt = PMU->getPowerKeyPressOffTime(); + Serial.print("PowerKeyPressOffTime:"); + switch (opt) + { + case XPOWERS_POWEROFF_4S: + Serial.println("4 Second"); + break; + case XPOWERS_POWEROFF_6S: + Serial.println("6 Second"); + break; + case XPOWERS_POWEROFF_8S: + Serial.println("8 Second"); + break; + case XPOWERS_POWEROFF_10S: + Serial.println("10 Second"); + break; + default: + break; + } +#endif + return true; +} + +void disablePeripherals() +{ + +#ifdef HAS_PMU + if (!PMU) + return; +#if defined(T_BEAM_S3_BPF) + PMU->disablePowerOutput(XPOWERS_ALDO4); // gps + PMU->disablePowerOutput(XPOWERS_ALDO2); // Sdcard + PMU->disablePowerOutput(XPOWERS_DCDC3); // Extern Power source + PMU->disablePowerOutput(XPOWERS_DCDC5); + PMU->disablePowerOutput(XPOWERS_ALDO1); +#endif +#endif +} + +void loopPMU() +{ +#ifdef HAS_PMU + if (!PMU) + { + return; + } + if (!pmuInterrupt) + { + return; + } + + pmuInterrupt = false; + // Get PMU Interrupt Status Register + uint32_t status = PMU->getIrqStatus(); + Serial.print("STATUS => HEX:"); + Serial.print(status, HEX); + Serial.print(" BIN:"); + Serial.println(status, BIN); + + if (PMU->isVbusInsertIrq()) + { + Serial.println("isVbusInsert"); + } + if (PMU->isVbusRemoveIrq()) + { + Serial.println("isVbusRemove"); + } + if (PMU->isBatInsertIrq()) + { + Serial.println("isBatInsert"); + } + if (PMU->isBatRemoveIrq()) + { + Serial.println("isBatRemove"); + } + if (PMU->isPekeyShortPressIrq()) + { + Serial.println("isPekeyShortPress"); + } + if (PMU->isPekeyLongPressIrq()) + { + Serial.println("isPekeyLongPress"); + } + if (PMU->isBatChagerDoneIrq()) + { + Serial.println("isBatChagerDone"); + } + if (PMU->isBatChagerStartIrq()) + { + Serial.println("isBatChagerStart"); + } + // Clear PMU Interrupt Status Register + PMU->clearIrqStatus(); +#endif +} + +bool beginDisplay() +{ + Wire.beginTransmission(DISPLAY_ADDR); + if (Wire.endTransmission() == 0) + { + Serial.printf("Find Display model at 0x%X address\n", DISPLAY_ADDR); + u8g2 = new DISPLAY_MODEL(U8G2_R0, U8X8_PIN_NONE); + u8g2->begin(); + u8g2->clearBuffer(); + u8g2->setFont(u8g2_font_inb19_mr); + u8g2->drawStr(0, 30, "LilyGo"); + u8g2->drawHLine(2, 35, 47); + u8g2->drawHLine(3, 36, 47); + u8g2->drawVLine(45, 32, 12); + u8g2->drawVLine(46, 33, 12); + u8g2->setFont(u8g2_font_inb19_mf); + u8g2->drawStr(58, 60, "LoRa"); + u8g2->sendBuffer(); + u8g2->setFont(u8g2_font_fur11_tf); + delay(3000); + return true; + } + + Serial.printf("Warning: Failed to find Display at 0x%0X address\n", DISPLAY_ADDR); + return false; +} + +bool beginSDCard() +{ +#ifdef SDCARD_CS + if (SD.begin(SDCARD_CS, SDCardSPI)) + { + uint32_t cardSize = SD.cardSize() / (1024 * 1024); + Serial.print("Sd Card init succeeded, The current available capacity is "); + Serial.print(cardSize / 1024.0); + Serial.println(" GB"); + return true; + } + else + { + Serial.println("Warning: Failed to init Sd Card"); + } +#endif + return false; +} + +void beginWiFi() +{ + if (!WiFi.softAP(BOARD_VARIANT_NAME)) + { + log_e("Soft AP creation failed."); + } + IPAddress myIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(myIP); +} + +void printWakeupReason() +{ +#ifdef ESP32 + Serial.print("Reset reason:"); + esp_sleep_wakeup_cause_t wakeup_reason; + wakeup_reason = esp_sleep_get_wakeup_cause(); + switch (wakeup_reason) + { + case ESP_SLEEP_WAKEUP_UNDEFINED: + Serial.println( + " In case of deep sleep, reset was not caused by exit from deep sleep"); + break; + case ESP_SLEEP_WAKEUP_ALL: + break; + case ESP_SLEEP_WAKEUP_EXT0: + Serial.println("Wakeup caused by external signal using RTC_IO"); + break; + case ESP_SLEEP_WAKEUP_EXT1: + Serial.println("Wakeup caused by external signal using RTC_CNTL"); + break; + case ESP_SLEEP_WAKEUP_TIMER: + Serial.println("Wakeup caused by timer"); + break; + case ESP_SLEEP_WAKEUP_TOUCHPAD: + Serial.println("Wakeup caused by touchpad"); + break; + case ESP_SLEEP_WAKEUP_ULP: + Serial.println("Wakeup caused by ULP program"); + break; + default: + Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); + break; + } +#endif +} + +void getChipInfo() +{ +#if defined(ARDUINO_ARCH_ESP32) + + Serial.println("-----------------------------------"); + + printWakeupReason(); + +#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3) + + if (psramFound()) + { + uint32_t psram = ESP.getPsramSize(); + devInfo.psramSize = psram / 1024.0 / 1024.0; + Serial.printf("PSRAM is enable! PSRAM: %.2fMB\n", devInfo.psramSize); + } + else + { + Serial.println("PSRAM is disable!"); + devInfo.psramSize = 0; + } + +#endif + + Serial.print("Flash:"); + devInfo.flashSize = ESP.getFlashChipSize() / 1024.0 / 1024.0; + devInfo.flashSpeed = ESP.getFlashChipSpeed() / 1000 / 1000; + devInfo.chipModel = ESP.getChipModel(); + devInfo.chipModelRev = ESP.getChipRevision(); + devInfo.chipFreq = ESP.getCpuFreqMHz(); + + Serial.print(devInfo.flashSize); + Serial.println(" MB"); + Serial.print("Flash speed:"); + Serial.print(devInfo.flashSpeed); + Serial.println(" M"); + Serial.print("Model:"); + + Serial.println(devInfo.chipModel); + Serial.print("Chip Revision:"); + Serial.println(devInfo.chipModelRev); + Serial.print("Freq:"); + Serial.print(devInfo.chipFreq); + Serial.println(" MHZ"); + Serial.print("SDK Ver:"); + Serial.println(ESP.getSdkVersion()); + Serial.print("DATE:"); + Serial.println(__DATE__); + Serial.print("TIME:"); + Serial.println(__TIME__); + + Serial.print("EFUSE MAC: "); + Serial.print(ESP.getEfuseMac(), HEX); + Serial.println(); + + Serial.println("-----------------------------------"); + +#elif defined(ARDUINO_ARCH_STM32) + uint32_t uid[3]; + + uid[0] = HAL_GetUIDw0(); + uid[1] = HAL_GetUIDw1(); + uid[2] = HAL_GetUIDw2(); + Serial.print("STM UID: 0X"); + Serial.print(uid[0], HEX); + Serial.print(uid[1], HEX); + Serial.print(uid[2], HEX); + Serial.println(); +#endif +} + +void setupBoards(bool disable_u8g2) +{ + Serial.begin(115200); + + // while (!Serial); + + Serial.println("setupBoards"); + + getChipInfo(); + +#if defined(ARDUINO_ARCH_ESP32) + SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN); +#elif defined(ARDUINO_ARCH_STM32) + SPI.setMISO(RADIO_MISO_PIN); + SPI.setMOSI(RADIO_MOSI_PIN); + SPI.setSCLK(RADIO_SCLK_PIN); + SPI.begin(); +#endif + +#ifdef HAS_SDCARD + SDCardSPI.begin(SDCARD_SCLK, SDCARD_MISO, SDCARD_MOSI); +#endif + +#ifdef I2C_SDA + Wire.begin(I2C_SDA, I2C_SCL); + scanDevices(&Wire); +#endif + +#ifdef I2C1_SDA + Wire1.begin(I2C1_SDA, I2C1_SCL); +#endif + +#ifdef HAS_GPS +#if defined(ARDUINO_ARCH_ESP32) + SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); +#elif defined(ARDUINO_ARCH_STM32) + SerialGPS.setRx(GPS_RX_PIN); + SerialGPS.setTx(GPS_TX_PIN); + SerialGPS.begin(GPS_BAUD_RATE); +#endif // ARDUINO_ARCH_ +#endif // HAS_GPS + +#if OLED_RST + pinMode(OLED_RST, OUTPUT); + digitalWrite(OLED_RST, HIGH); + delay(20); + digitalWrite(OLED_RST, LOW); + delay(20); + digitalWrite(OLED_RST, HIGH); + delay(20); +#endif + +#ifdef BOARD_LED + /* + * T-Beam LED defaults to low level as turn on, + * so it needs to be forced to pull up + * * * * */ +#if LED_ON == LOW +#if defined(ARDUINO_ARCH_ESP32) + gpio_hold_dis((gpio_num_t)BOARD_LED); +#endif // ARDUINO_ARCH_ESP32 +#endif + + pinMode(BOARD_LED, OUTPUT); + digitalWrite(BOARD_LED, LED_ON); +#endif + +#ifdef GPS_EN_PIN + pinMode(GPS_EN_PIN, OUTPUT); + digitalWrite(GPS_EN_PIN, HIGH); +#endif + +#ifdef GPS_RST_PIN + pinMode(GPS_RST_PIN, OUTPUT); + digitalWrite(GPS_RST_PIN, HIGH); +#endif + +#if defined(ARDUINO_ARCH_STM32) + SerialGPS.println("@GSR"); + delay(300); + SerialGPS.println("@GSR"); + delay(300); + SerialGPS.println("@GSR"); + delay(300); + SerialGPS.println("@GSR"); + delay(300); + SerialGPS.println("@GSR"); + delay(300); +#endif + +#ifdef RADIO_LDO_EN + pinMode(RADIO_LDO_EN, OUTPUT); + digitalWrite(RADIO_LDO_EN, HIGH); +#endif + + beginPower(); + + beginSDCard(); + + if (!disable_u8g2) + { + beginDisplay(); + } + + beginWiFi(); + +#ifdef HAS_GPS +#ifdef T_BEAM_S3_BPF + find_gps = beginGPS(); +#endif +#endif + + Serial.println("init done . "); +} + +void printResult(bool radio_online) +{ + Serial.print("Radio : "); + Serial.println((radio_online) ? "+" : "-"); + +#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3) + + Serial.print("PSRAM : "); + Serial.println((psramFound()) ? "+" : "-"); + + Serial.print("Display : "); + Serial.println((u8g2) ? "+" : "-"); + +#ifdef HAS_SDCARD + Serial.print("Sd Card : "); + Serial.println((SD.cardSize() != 0) ? "+" : "-"); +#endif + +#ifdef HAS_PMU + Serial.print("Power : "); + Serial.println((PMU) ? "+" : "-"); +#endif + +#ifdef HAS_GPS +#ifdef T_BEAM_S3_BPF + Serial.print("GPS : "); + Serial.println((find_gps) ? "+" : "-"); +#endif +#endif + + if (u8g2) + { + + u8g2->clearBuffer(); + u8g2->setFont(u8g2_font_NokiaLargeBold_tf); + uint16_t str_w = u8g2->getStrWidth(BOARD_VARIANT_NAME); + u8g2->drawStr((u8g2->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME); + u8g2->drawHLine(5, 21, u8g2->getWidth() - 5); + + u8g2->drawStr(0, 38, "Disp:"); + u8g2->drawStr(45, 38, (u8g2) ? "+" : "-"); + +#ifdef HAS_SDCARD + u8g2->drawStr(0, 54, "SD :"); + u8g2->drawStr(45, 54, (SD.cardSize() != 0) ? "+" : "-"); +#endif + + u8g2->drawStr(62, 38, "Radio:"); + u8g2->drawStr(120, 38, (radio_online) ? "+" : "-"); + +#ifdef HAS_PMU + u8g2->drawStr(62, 54, "Power:"); + u8g2->drawStr(120, 54, (PMU) ? "+" : "-"); +#endif + + u8g2->sendBuffer(); + + delay(2000); + } +#endif +} + +static uint8_t ledState = LOW; +static const uint32_t debounceDelay = 50; +static uint32_t lastDebounceTime = 0; + +void flashLed() +{ +#ifdef BOARD_LED + if ((millis() - lastDebounceTime) > debounceDelay) + { + ledState = !ledState; + if (ledState) + { + digitalWrite(BOARD_LED, LED_ON); + } + else + { + digitalWrite(BOARD_LED, !LED_ON); + } + lastDebounceTime = millis(); + } +#endif +} + +void scanDevices(TwoWire *w) +{ + uint8_t err, addr; + int nDevices = 0; + uint32_t start = 0; + + Serial.println("I2C Devices scanning"); + for (addr = 1; addr < 127; addr++) + { + start = millis(); + w->beginTransmission(addr); + delay(2); + err = w->endTransmission(); + if (err == 0) + { + nDevices++; + switch (addr) + { + case 0x77: + case 0x76: + Serial.println("\tFind BMX280 Sensor!"); + break; + case 0x34: + Serial.println("\tFind AXP192/AXP2101 PMU!"); + break; + case 0x3C: + Serial.println("\tFind SSD1306/SH1106 dispaly!"); + break; + case 0x51: + Serial.println("\tFind PCF8563 RTC!"); + break; + case 0x1C: + Serial.println("\tFind QMC6310 MAG Sensor!"); + break; + default: + Serial.print("\tI2C device found at address 0x"); + if (addr < 16) + { + Serial.print("0"); + } + Serial.print(addr, HEX); + Serial.println(" !"); + break; + } + } + else if (err == 4) + { + Serial.print("Unknow error at address 0x"); + if (addr < 16) + { + Serial.print("0"); + } + Serial.println(addr, HEX); + } + } + if (nDevices == 0) + Serial.println("No I2C devices found\n"); + + Serial.println("Scan devices done."); + Serial.println("\n"); +} + +#ifdef HAS_GPS +bool beginGPS() +{ + SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); + bool result = false; + uint32_t startTimeout; + for (int i = 0; i < 3; ++i) + { + SerialGPS.write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n"); + delay(5); + // Get version information + startTimeout = millis() + 3000; + Serial.print("Try to init L76K . Wait stop ."); + while (SerialGPS.available()) + { + Serial.print("."); + SerialGPS.readString(); + if (millis() > startTimeout) + { + Serial.println("Wait L76K stop NMEA timeout!"); + return false; + } + }; + Serial.println(); + SerialGPS.flush(); + delay(200); + + SerialGPS.write("$PCAS06,0*1B\r\n"); + startTimeout = millis() + 500; + String ver = ""; + while (!SerialGPS.available()) + { + if (millis() > startTimeout) + { + Serial.println("Get L76K timeout!"); + return false; + } + } + SerialGPS.setTimeout(10); + ver = SerialGPS.readStringUntil('\n'); + if (ver.startsWith("$GPTXT,01,01,02")) + { + Serial.println("L76K GNSS init succeeded, using L76K GNSS Module\n"); + result = true; + break; + } + delay(500); + } + // Initialize the L76K Chip, use GPS + GLONASS + SerialGPS.write("$PCAS04,5*1C\r\n"); + delay(250); + // only ask for RMC and GGA + SerialGPS.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n"); + delay(250); + // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g + SerialGPS.write("$PCAS11,3*1E\r\n"); + return result; +} +#endif diff --git a/include/LoRaBoards.h b/include/LoRaBoards.h new file mode 100644 index 0000000..655376e --- /dev/null +++ b/include/LoRaBoards.h @@ -0,0 +1,97 @@ +/** + * @file boards.h + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd + * @date 2024-04-25 + * @last-update 2024-08-07 + */ + +#pragma once + +#include "utilities.h" + +#ifdef HAS_SDCARD +#include +#endif + +#if defined(ARDUINO_ARCH_ESP32) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#ifndef DISPLAY_MODEL +#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C +#endif + +#ifndef OLED_WIRE_PORT +#define OLED_WIRE_PORT Wire +#endif + +#ifndef PMU_WIRE_PORT +#define PMU_WIRE_PORT Wire +#endif + +#ifndef DISPLAY_ADDR +#define DISPLAY_ADDR 0x3C +#endif + +#ifndef LORA_FREQ_CONFIG +#define LORA_FREQ_CONFIG 915.0 +#endif + +typedef struct +{ + String chipModel; + float psramSize; + uint8_t chipModelRev; + uint8_t chipFreq; + uint8_t flashSize; + uint8_t flashSpeed; +} DevInfo_t; + +void setupBoards(bool disable_u8g2 = false); + +bool beginSDCard(); + +bool beginDisplay(); + +void disablePeripherals(); + +bool beginPower(); + +void printResult(bool radio_online); + +void flashLed(); + +void scanDevices(TwoWire *w); + +bool beginGPS(); + +void loopPMU(); + +#ifdef HAS_PMU +extern XPowersLibInterface *PMU; +extern bool pmuInterrupt; +#endif +extern DISPLAY_MODEL *u8g2; + +#define U8G2_HOR_ALIGN_CENTER(t) ((u8g2->getDisplayWidth() - (u8g2->getUTF8Width(t))) / 2) +#define U8G2_HOR_ALIGN_RIGHT(t) (u8g2->getDisplayWidth() - u8g2->getUTF8Width(t)) + +#if defined(ARDUINO_ARCH_ESP32) + +#if defined(HAS_SDCARD) +extern SPIClass SDCardSPI; +#endif + +#define SerialGPS Serial1 +#elif defined(ARDUINO_ARCH_STM32) +extern HardwareSerial SerialGPS; +#endif diff --git a/include/global_config.h b/include/global_config.h index ded70ae..d169fff 100644 --- a/include/global_config.h +++ b/include/global_config.h @@ -22,4 +22,7 @@ #define WATERFALL_ENABLED true #define WATERFALL_START 37 +#ifdef LILYGO +#define LED 46 +#endif // end not LILYGO #endif diff --git a/include/joyStick.h b/include/joyStick.h new file mode 100644 index 0000000..ae10fd8 --- /dev/null +++ b/include/joyStick.h @@ -0,0 +1,63 @@ +// Joystick integration +constexpr int JOY_X_PIN = 19; +int cursor_x_position = 0; +// Not integrated yet constexpr int JOY_Y_PIN = N/A; +constexpr int JOY_BTN_PIN = 46; +bool joy_btn_clicked = false; + +// Joystick integration +bool joy_btn_click() +{ + joy_btn_clicked = true; + // is the output from the pushbutton inside the joystick. It’s normally open. If we + // use a pull-up resistor in this pin, the SW pin will be HIGH + // when it is not pressed, and LOW when Pressed. + return digitalRead(JOY_BTN_PIN) == HIGH ? false : true; +} + +int joyXMid = 0; +int cal_X = 0, cal_Y = 0; + +void calibrate_joy() +{ + for (int i = 0; i < 100; i++) + { + cal_X += analogRead(JOY_X_PIN); + } + // calibrate center + joyXMid = cal_X / 100; +} + +int MID = 100; // 10 mid point delta arduino, use 4 for attiny +int get_joy_x(bool logical = false) +{ + int joyX = analogRead(JOY_X_PIN); + + /* + Serial.print("Calibrated_X_Voltage = "); + Serial.print(joyXMid); + Serial.print("X_Voltage = "); + Serial.print(joyX); + Serial.print("\t"); + */ + + if (logical) + { + // 4095 + if (joyX < joyXMid - MID) + { + return -1; + } + // 0-5 + else if (joyX > joyXMid + MID) + { + return 1; + } + else + { + return 0; + } + } + + return joyX; +} diff --git a/include/utilities.h b/include/utilities.h new file mode 100644 index 0000000..1d1b3ef --- /dev/null +++ b/include/utilities.h @@ -0,0 +1,551 @@ +/** + * @file utilities.h + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd + * @date 2024-05-12 + * @last-update 2024-08-07 + */ +#pragma once + +// Support board list , Macro definition below, select the board definition to be used + +// #define T3_V1_3_SX1276 +// #define T3_V1_3_SX1278 + +// #define T3_V1_6_SX1276 +// #define T3_V1_6_SX1278 + +// #define T3_V1_6_SX1276_TCXO +// #define T3_V3_0_SX1276_TCXO + +// #define T_BEAM_SX1262 +// #define T_BEAM_SX1276 +// #define T_BEAM_SX1278 + +// #define T_BEAM_S3_SUPREME + +// #define T3_S3_V1_2_SX1262 +// #define T3_S3_V1_2_SX1276 +// #define T3_S3_V1_2_SX1278 +// #define T3_S3_V1_2_SX1280 +// #define T3_S3_V1_2_SX1280_PA +// #define T3_S3_V1_2_LR1121 + +// #define T_MOTION + +// #define T3_C6 + +// #define T_BEAM_S3_BPF + +#define UNUSED_PIN (0) + +#if defined(T_BEAM_SX1262) || defined(T_BEAM_SX1276) || defined(T_BEAM_SX1278) + +#if defined(T_BEAM_SX1262) +#ifndef USING_SX1262 +#define USING_SX1262 +#endif +#elif defined(T_BEAM_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T_BEAM_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#endif // T_BEAM_SX1262 + +#define GPS_RX_PIN 34 +#define GPS_TX_PIN 12 +#define BUTTON_PIN 38 +#define BUTTON_PIN_MASK GPIO_SEL_38 +#define I2C_SDA 21 +#define I2C_SCL 22 +#define PMU_IRQ 35 + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN 33 +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + +#define BOARD_LED 4 +#define LED_ON LOW +#define LED_OFF HIGH + +#define GPS_BAUD_RATE 9600 +#define HAS_GPS +#define HAS_DISPLAY // Optional, bring your own board, no OLED !! +#define HAS_PMU + +#define BOARD_VARIANT_NAME "T-Beam" + +#elif defined(T3_V1_3_SX1276) || defined(T3_V1_3_SX1278) + +#if defined(T3_V1_3_SX1276) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + +#elif defined(T3_V1_3_SX1278) + +#ifndef USING_SX1278 +#define USING_SX1278 +#endif + +#endif // T3_V1_3_SX1276 + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 14 +#define RADIO_DIO1_PIN 33 + +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + +#define ADC_PIN 35 +#define HAS_DISPLAY +#define BOARD_VARIANT_NAME "T3 V1.3" + +#elif defined(T3_V1_6_SX1276) || defined(T3_V1_6_SX1278) + +#if defined(T3_V1_6_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T3_V1_6_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#endif // T3_V1_6_SX1276 + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN 33 +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V1.6" + +#elif defined(T3_V1_6_SX1276_TCXO) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN -1 // 33 +/* + * In the T3 V1.6.1 TCXO version, Radio DIO1 is connected to Radio’s + * internal temperature-compensated crystal oscillator enable + * */ +// TCXO pin must be set to HIGH before enabling Radio +#define RADIO_TCXO_ENABLE 33 +#define RADIO_BUSY_PIN 32 + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V1.6 TCXO" + +#elif defined(T3_V3_0) + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST 4 + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_RST_PIN 23 + +// TCXO pin must be set to HIGH before enabling Radio +#define RADIO_TCXO_ENABLE 12 // only sx1276 tcxo version +#define RADIO_BUSY_PIN 32 + +#if defined(USING_SX1262) + +#define RADIO_DIO1_PIN 26 +#define RADIO_BUSY_PIN 32 + +#elif defined(USING_SX1276) || defined(USING_SX1278) +//! SX1276/78 module only + +#define RADIO_DIO0_PIN 26 +#define RADIO_DIO1_PIN 32 + +#elif defined(USING_LR1121) + +#define RADIO_DIO9_PIN 26 // LR1121 DIO9 +#define RADIO_BUSY_PIN 32 // LR1121 BUSY + +#endif + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V3.0" + +#define BUTTON_PIN 0 +#define BAT_ADC_PIN 35 + +#elif defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) || \ + defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) || \ + defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) || \ + defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) || \ + defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) || \ + defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) + +#if defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) +#ifndef USING_SX1262 +#define USING_SX1262 +#endif +#elif defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#elif defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) +#ifndef USING_SX1280 +#define USING_SX1280 +#endif +#elif defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) +#ifndef USING_SX1280PA +#define USING_SX1280PA +#endif +#elif defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) +#ifndef USING_LR1121 +#define USING_LR1121 +#endif + +#endif // T3_S3_V1_2_SX1262 + +#define I2C_SDA 18 +#define I2C_SCL 17 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 3 +#define RADIO_MOSI_PIN 6 +#define RADIO_CS_PIN 7 + +#define SDCARD_MOSI 11 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 37 +#define LED_ON HIGH + +#define BUTTON_PIN 0 +#define ADC_PIN 1 + +#define RADIO_RST_PIN 8 + +#if defined(USING_SX1262) + +#define RADIO_DIO1_PIN 33 +#define RADIO_BUSY_PIN 34 + +#elif defined(USING_SX1276) || defined(USING_SX1278) +//! SX1276/78 module only +#define RADIO_BUSY_PIN 33 // DIO1 + +#define RADIO_DIO0_PIN 9 +#define RADIO_DIO1_PIN 33 +#define RADIO_DIO2_PIN 34 +#define RADIO_DIO3_PIN 21 +#define RADIO_DIO4_PIN 10 +#define RADIO_DIO5_PIN 36 + +#elif defined(USING_SX1280) + +#define RADIO_DIO1_PIN 9 // SX1280 DIO1 = IO9 +#define RADIO_BUSY_PIN 36 // SX1280 BUSY = IO36 + +#elif defined(USING_SX1280PA) + +#define RADIO_DIO1_PIN 9 // SX1280 DIO1 = IO9 +#define RADIO_BUSY_PIN 36 // SX1280 BUSY = IO36 +#define RADIO_RX_PIN 21 +#define RADIO_TX_PIN 10 + +#elif defined(USING_LR1121) + +#define RADIO_DIO9_PIN 36 // LR1121 DIO9 = IO36 +#define RADIO_BUSY_PIN 34 // LR1121 BUSY = IO34 + +#endif + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 S3 V1.X" + +#elif defined(T_BEAM_S3_SUPREME) + +#ifndef USING_SX1262 +#define USING_SX1262 +#endif + +#define I2C_SDA 17 +#define I2C_SCL 18 + +#define I2C1_SDA 42 +#define I2C1_SCL 41 +#define PMU_IRQ 40 + +#define GPS_RX_PIN 9 +#define GPS_TX_PIN 8 +#define GPS_WAKEUP_PIN 7 +#define GPS_PPS_PIN 6 + +#define BUTTON_PIN 0 +#define BUTTON_PIN_MASK GPIO_SEL_0 +#define BUTTON_CONUT (1) +#define BUTTON_ARRAY {BUTTON_PIN} + +#define RADIO_SCLK_PIN (12) +#define RADIO_MISO_PIN (13) +#define RADIO_MOSI_PIN (11) +#define RADIO_CS_PIN (10) +#define RADIO_DIO0_PIN (-1) +#define RADIO_RST_PIN (5) +#define RADIO_DIO1_PIN (1) +#define RADIO_BUSY_PIN (4) + +#define SPI_MOSI (35) +#define SPI_SCK (36) +#define SPI_MISO (37) +#define SPI_CS (47) +#define IMU_CS (34) +#define IMU_INT (33) + +#define SDCARD_MOSI SPI_MOSI +#define SDCARD_MISO SPI_MISO +#define SDCARD_SCLK SPI_SCK +#define SDCARD_CS SPI_CS + +#define PIN_NONE (-1) +#define RTC_INT (14) + +#define GPS_BAUD_RATE 9600 + +#define HAS_SDCARD +#define HAS_GPS +#define HAS_DISPLAY +#define HAS_PMU + +#define __HAS_SPI1__ +#define __HAS_SENSOR__ + +#define PMU_WIRE_PORT Wire1 +#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C +#define BOARD_VARIANT_NAME "T-Beam S3" + +#elif defined(T_MOTION_S76G) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + +#define RADIO_SCLK_PIN PB13 +#define RADIO_MISO_PIN PB14 +#define RADIO_MOSI_PIN PB15 +#define RADIO_CS_PIN PB12 +#define RADIO_RST_PIN PB10 + +#define RADIO_DIO0_PIN PB11 +#define RADIO_DIO1_PIN PC13 +#define RADIO_DIO2_PIN PB9 +#define RADIO_DIO3_PIN PB4 +#define RADIO_DIO4_PIN PB3 +#define RADIO_DIO5_PIN PA15 + +#undef RADIO_BUSY_PIN +#undef RADIO_DIO1_PIN +#define RADIO_BUSY_PIN PC13 // DIO1 +#define RADIO_DIO1_PIN PB11 // DIO0 + +#define RADIO_SWITCH_PIN PA1 // 1:Rx, 0:Tx + +#define GPS_EN_PIN PC6 +#define GPS_RST_PIN PB2 +#define GPS_RX_PIN PC11 +#define GPS_TX_PIN PC10 +#define GPS_ENABLE_PIN PC6 +#define GPS_BAUD_RATE 115200 +#define GPS_PPS_PIN PB5 + +#define UART_RX_PIN PA10 +#define UART_TX_PIN PA9 + +#define I2C_SCL PB6 +#define I2C_SDA PB7 + +#define BOARD_VARIANT_NAME "T-Motion S76G" + +#define HAS_GPS + +#elif defined(T3_C6) + +#ifndef USING_SX1262 +#define USING_SX1262 +#endif + +#define RADIO_SCLK_PIN 6 +#define RADIO_MISO_PIN 1 +#define RADIO_MOSI_PIN 0 +#define RADIO_CS_PIN 18 +#define RADIO_DIO1_PIN 23 +#define RADIO_BUSY_PIN 22 +#define RADIO_RST_PIN 21 + +#define I2C_SDA 8 +#define I2C_SCL 9 + +#define BOARD_LED 7 +#define LED_ON HIGH +#define RADIO_RX_PIN 15 +#define RADIO_TX_PIN 14 + +#define BOARD_VARIANT_NAME "T3-C6" + +#define USING_DIO2_AS_RF_SWITCH + +#elif defined(T_BEAM_S3_BPF) + +#ifndef USING_SX1278 +#define USING_SX1278 +#endif + +#define I2C_SDA 8 +#define I2C_SCL 9 + +#define PMU_IRQ 4 + +#define GPS_RX_PIN 5 +#define GPS_TX_PIN 6 +#define GPS_PPS_PIN 7 + +#define BUTTON_PIN 0 +#define BUTTON_PIN_MASK GPIO_SEL_0 +#define BUTTON_CONUT (2) +#define BUTTON_ARRAY {BUTTON_PIN, 3} + +#define RADIO_SCLK_PIN (41) +#define RADIO_MISO_PIN (42) +#define RADIO_MOSI_PIN (2) +#define RADIO_CS_PIN (1) +#define RADIO_RST_PIN (18) + +#define RADIO_DIO0_PIN (14) +#define RADIO_DIO1_PIN (21) +#define RADIO_DIO2_PIN (15) + +#define RADIO_TCXO_ENABLE (17) +#define RADIO_LDO_EN (16) +#define RADIO_BUSY_PIN (RADIO_DIO1_PIN) + +#define SPI_MOSI (11) +#define SPI_SCK (12) +#define SPI_MISO (13) +#define SPI_CS (10) + +#define SDCARD_MOSI SPI_MOSI +#define SDCARD_MISO SPI_MISO +#define SDCARD_SCLK SPI_SCK +#define SDCARD_CS SPI_CS + +#define PIN_NONE (-1) + +#define GPS_BAUD_RATE 9600 + +#define HAS_SDCARD +#define HAS_GPS +#define HAS_DISPLAY +#define HAS_PMU + +#define __HAS_SPI1__ +#define __HAS_SENSOR__ + +#define PMU_WIRE_PORT Wire +#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C +#define BOARD_VARIANT_NAME "T-Beam BPF" + +#else +#error "When using it for the first time, please define the board model in " +#endif diff --git a/platformio.ini b/platformio.ini index e7d2dec..e89e8e3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,13 +18,36 @@ platform = espressif32 board = heltec_wifi_lora_32_V3 framework = arduino -upload_speed = 115200 +upload_speed = 921600 monitor_speed = 115200 board_build.f_cpu = 240000000 lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 build_flags = -DHELTEC_POWER_BUTTON +[env:lilygo-T3S3-v1-2] +platform = espressif32 +board = t3_s3_v1_x ;platformio doesn't have right boatd check local boards bolder +framework = arduino +upload_speed = 921600 +monitor_speed = 115200 +board_build.f_cpu = 240000000 +lib_deps = + ropg/Heltec_ESP32_LoRa_v3@^0.9.1 + RadioLib +build_flags = + -DLILYGO ; flag for our code + -DT3_S3_V1_2_SX1262 + -DT3_V1_3_SX1262 + -DARDUINO_LILYGO_T3S3_SX1262 + -DESP32 + -DUSING_SX1262 + -DARDUINO_ARCH_ESP32 + -DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_LILYGO_T3_S3_V1_X + -DARDUINO_USB_MODE=1 + ;-UARDUINO_USB_CDC_ON_BOOT + [env:heltec_wifi_lora_32_V3-test-signal-generator] platform = espressif32 board = heltec_wifi_lora_32_V3 @@ -32,9 +55,10 @@ framework = arduino upload_speed = 115200 monitor_speed = 115200 board_build.f_cpu = 240000000 +board_build.flash_size = 80000000L lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 -build_flags = -DHELTEC_POWER_BUTTON +build_flags = -DLILYGO [env:vision-master-e290] platform = espressif32 diff --git a/src/main.cpp b/src/main.cpp index d6f50e8..349d856 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,12 +24,26 @@ // #define HELTEC_NO_DISPLAY #include + +// #define OSD_ENABLED true +// #define WIFI_SCANNING_ENABLED true +// #define BT_SCANNING_ENABLED true + +#ifndef LILYGO #include // This file contains a binary patch for the SX1262 #include "modules/SX126x/patches/SX126x_patch_scan.h" -// #define OSD_ENABLED true -// #define WIFI_SCANNING_ENABLED true -// #define BT_SCANNING_ENABLED true +#elif defined(LILYGO) +// LiLyGO device does not support the auto download mode, you need to get into the +// download mode manually. To do so, press and hold the BOOT button and then press the +// RESET button once. After that release the BOOT button. Or OFF->ON together with BOOT + +// Default LilyGO code +#include "utilities.h" +// Our Code +#include "LiLyGo.h" + +#endif // end LILYGO #define BT_SCAN_DELAY 60 * 1 * 1000 #define WF_SCAN_DELAY 60 * 2 * 1000 @@ -114,7 +128,7 @@ static constexpr uint16_t power_level[MAX_POWER_LEVELS + 1] = { #define OSD_X_START 1 #define OSD_Y_START 16 -// TODO: Calculate dinammicaly: +// TODO: Calculate dynamically: // osd_steps = osd_mhz_in_bin / (FM range / LORA radio x Steps) int osd_mhz_in_bin = 5; int osd_steps = 12; @@ -154,15 +168,19 @@ typedef enum } TSCAN_METOD_ENUM; #define SCAN_METHOD -#define METHOD_SPECTRAL -// #define METHOD_RSSI // Uncomment this and comment METHOD_SPECTRAL fot RSSI +// #define METHOD_SPECTRAL // Spectral scan method +#define METHOD_RSSI // Uncomment this and comment METHOD_SPECTRAL fot RSSI -// Feature to scan diapazones. Other frequency settings will be ignored. +// Output Pixel Formula +// 1 = rssi / 4, 2 = (rssi / 2) - 22 or 20 +constexpr int RSSI_OUTPUT_FORMULA = 2; + +// Feature to scan diapasones. Other frequency settings will be ignored. // int SCAN_RANGES[] = {850890, 920950}; int SCAN_RANGES[] = {}; // MHZ per page -// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 +// to put everything into one page set RANGE_PER_PAGE = FREQ_END - 800 uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // multiplies STEPS * N to increase scan resolution. @@ -189,7 +207,7 @@ bool ANIMATED_RELOAD = false; constexpr bool DRAW_DETECTION_TICKS = true; // Number of samples for each frequency scan. Fewer samples = better temporal resolution. -// if more than 100 it can freez +// if more than 100 it can freeze #define SAMPLES 35 //(scan time = 1294) // number of samples for RSSI method #define SAMPLES_RSSI 20 // 21 // @@ -263,69 +281,11 @@ uint8_t result_index = 0; uint8_t button_pressed_counter = 0; uint64_t loop_cnt = 0; -// Joystick integration -constexpr int JOY_X_PIN = 19; -int cursor_x_position = 0; -// Not integrated yet constexpr int JOY_Y_PIN = N/A; -constexpr int JOY_BTN_PIN = 46; -bool joy_btn_clicked = false; -#define JOYSTICK_ENABLED +#ifndef LILYGO +// #define JOYSTICK_ENABLED +#endif -bool joy_btn_click() -{ - joy_btn_clicked = true; - // is the output from the pushbutton inside the joystick. It’s normally open. If we - // use a pull-up resistor in this pin, the SW pin will be HIGH - // when it is not pressed, and LOW when Pressed. - return digitalRead(JOY_BTN_PIN) == HIGH ? false : true; -} - -int joyXMid = 0; -int cal_X = 0, cal_Y = 0; - -void calibrate_joy() -{ - for (int i = 0; i < 100; i++) - { - cal_X += analogRead(JOY_X_PIN); - } - // calibrate center - joyXMid = cal_X / 100; -} - -int MID = 100; // 10 mid point delta arduino, use 4 for attiny -int get_joy_x(bool logical = false) -{ - int joyX = analogRead(JOY_X_PIN); - - /* - Serial.print("Calibrated_X_Voltage = "); - Serial.print(joyXMid); - Serial.print("X_Voltage = "); - Serial.print(joyX); - Serial.print("\t"); - */ - - if (logical) - { - // 4095 - if (joyX < joyXMid - MID) - { - return -1; - } - // 0-5 - else if (joyX > joyXMid + MID) - { - return 1; - } - else - { - return 0; - } - } - - return joyX; -} +#include "joyStick.h" #ifdef WIFI_SCANNING_ENABLED // WiFi Scan @@ -539,7 +499,21 @@ void init_radio() { // initialize SX1262 FSK modem at the initial frequency both.println("Init radio"); - RADIOLIB_OR_HALT(radio.beginFSK(FREQ_BEGIN)); + state == radio.beginFSK(FREQ_BEGIN); + + if (state == RADIOLIB_ERR_NONE) + { + Serial.println(F("success!")); + } + else + { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) + { + delay(5); + } + } // upload a patch to the SX1262 to enable spectral scan // NOTE: this patch is uploaded into volatile memory, @@ -613,9 +587,10 @@ void setup(void) } init_radio(); - +#ifndef LILYGO vbat = heltec_vbat(); both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); +#endif // end not LILYGO #ifdef WIFI_SCANNING_ENABLED WiFi.mode(WIFI_STA); WiFi.disconnect(); @@ -642,7 +617,7 @@ void setup(void) { both.println("Single Page Screen MODE"); both.println("Multi Screen View Press P - button"); - both.println("Multi Screan Res: " + String(resolution) + "Mhz/tick"); + both.println("Multi Screen Res: " + String(resolution) + "Mhz/tick"); both.println( "Resolution: " + String((float)RANGE_PER_PAGE / (STEPS * SCAN_RBW_FACTOR)) + "MHz/tick"); @@ -693,6 +668,9 @@ void setup(void) if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Failed to start receive mode, error code: ")); + display.drawString(0, 64 - 10, "E:startReceive"); + display.display(); + delay(500); Serial.println(state); } #endif @@ -703,51 +681,83 @@ void setup(void) #endif } -// Formula to translate 33 bin to aproximate RSSI value +// Formula to translate 33 bin to approximate RSSI value int binToRSSI(int bin) { // the first the strongest RSSI in bin value is 0 return 11 + (bin * 4); } +void drone_sound_alarm(int drone_detection_level, int detection_count) +{ + // If level is set to sensitive, + // start beeping every 10th frequency and shorter + // it improves performance less short beep delays... + if (drone_detection_level <= 25) + { + if (detection_count == 1 && SOUND_ON) + { + tone(BUZZER_PIN, 205, + 10); // same action ??? but first time + } + if (detection_count % 5 == 0 && SOUND_ON) + { + tone(BUZZER_PIN, 205, + 10); // same action ??? but every 5th time + } + } + else + { + if (detection_count % 20 == 0 && SOUND_ON) + { + tone(BUZZER_PIN, 205, + 10); // same action ??? but every 20th detection + } + } +} + // MAX Frequency RSSI value of the samples int max_rssi_x = 999; + void loop(void) { - UI_displayDecorate(0, 0, false); // some default values - detection_count = 0; - drone_detected_frequency_start = 0; - ranges_count = 0; - // reset scan time - scan_time = 0; + { + UI_displayDecorate(0, 0, false); // some default values - // general purpose loop conter - loop_cnt++; + detection_count = 0; + drone_detected_frequency_start = 0; + ranges_count = 0; + + // reset scan time + scan_time = 0; + + // general purpose loop counter + loop_cnt++; #ifdef PRINT_PROFILE_TIME - loop_start = millis(); + loop_start = millis(); #endif - if (!ANIMATED_RELOAD || !single_page_scan) - { - // clear the scan plot rectangle - UI_clearPlotter(); - } + if (!ANIMATED_RELOAD || !single_page_scan) + { + // clear the scan plot rectangle + UI_clearPlotter(); + } - // do the scan - range = FREQ_END - FREQ_BEGIN; - if (RANGE_PER_PAGE > range) - { - RANGE_PER_PAGE = range; - } + // do the scan + range = FREQ_END - FREQ_BEGIN; + if (RANGE_PER_PAGE > range) + { + RANGE_PER_PAGE = range; + } - fr_begin = FREQ_BEGIN; - fr_end = fr_begin; + fr_begin = FREQ_BEGIN; + fr_end = fr_begin; - // 50 is a single-screen range - // TODO: Make 50 a variable with the option to show the full range - iterations = range / RANGE_PER_PAGE; + // 50 is a single-screen range + // TODO: Make 50 a variable with the option to show the full range + iterations = range / RANGE_PER_PAGE; #if 0 // disabled code if (range % RANGE_PER_PAGE != 0) @@ -757,529 +767,563 @@ void loop(void) } #endif - if (RANGE_PER_PAGE == range) - { - single_page_scan = true; - } - else - { - single_page_scan = false; - } - - for (int range : SCAN_RANGES) - { - ranges_count++; - } - - if (ranges_count > 0) - { - iterations = ranges_count; - single_page_scan = false; - } - - // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz - for (range_item = 0; range_item < iterations; range_item++) - { - range = RANGE_PER_PAGE; - if (ranges_count == 0) + if (RANGE_PER_PAGE == range) { - fr_begin = (range_item == 0) ? fr_begin : fr_begin += range; - fr_end = fr_begin + RANGE_PER_PAGE; + single_page_scan = true; } else { - fr_begin = SCAN_RANGES[range_item] / 1000; - fr_end = SCAN_RANGES[range_item] % 1000; - range = fr_end - fr_begin; + single_page_scan = false; } + for (int range : SCAN_RANGES) + { + ranges_count++; + } + + if (ranges_count > 0) + { + iterations = ranges_count; + single_page_scan = false; + } + + // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz + for (range_item = 0; range_item < iterations; range_item++) + { + range = RANGE_PER_PAGE; + if (ranges_count == 0) + { + fr_begin = (range_item == 0) ? fr_begin : fr_begin += range; + fr_end = fr_begin + RANGE_PER_PAGE; + } + else + { + fr_begin = SCAN_RANGES[range_item] / 1000; + fr_end = SCAN_RANGES[range_item] % 1000; + range = fr_end - fr_begin; + } + #ifdef DISABLED_CODE - if (!ANIMATED_RELOAD || !single_page_scan) - { - // clear the scan plot rectangle - UI_clearPlotter(); - } + if (!ANIMATED_RELOAD || !single_page_scan) + { + // clear the scan plot rectangle + UI_clearPlotter(); + } #endif - if (single_page_scan == false) - { - UI_displayDecorate(fr_begin, fr_end, true); - } - - drone_detected_frequency_start = 0; - display.setTextAlignment(TEXT_ALIGN_RIGHT); - - for (int i = 0; i < MAX_POWER_LEVELS; i++) - { - max_bins_array_value[i] = 0; - } - - // horizontal (x axis) Frequency loop - osd_x = 1, osd_y = 2, col = 0, max_bin = 0; - // x loop - for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) - { - - if (x % SCAN_RBW_FACTOR == 0) - new_pixel = true; - else - new_pixel = false; - if (ANIMATED_RELOAD && SCAN_RBW_FACTOR == 1) + if (single_page_scan == false) { - UI_drawCursor(x); + UI_displayDecorate(fr_begin, fr_end, true); } - if (new_pixel && ANIMATED_RELOAD && SCAN_RBW_FACTOR > 1) + + drone_detected_frequency_start = 0; + display.setTextAlignment(TEXT_ALIGN_RIGHT); + + for (int i = 0; i < MAX_POWER_LEVELS; i++) { - UI_drawCursor((int)(x / SCAN_RBW_FACTOR)); + max_bins_array_value[i] = 0; } + // horizontal (x axis) Frequency loop + osd_x = 1, osd_y = 2, col = 0, max_bin = 0; + // x loop + for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) + { + start: + + if (x % SCAN_RBW_FACTOR == 0) + new_pixel = true; + else + new_pixel = false; + if (ANIMATED_RELOAD && SCAN_RBW_FACTOR == 1) + { + UI_drawCursor(x); + } + if (new_pixel && ANIMATED_RELOAD && SCAN_RBW_FACTOR > 1) + { + UI_drawCursor((int)(x / SCAN_RBW_FACTOR)); + } + #ifdef PRINT_PROFILE_TIME - scan_start_time = millis(); + scan_start_time = millis(); #endif - // Real display pixel x - axis. - // Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore - // x > STEPS on SCAN_RBW_FACTOR - int display_x = x / SCAN_RBW_FACTOR; - waterfall[display_x] = false; - float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); + // Real display pixel x - axis. + // Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore + // x > STEPS on SCAN_RBW_FACTOR + int display_x = x / SCAN_RBW_FACTOR; + waterfall[display_x] = false; + float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); - freq = fr_begin + step; + freq = fr_begin + step; +#ifdef PRINT_DEBUG + Serial.println("setFrequency:" + String(freq)); +#endif - radio.setFrequency(freq, false); // false = no calibration need here +#ifdef LILYGO + state = + radio.setFrequency(freq, false); // false = no calibration need here +#else + state = + radio.setFrequency(freq, false); // false = no calibration need here +#endif + int radio_error_count = 0; + if (state != RADIOLIB_ERR_NONE) + { + display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); + // display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); + Serial.println("E:setFrequency:" + String(freq)); + display.display(); + delay(2); + radio_error_count++; + if (radio_error_count > 10) + continue; + } #ifdef PRINT_DEBUG - Serial.printf("Step:%d Freq: %f\n", x, freq); + Serial.printf("Step:%d Freq: %f\n", x, freq); #endif - // SpectralScan Method + // SpectralScan Method #ifdef METHOD_SPECTRAL - { - // start spectral scan third parameter is a sleep interval - radio.spectralScanStart(SAMPLES, 1); - // wait for spectral scan to finish - while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) { - Serial.print("radio.spectralScanGetStatus ERROR: "); - Serial.println(radio.spectralScanGetStatus()); - heltec_delay(ONE_MILLISEC * 10); + // start spectral scan third parameter is a sleep interval + radio.spectralScanStart(SAMPLES, 1); + // wait for spectral scan to finish + radio_error_count = 0; + while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) + { + Serial.println("radio.spectralScanGetStatus ERROR: "); + Serial.println(radio.spectralScanGetStatus()); + display.drawString(0, 64 - 20, + "E:specScSta:" + + String(radio.spectralScanGetStatus())); + display.display(); + heltec_delay(ONE_MILLISEC * 2); + radio_error_count++; + if (radio_error_count > 10) + continue; + } + + // read the results Array to which the results will be saved + state = radio.spectralScanGetResult(result); + display.drawString(0, 64 - 10, "scanGetResult:" + String(state)); } - // read the results Array to which the results will be saved - radio.spectralScanGetResult(result); - } + #endif #ifdef METHOD_RSSI - // Spectrum analyzer using getRSSI - { + // Spectrum analyzer using getRSSI + { #ifdef PRINT_DEBUG - Serial.println("METHOD RSSI"); + Serial.println("METHOD RSSI"); #endif - // memset - // memset(result, 0, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); - // Some issues with memset function - for (i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) - { - result[i] = 0; - } - result_index = 0; - // N of samples - for (int r = 0; r < SAMPLES_RSSI; r++) - { - rssi = radio.getRSSI(false); - // delay(ONE_MILLISEC); - // ToDO: check if 4 is correct value for 33 power bins - result_index = uint8_t(abs(rssi) / 4); /// still not clear formula + // memset + // memset(result, 0, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); + // Some issues with memset function + for (i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) + { + result[i] = 0; + } + result_index = 0; + // N of samples + for (int r = 0; r < SAMPLES_RSSI; r++) + { + rssi = radio.getRSSI(false); + // ToDO: check if 4 is correct value for 33 power bins + // Now we have more space because we are ignoring low dB values + // we can / 3 default 4 + if (RSSI_OUTPUT_FORMULA == 1) + { + result_index = + /// still not clear formula but it works + uint8_t(abs(rssi) / 4); + } + else if (RSSI_OUTPUT_FORMULA == 2) + { + // I like this formula better + result_index = uint8_t(abs(rssi) / 2) - 22; + } #ifdef PRINT_DEBUG - Serial.printf("RSSI: %d IDX: %d\n", rssi, result_index); + Serial.printf("RSSI: %d IDX: %d\n", rssi, result_index); #endif - // avoid buffer overflow - if (result_index < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) - { - // Saving max value only rss is negative so smaller is bigger - if (result[result_index] > rssi) + // avoid buffer overflow + if (result_index < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) { - result[result_index] = rssi; + // Saving max value only rss is negative so smaller is bigger + if (result[result_index] > rssi) + { + result[result_index] = rssi; + } } + else + { + Serial.print("Out-of-Range: result_index %d\n"); + } + } + } +#endif // SCAN_METHOD == METHOD_RSSI + + // if this code is not executed LORA radio doesn't work + // basically SX1262 requires delay + // osd.displayString(12, 1, String(FREQ_BEGIN)); + // osd.displayString(12, 30 - 8, String(FREQ_END)); + // delay(2); + +#ifdef OSD_ENABLED + osdProcess(); +#endif +#ifdef JOYSTICK_ENABLED + if (display_x == cursor_x_position) + { + display.setColor(BLACK); + display.fillRect(display_x - 20, 3, 36, 11); + display.setColor(WHITE); + } +#endif + detected = false; + detected_y[display_x] = false; + max_rssi_x = 999; + + for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { + +#ifdef PRINT_DEBUG + Serial.print(String(y) + ":"); + Serial.print(String(result[y]) + ","); +#endif +#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false + if (result[y] && result[y] != 0) + { + filtered_result[y] = 1; } else { - Serial.print("Out-of-Range: result_index %d\n"); + filtered_result[y] = 0; } - } - } -#endif // SCAN_METHOD == METHOD_RSSI - - // if this code is not executed LORA radio doesn't work - // basically SX1262 requires delay - // osd.displayString(12, 1, String(FREQ_BEGIN)); - // osd.displayString(12, 30 - 8, String(FREQ_END)); - // delay(2); - -#ifdef OSD_ENABLED - osdProcess(); -#endif -#ifdef JOYSTICK_ENABLED - if (display_x == cursor_x_position) - { - display.setColor(BLACK); - display.fillRect(display_x - 20, 3, 36, 11); - display.setColor(WHITE); - } -#endif - detected = false; - detected_y[display_x] = false; - max_rssi_x = 999; - for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) - { - -#ifdef PRINT_DEBUG - Serial.print(String(y) + ":"); - Serial.print(String(result[y]) + ","); -#endif - -#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false - if (result[y] && result[y] != 0) - { - filtered_result[y] = 1; - } - else - { - filtered_result[y] = 0; - } #endif // if samples low ~1 filter removes all values #if FILTER_SPECTRUM_RESULTS - filtered_result[y] = 0; - // Filter Elements without neighbors - // if RSSI method actual value is -xxx dB - if (result[y] > 0 && samples > 1) - { - // do not process 'first' and 'last' row to avoid out of index - // access. - if ((y > 0) && (y != (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 3))) + + filtered_result[y] = 0; + // Filter Elements without neighbors + // if RSSI method actual value is -xxx dB + if (result[y] > 0 && samples > 1) { - if (((result[y + 1] != 0) && (result[y + 2] != 0)) || - (result[y - 1] != 0)) - { - filtered_result[y] = 1; - } - else + // do not process 'first' and 'last' row to avoid out of index + // access. + if ((y > 0) && + (y != (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 3))) { + if (((result[y + 1] != 0) && (result[y + 2] != 0)) || + (result[y - 1] != 0)) + { + filtered_result[y] = 1; + } + else + { #ifdef PRINT_DEBUG - Serial.print("Filtered:" + String(x) + ":" + String(y) + ","); + Serial.print("Filtered:" + String(x) + ":" + String(y) + + ","); #endif + } } + } // not filtering if samples == 1 + else if (result[y] > 0 && samples == 1) + { + filtered_result[y] = 1; } - } // not filtering if samples == 1 - else if (result[y] > 0 && samples == 1) - { - filtered_result[y] = 1; - } -#endif - // check if we should alarm about a drone presence - if ((filtered_result[y] == 1) // we have some data and - && (y <= drone_detection_level) && - detected_y[display_x] == false) // detection threshold match - { - // Set LED to ON (filtered in UI component) - UI_setLedFlag(true); +#endif + // check if we should alarm about a drone presence + if ((filtered_result[y] == 1) // we have some data and + && (y <= drone_detection_level) && + detected_y[display_x] == false) // detection threshold match + { + // Set LED to ON (filtered in UI component) + UI_setLedFlag(true); #if (WATERFALL_ENABLED == true) - if (single_page_scan) - { - // Drone detection true for waterfall - if (!waterfall[display_x]) + if (single_page_scan) { - waterfall[display_x] = true; - display.setColor(WHITE); - display.setPixel(display_x, w); + // Drone detection true for waterfall + if (!waterfall[display_x]) + { + waterfall[display_x] = true; + display.setColor(WHITE); + display.setPixel(display_x, w); + } } - } #endif - if (drone_detected_frequency_start == 0) - { - // mark freq start - drone_detected_frequency_start = freq; - } + if (drone_detected_frequency_start == 0) + { + // mark freq start + drone_detected_frequency_start = freq; + } - // mark freq end ... will shift right to last detected range - drone_detected_frequency_end = freq; + // mark freq end ... will shift right to last detected range + drone_detected_frequency_end = freq; + if (SOUND_ON == true) + { + drone_sound_alarm(drone_detection_level, detection_count); + } - // If level is set to sensitive, - // start beeping every 10th frequency and shorter - // it improves performance less short beep delays... - if (drone_detection_level <= 25) - { - if (detection_count == 1 && SOUND_ON) + if (DRAW_DETECTION_TICKS == true) { - tone(BUZZER_PIN, 205, - 10); // same action ??? but first time - } - if (detection_count % 5 == 0 && SOUND_ON) - { - tone(BUZZER_PIN, 205, - 10); // same action ??? but everey 5th time + // draw vertical line on top of display for "drone detected" + // frequencies + if (!detected_y[display_x]) + { + display.drawLine(display_x, 1, display_x, 4); + detected_y[display_x] = true; + } } } - else - { - if (detection_count % 20 == 0 && SOUND_ON) - { - tone(BUZZER_PIN, 205, - 10); // same action ??? but everey 20th detection - } - } - - if (DRAW_DETECTION_TICKS == true) - { - // draw vertical line on top of display for "drone detected" - // frequencies - if (!detected_y[display_x]) - { - display.drawLine(display_x, 1, display_x, 4); - detected_y[display_x] = true; - } - } - } #if (WATERFALL_ENABLED == true) - if ((filtered_result[y] == 1) && (y <= drone_detection_level) && - (single_page_scan) && (waterfall[display_x] != true) && new_pixel) - { - // If drone not found set dark pixel on the waterfall - // TODO: make something like scrolling up if possible - waterfall[display_x] = false; - display.setColor(BLACK); - display.setPixel(display_x, w); - display.setColor(WHITE); - } + if ((filtered_result[y] == 1) && (y <= drone_detection_level) && + (single_page_scan) && (waterfall[display_x] != true) && new_pixel) + { + // If drone not found set dark pixel on the waterfall + // TODO: make something like scrolling up if possible + waterfall[display_x] = false; + display.setColor(BLACK); + display.setPixel(display_x, w); + display.setColor(WHITE); + } #endif - -#if 0 - -#endif // If 0 - - // next 2 If's ... adds !!!! 10ms of runtime ......tfk ??? - if (filtered_result[y] == 1) - { -#ifdef PRINT_DEBUG - Serial.print("Pixel:" + String(display_x) + "(" + String(x) + ")" + - ":" + String(y) + ","); -#endif - if (max_rssi_x > y) - { - max_rssi_x = y; - } - // Set signal level pixel - if (y < MAX_POWER_LEVELS - START_LOW) - { - display.setPixel(display_x, y + START_LOW); - } - if (!detected) - { - detected = true; - } - } - - // ------------------------------------------------------------- - // Draw "Detection Level line" every 2 pixel - // ------------------------------------------------------------- - if ((y == drone_detection_level) && (display_x % 2 == 0)) - { - display.setColor(WHITE); + // next 2 If's ... adds !!!! 10ms of runtime ......tfk ??? if (filtered_result[y] == 1) { - display.setColor(INVERSE); +#ifdef PRINT_DEBUG + Serial.print("Pixel:" + String(display_x) + "(" + String(x) + + ")" + ":" + String(y) + ","); +#endif + if (max_rssi_x > y) + { + max_rssi_x = y; + } + // Set signal level pixel + if (y < MAX_POWER_LEVELS - START_LOW) + { + display.setPixel(display_x, y + START_LOW); + } + if (!detected) + { + detected = true; + } } - display.setPixel(display_x, y + START_LOW); - // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide - display.setColor(WHITE); + // ------------------------------------------------------------- + // Draw "Detection Level line" every 2 pixel + // ------------------------------------------------------------- + if ((y == drone_detection_level) && (display_x % 2 == 0)) + { + display.setColor(WHITE); + if (filtered_result[y] == 1) + { + display.setColor(INVERSE); + } + display.setPixel(display_x, y + START_LOW); + // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide + + display.setColor(WHITE); + } } - } -#ifdef JOYSTICK_ENABLED - if (display_x == cursor_x_position) - { - display.drawString(display_x - 1, 0, String((int)freq)); - display.drawLine(display_x, 1, display_x, 12); - // if method scan RSSI we can get exact RSSI value - display.drawString(display_x + 17, 0, "-" + String((int)max_rssi_x * 4)); - } +#ifdef JOYSTICK_ENABLED + if (display_x == cursor_x_position) + { + + display.drawString(display_x - 1, 0, String((int)freq)); + display.drawLine(display_x, 1, display_x, 12); + // if method scan RSSI we can get exact RSSI value + display.drawString(display_x + 17, 0, + "-" + String((int)max_rssi_x * 4)); + } #endif #ifdef PRINT_PROFILE_TIME - scan_time += (millis() - scan_start_time); + scan_time += (millis() - scan_start_time); #endif - // count detected - if (detected) - { - detection_count++; - } + // count detected + if (detected) + { + detection_count++; + } #ifdef PRINT_DEBUG - Serial.println("....\n"); + Serial.println("....\n"); #endif - if (first_run || ANIMATED_RELOAD) - { - display.display(); - } + if (first_run || ANIMATED_RELOAD) + { + display.display(); + } - // Detection level button short press - if (button.pressedFor(100) +#ifndef LILYGO + // Detection level button short press + if (button.pressedFor(100) #ifdef JOYSTICK_ENABLED - || joy_btn_click() -#endif - ) - { - button.update(); - button_pressed_counter = 0; - // if long press stop - while (button.pressedNow() -#ifdef JOYSTICK_ENABLED - || joy_btn_click() + || joy_btn_click() #endif ) { - delay(10); - // Print Curent frequency - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(128 / 2, 0, String(freq)); - display.display(); - button_pressed_counter++; + button.update(); + button_pressed_counter = 0; + // if long press stop + while (button.pressedNow() +#ifdef JOYSTICK_ENABLED + || joy_btn_click() +#endif + ) + { + delay(10); + // Print Curent frequency + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.drawString(128 / 2, 0, String(freq)); + display.display(); + button_pressed_counter++; + if (button_pressed_counter > 150) + { + digitalWrite(LED, HIGH); + delay(150); + digitalWrite(LED, LOW); + } + } if (button_pressed_counter > 150) { - digitalWrite(LED, HIGH); - delay(150); - digitalWrite(LED, LOW); + // Remove Curent Frequency 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 > 150) - { - // Remove Curent Frequency Text - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setColor(BLACK); - display.drawString(128 / 2, 0, String(freq)); - display.setColor(WHITE); - display.display(); - break; - } - if (button_pressed_counter > 50 && button_pressed_counter < 150) - { - - if (!joy_btn_clicked) + if (button_pressed_counter > 50 && button_pressed_counter < 150) { - // Visually confirm it's off so user releases button - display.displayOff(); - // Deep sleep (has wait for release so we don't wake up - // immediately) - heltec_deep_sleep(); + if (!joy_btn_clicked) + { + // 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 drone detection level value + display.setColor(BLACK); + display.fillRect(128 - 13, 0, 13, 13); + display.setColor(WHITE); + drone_detection_level++; + // print new value + display.drawString(128, 0, String(drone_detection_level)); + tone(BUZZER_PIN, 104, 150); + if (drone_detection_level > 30) + { + drone_detection_level = 1; } - break; - } - button.update(); - display.setTextAlignment(TEXT_ALIGN_RIGHT); - // erase old drone detection level value - display.setColor(BLACK); - display.fillRect(128 - 13, 0, 13, 13); - display.setColor(WHITE); - drone_detection_level++; - // print new value - display.drawString(128, 0, String(drone_detection_level)); - tone(BUZZER_PIN, 104, 150); - if (drone_detection_level > 30) - { - drone_detection_level = 1; - } - } - // wait a little bit before the next scan, - // otherwise the SX1262 hangs - // Add more logic before insead of long delay... - int delay_cnt = 1; - while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) - { - if (delay_cnt == 1) - { - // trying to use display as delay.. - display.display(); - } - else - { - heltec_delay(ONE_MILLISEC * 2); } - Serial.println("spectralScanGetStatus ERROR(" + - String(radio.spectralScanGetStatus()) + - ") hard delay(2) - " + String(delay_cnt)); - // if error than speed is slow animating chart - ANIMATED_RELOAD = true; +#endif // END LILYGO - delay_cnt++; - } - // TODO: move osd logic here as a dalay ;) - // Loop is needed if heltec_delay(1) not used - heltec_loop(); + // wait a little bit before the next scan, + // otherwise the SX1262 hangs + // Add more logic before instead of long delay... + int delay_cnt = 1; +#ifdef METHOD_SPECTRAL + if (false && state != RADIOLIB_ERR_NONE) + { + if (delay_cnt == 1) + { + Serial.println("E:getResult"); + display.drawString(0, 64 - 10, "E:getResult"); + // trying to use display as delay.. + display.display(); + } + else + { + heltec_delay(ONE_MILLISEC * 2); + Serial.println("E:getStatus"); + display.drawString(0, 64 - 10, "E:getResult"); + // trying to use display as delay.. + display.display(); + } + + Serial.println("spectralScanGetStatus ERROR(" + + String(radio.spectralScanGetStatus()) + + ") hard delay(2) - " + String(delay_cnt)); + // if error than speed is slow animating chart + ANIMATED_RELOAD = true; + delay(50); + delay_cnt++; + } +#endif + // TODO: move osd logic here as a daley ;) + // Loop is needed if heltec_delay(1) not used + heltec_loop(); // Move joystick #ifdef JOYSTICK_ENABLED - int joy_x_pressed = get_joy_x(true); - if (joy_x_pressed > 0) - { - cursor_x_position--; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } - else if (joy_x_pressed < 0) - { - cursor_x_position++; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } - if (cursor_x_position > DISPLAY_WIDTH || cursor_x_position < 0) - { - cursor_x_position = 0; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } + int joy_x_pressed = get_joy_x(true); + if (joy_x_pressed > 0) + { + cursor_x_position--; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } + else if (joy_x_pressed < 0) + { + cursor_x_position++; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } + if (cursor_x_position > DISPLAY_WIDTH || cursor_x_position < 0) + { + cursor_x_position = 0; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } #endif - } - w++; - if (w > ROW_STATUS_TEXT + 1) - { - w = WATERFALL_START; - } + } + w++; + if (w > ROW_STATUS_TEXT + 1) + { + w = WATERFALL_START; + } #if (WATERFALL_ENABLED == true) - // Draw waterfall position cursor - if (single_page_scan) - { - display.setColor(BLACK); - display.drawHorizontalLine(0, w, STEPS); - display.setColor(WHITE); - } + // Draw waterfall position cursor + if (single_page_scan) + { + display.setColor(BLACK); + display.drawHorizontalLine(0, w, STEPS); + display.setColor(WHITE); + } #endif - // Render display data here - display.display(); + // Render display data here + display.display(); #ifdef OSD_ENABLED - // Sometimes OSD prints entire screan with the digits. - // We need clean the screan to fix it. - // We can do it every time but to optimise doing every N times - if (global_counter != 0 && global_counter % 10 == 0) - { + // Sometimes OSD prints entire screen with the digits. + // We need clean the screen to fix it. + // We can do it every time but to optimise doing every N times + if (global_counter != 0 && global_counter % 10 == 0) + { #if !defined(BT_SCANNING_ENABLED) && !defined(WIFI_SCANNING_ENABLED) - osd.clear(); - osd.displayChar(14, 1, 0x10f); - global_counter = 0; + osd.clear(); + osd.displayChar(14, 1, 0x10f); + global_counter = 0; +#endif + } + ANIMATED_RELOAD = false; + global_counter++; #endif } - ANIMATED_RELOAD = false; - global_counter++; -#endif } - #ifdef PRINT_DEBUG // Serial.println("----"); #endif From f8650ab5c8efd9a7f5f3e5c12821918e665f74ab Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sun, 8 Sep 2024 01:42:05 -0700 Subject: [PATCH 14/17] Add Vision Master T190 Color display --- include/BT_WIFI_scan.h | 60 ++- platformio.ini | 62 ++- src/main.cpp | 1125 +++++++++++++++++++--------------------- tft_src/images.h | 109 ++++ tft_src/main.cpp | 572 ++++++++++++++++++++ 5 files changed, 1311 insertions(+), 617 deletions(-) create mode 100644 tft_src/images.h create mode 100644 tft_src/main.cpp diff --git a/include/BT_WIFI_scan.h b/include/BT_WIFI_scan.h index 8313111..d0b2be5 100644 --- a/include/BT_WIFI_scan.h +++ b/include/BT_WIFI_scan.h @@ -14,7 +14,7 @@ void setOSD() {} // TODO: Make Async Scan // https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/scan-examples.html#async-scan -void scanWiFi(void) +void scanWiFi(DFRobot_OSD osd) { osd.clear(); osd.displayString(14, 2, "Scanning WiFi.."); @@ -50,3 +50,61 @@ void scanWiFi(void) } osd.displayChar(14, 1, 0x10f); } + +//********************** +// BLE devices scan. +//*********************** +// TODO: Make Async Scan +// https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/SampleAsyncScan.cpp +void scanBT(DFRobot_OSD osd) +{ + osd.clear(); + osd.displayString(14, 2, "Scanning BT..."); + cycleCnt++; + + BLEDevice::init(""); + BLEScan *pBLEScan = BLEDevice::getScan(); + // active scan uses more power, but get results faster + pBLEScan->setActiveScan(true); + // TODO: adjust interval and window + pBLEScan->setInterval(0x50); + pBLEScan->setWindow(0x30); + +#ifdef SERIAL_PRINT + Serial.printf("Start BLE scan for %d seconds...\n", BT_SCAN_TIME); +#endif + + BLEScanResults foundDevices = pBLEScan->start(BT_SCAN_TIME); + int count = foundDevices.getCount(); +#ifdef PRINT_DEBUG + Serial.printf("Found devices: %d \n", count); +#endif + present = false; + for (int i = 0; i < count; i++) + { + BLEAdvertisedDevice device = foundDevices.getDevice(i); + String currDevAddr = device.getAddress().toString().c_str(); + String deviceName; + if (device.haveName()) + { + deviceName = device.getName().c_str(); + } + else + { + deviceName = currDevAddr; + } + +#ifdef PRINT_DEBUG + Serial.printf("Found device #%s/%s with RSSI: %d \n", currDevAddr, deviceName, + device.getRSSI()); +#endif + osd.displayString(i + 1, 1, + "BT:" + deviceName + ":" + String(device.getRSSI()) + " \n"); + } +#ifdef PRINT_DEBUG + Serial.println("Scan done!"); + Serial.printf("Cycle counter: %d, Free heap: %d \n", cycleCnt, ESP.getFreeHeap()); +#endif + osd.displayChar(14, 1, 0x10f); + scanFinished = true; +} diff --git a/platformio.ini b/platformio.ini index e89e8e3..51f29ca 100644 --- a/platformio.ini +++ b/platformio.ini @@ -9,10 +9,12 @@ ; https://docs.platformio.org/page/projectconf.html [platformio] -;; for env:vision-master-e290 -;;src_dir = eink_src -;; for env:heltec_wifi_lora_32_V3 -;;src_dir = src ;;Default +; for env:vision-master-e190 +src_dir = tft_src +; for env:vision-master-e290 +; src_dir = eink_src +; for env:heltec_wifi_lora_32_V3 +; src_dir = src ;;Default [env:heltec_wifi_lora_32_V3] platform = espressif32 @@ -23,11 +25,12 @@ monitor_speed = 115200 board_build.f_cpu = 240000000 lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 + adafruit/Adafruit ST7735 and ST7789 Library@^1.10.4 build_flags = -DHELTEC_POWER_BUTTON [env:lilygo-T3S3-v1-2] platform = espressif32 -board = t3_s3_v1_x ;platformio doesn't have right boatd check local boards bolder +board = t3_s3_v1_x framework = arduino upload_speed = 921600 monitor_speed = 115200 @@ -35,8 +38,9 @@ board_build.f_cpu = 240000000 lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 RadioLib + adafruit/Adafruit ST7735 and ST7789 Library@^1.10.4 build_flags = - -DLILYGO ; flag for our code + -DLILYGO -DT3_S3_V1_2_SX1262 -DT3_V1_3_SX1262 -DARDUINO_LILYGO_T3S3_SX1262 @@ -45,8 +49,7 @@ build_flags = -DARDUINO_ARCH_ESP32 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_LILYGO_T3_S3_V1_X - -DARDUINO_USB_MODE=1 - ;-UARDUINO_USB_CDC_ON_BOOT + -DARDUINO_USB_MODE=1 [env:heltec_wifi_lora_32_V3-test-signal-generator] platform = espressif32 @@ -58,6 +61,7 @@ board_build.f_cpu = 240000000 board_build.flash_size = 80000000L lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 + adafruit/Adafruit ST7735 and ST7789 Library@^1.10.4 build_flags = -DLILYGO [env:vision-master-e290] @@ -68,10 +72,10 @@ monitor_speed = 115200 monitor_filters = esp32_exception_decoder board_upload.use_1200bps_touch = true build_flags = - -DHELTEC_BOARD=37 - -DSLOW_CLK_TPYE=1 + -DHELTEC_BOARD=37 + -DSLOW_CLK_TPYE=1 -DARDUINO_USB_CDC_ON_BOOT=1 - -DLoRaWAN_DEBUG_LEVEL=0 + -DLoRaWAN_DEBUG_LEVEL=0 -DE290 -DESP32 -DVision_Master_E290 @@ -88,6 +92,40 @@ lib_deps = SPI Wire adafruit/Adafruit BusIO @ 1.9.6 - https://github.com/HelTecAutomation/Heltec_ESP32/ + https://github.com/HelTecAutomation/Heltec_ESP32/ adafruit/Adafruit GFX Library@^1.11.10 ropg/Heltec_ESP32_LoRa_v3@^0.9.1 + adafruit/Adafruit ST7735 and ST7789 Library@^1.10.4 + +[env:vision-master-t190] +platform = espressif32 +board = heltec_wifi_lora_32_V3 +framework = arduino +monitor_speed = 115200 +monitor_filters = esp32_exception_decoder +board_upload.use_1200bps_touch = true +build_flags = + -DHELTEC_BOARD=38 + -DSLOW_CLK_TPYE=1 + -DARDUINO_USB_CDC_ON_BOOT=1 + -DLoRaWAN_DEBUG_LEVEL=0 + -DT190 + -DESP32 + -DVision_Master_T190 + -DRADIOLIB_EXCLUDE_CC1101=true + -DRADIOLIB_EXCLUDE_LR11x0=true + -DRADIOLIB_EXCLUDE_NRF24=true + -DRADIOLIB_EXCLUDE_RF69=true + -DRADIOLIB_EXCLUDE_RFM2X=true + -DRADIOLIB_EXCLUDE_SI443X=true + -DRADIOLIB_EXCLUDE_SX1231=true + -DRADIOLIB_EXCLUDE_SX127X=true + -DRADIOLIB_EXCLUDE_SX128X=true +lib_deps = + SPI + Wire + adafruit/Adafruit BusIO @ 1.9.6 + https://github.com/HelTecAutomation/Heltec_ESP32/ + adafruit/Adafruit GFX Library@^1.11.10 + ropg/Heltec_ESP32_LoRa_v3@^0.9.1 + adafruit/Adafruit ST7735 and ST7789 Library@^1.10.4 diff --git a/src/main.cpp b/src/main.cpp index 349d856..ccc69f1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -143,17 +143,6 @@ static const int buf0[36] = {0x02, 0x80, 0x02, 0x40, 0x7F, 0xE0, 0x42, 0x00, 0x42, 0x00, 0x7A, 0x40, 0x4A, 0x40, 0x4A, 0x80, 0x49, 0x20, 0x5A, 0xA0, 0x44, 0x60, 0x88, 0x20}; -// project components -#ifdef WIFI_SCANNING_ENABLED -#include "WiFi.h" -#endif -#ifdef BT_SCANNING_ENABLED -#include -#include -#include -#include -#endif - #include "global_config.h" #include "ui.h" @@ -287,110 +276,22 @@ uint64_t loop_cnt = 0; #include "joyStick.h" -#ifdef WIFI_SCANNING_ENABLED -// WiFi Scan -// TODO: Make Async Scan -// https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/scan-examples.html#async-scan -void scanWiFi() -{ - osd.clear(); - osd.displayString(14, 2, "Scanning WiFi.."); - int n = WiFi.scanNetworks(); -#ifdef PRINT_DEBUG - Serial.println("scan done"); - if (n == 0) - { - Serial.println("no networks found"); - } -#endif - if (n > 0) - { -#ifdef PRINT_DEBUG - Serial.print(n); - Serial.println(" networks found"); -#endif - for (int i = 0; i < n; ++i) - { -// Print SSID and RSSI for each network found -#ifdef PRINT_DEBUG - Serial.print(i + 1); - Serial.print(": "); - Serial.print(WiFi.SSID(i)); - Serial.print(" ("); - Serial.print(WiFi.RSSI(i)); - Serial.print(")"); - Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*"); -#endif - osd.displayString(i + 1, 1, - "WF:" + String((WiFi.SSID(i) + ":" + WiFi.RSSI(i)))); - } - } - osd.displayChar(14, 1, 0x10f); -} +// project components +#if (defined(WIFI_SCANNING_ENABLED) || defined(BT_SCANNING_ENABLED)) && \ + defined(OSD_ENABLED) +#include "BT_WIFI_scan.h" #endif -#ifdef BT_SCANNING_ENABLED -//********************** -// BLE devices scan. -//*********************** -// TODO: Make Async Scan -// https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLETests/SampleAsyncScan.cpp -void scanBT() -{ - osd.clear(); - osd.displayString(14, 2, "Scanning BT..."); - cycleCnt++; - - BLEDevice::init(""); - BLEScan *pBLEScan = BLEDevice::getScan(); - // active scan uses more power, but get results faster - pBLEScan->setActiveScan(true); - // TODO: adjust interval and window - pBLEScan->setInterval(0x50); - pBLEScan->setWindow(0x30); - -#ifdef SERIAL_PRINT - Serial.printf("Start BLE scan for %d seconds...\n", BT_SCAN_TIME); +#if defined(WIFI_SCANNING_ENABLED) && defined(OSD_ENABLED) +scanWiFi(osd) #endif - BLEScanResults foundDevices = pBLEScan->start(BT_SCAN_TIME); - int count = foundDevices.getCount(); -#ifdef PRINT_DEBUG - Serial.printf("Found devices: %d \n", count); -#endif - present = false; - for (int i = 0; i < count; i++) - { - BLEAdvertisedDevice device = foundDevices.getDevice(i); - String currDevAddr = device.getAddress().toString().c_str(); - String deviceName; - if (device.haveName()) - { - deviceName = device.getName().c_str(); - } - else - { - deviceName = currDevAddr; - } - -#ifdef PRINT_DEBUG - Serial.printf("Found device #%s/%s with RSSI: %d \n", currDevAddr, deviceName, - device.getRSSI()); -#endif - osd.displayString(i + 1, 1, - "BT:" + deviceName + ":" + String(device.getRSSI()) + " \n"); - } -#ifdef PRINT_DEBUG - Serial.println("Scan done!"); - Serial.printf("Cycle counter: %d, Free heap: %d \n", cycleCnt, ESP.getFreeHeap()); -#endif - osd.displayChar(14, 1, 0x10f); - scanFinished = true; -} +#if defined(BT_SCANNING_ENABLED) && defined(OSD_ENABLED) + scanBT(osd) #endif #ifdef OSD_ENABLED -unsigned short selectFreqChar(int bin, int start_level = 0) + unsigned short selectFreqChar(int bin, int start_level = 0) { if (bin >= start_level) { @@ -515,6 +416,7 @@ void init_radio() } } +#ifdef METHOD_SPECTRAL // 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 @@ -524,6 +426,7 @@ void init_radio() // enable spectral scan and must be uploaded again on every power cycle. RADIOLIB_OR_HALT(radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan))); // configure scan bandwidth and disable the data shaping +#endif both.println("Setting up radio"); RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); @@ -688,6 +591,78 @@ int binToRSSI(int bin) return 11 + (bin * 4); } +// returns tru if continue the code is false breake the loop +bool buttonPressHandler(float freq) +{ + // Detection level button short press + if (button.pressedFor(100) +#ifdef JOYSTICK_ENABLED + || joy_btn_click() +#endif + ) + { + button.update(); + button_pressed_counter = 0; + // if long press stop + while (button.pressedNow() +#ifdef JOYSTICK_ENABLED + || joy_btn_click() +#endif + ) + { + delay(10); + // Print Curent frequency + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.drawString(128 / 2, 0, String(freq)); + display.display(); + button_pressed_counter++; + if (button_pressed_counter > 150) + { + digitalWrite(LED, HIGH); + delay(150); + digitalWrite(LED, LOW); + } + } + if (button_pressed_counter > 150) + { + // Remove Curent Frequency Text + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setColor(BLACK); + display.drawString(128 / 2, 0, String(freq)); + display.setColor(WHITE); + display.display(); + return false; + } + if (button_pressed_counter > 50 && button_pressed_counter < 150) + { + if (!joy_btn_clicked) + { + // 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(); + } + return false; + } + button.update(); + display.setTextAlignment(TEXT_ALIGN_RIGHT); + // erase old drone detection level value + display.setColor(BLACK); + display.fillRect(128 - 13, 0, 13, 13); + display.setColor(WHITE); + drone_detection_level++; + // print new value + display.drawString(128, 0, String(drone_detection_level)); + tone(BUZZER_PIN, 104, 150); + if (drone_detection_level > 30) + { + drone_detection_level = 1; + } + } + return true; +} + void drone_sound_alarm(int drone_detection_level, int detection_count) { // If level is set to sensitive, @@ -716,48 +691,105 @@ void drone_sound_alarm(int drone_detection_level, int detection_count) } } +void joystickMoveCursor(int joy_x_pressed) +{ + + if (joy_x_pressed > 0) + { + cursor_x_position--; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } + else if (joy_x_pressed < 0) + { + cursor_x_position++; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } + if (cursor_x_position > DISPLAY_WIDTH || cursor_x_position < 0) + { + cursor_x_position = 0; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } +} + +bool is_new_x_pixel(int x) +{ + if (x % SCAN_RBW_FACTOR == 0) + return true; + else + return false; +} + +void check_ranges() +{ + if (RANGE_PER_PAGE == range) + { + single_page_scan = true; + } + else + { + single_page_scan = false; + } + + for (int range : SCAN_RANGES) + { + ranges_count++; + } + + if (ranges_count > 0) + { + iterations = ranges_count; + single_page_scan = false; + } +} // MAX Frequency RSSI value of the samples int max_rssi_x = 999; void loop(void) { + UI_displayDecorate(0, 0, false); // some default values - { - UI_displayDecorate(0, 0, false); // some default values + detection_count = 0; + drone_detected_frequency_start = 0; + ranges_count = 0; - detection_count = 0; - drone_detected_frequency_start = 0; - ranges_count = 0; + // reset scan time + scan_time = 0; - // reset scan time - scan_time = 0; - - // general purpose loop counter - loop_cnt++; + // general purpose loop counter + loop_cnt++; #ifdef PRINT_PROFILE_TIME - loop_start = millis(); + loop_start = millis(); #endif - if (!ANIMATED_RELOAD || !single_page_scan) - { - // clear the scan plot rectangle - UI_clearPlotter(); - } + if (!ANIMATED_RELOAD || !single_page_scan) + { + // clear the scan plot rectangle + UI_clearPlotter(); + } - // do the scan - range = FREQ_END - FREQ_BEGIN; - if (RANGE_PER_PAGE > range) - { - RANGE_PER_PAGE = range; - } + // do the scan + range = FREQ_END - FREQ_BEGIN; + if (RANGE_PER_PAGE > range) + { + RANGE_PER_PAGE = range; + } - fr_begin = FREQ_BEGIN; - fr_end = fr_begin; + fr_begin = FREQ_BEGIN; + fr_end = fr_begin; - // 50 is a single-screen range - // TODO: Make 50 a variable with the option to show the full range - iterations = range / RANGE_PER_PAGE; + // 50 is a single-screen range + // TODO: Make 50 a variable with the option to show the full range + iterations = range / RANGE_PER_PAGE; #if 0 // disabled code if (range % RANGE_PER_PAGE != 0) @@ -767,562 +799,447 @@ void loop(void) } #endif - if (RANGE_PER_PAGE == range) + check_ranges(); + + // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz + for (range_item = 0; range_item < iterations; range_item++) + { + range = RANGE_PER_PAGE; + if (ranges_count == 0) { - single_page_scan = true; + fr_begin = (range_item == 0) ? fr_begin : fr_begin += range; + fr_end = fr_begin + RANGE_PER_PAGE; } else { - single_page_scan = false; + fr_begin = SCAN_RANGES[range_item] / 1000; + fr_end = SCAN_RANGES[range_item] % 1000; + range = fr_end - fr_begin; } - for (int range : SCAN_RANGES) - { - ranges_count++; - } - - if (ranges_count > 0) - { - iterations = ranges_count; - single_page_scan = false; - } - - // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz - for (range_item = 0; range_item < iterations; range_item++) - { - range = RANGE_PER_PAGE; - if (ranges_count == 0) - { - fr_begin = (range_item == 0) ? fr_begin : fr_begin += range; - fr_end = fr_begin + RANGE_PER_PAGE; - } - else - { - fr_begin = SCAN_RANGES[range_item] / 1000; - fr_end = SCAN_RANGES[range_item] % 1000; - range = fr_end - fr_begin; - } - #ifdef DISABLED_CODE - if (!ANIMATED_RELOAD || !single_page_scan) - { - // clear the scan plot rectangle - UI_clearPlotter(); - } + if (!ANIMATED_RELOAD || !single_page_scan) + { + // clear the scan plot rectangle + UI_clearPlotter(); + } #endif - if (single_page_scan == false) + if (single_page_scan == false) + { + UI_displayDecorate(fr_begin, fr_end, true); + } + + drone_detected_frequency_start = 0; + display.setTextAlignment(TEXT_ALIGN_RIGHT); + + for (int i = 0; i < MAX_POWER_LEVELS; i++) + { + max_bins_array_value[i] = 0; + } + + // horizontal (x axis) Frequency loop + osd_x = 1, osd_y = 2, col = 0, max_bin = 0; + // x loop + for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) + { + new_pixel = is_new_x_pixel(x); + if (ANIMATED_RELOAD && SCAN_RBW_FACTOR == 1) { - UI_displayDecorate(fr_begin, fr_end, true); + UI_drawCursor(x); } - - drone_detected_frequency_start = 0; - display.setTextAlignment(TEXT_ALIGN_RIGHT); - - for (int i = 0; i < MAX_POWER_LEVELS; i++) + if (new_pixel && ANIMATED_RELOAD && SCAN_RBW_FACTOR > 1) { - max_bins_array_value[i] = 0; + UI_drawCursor((int)(x / SCAN_RBW_FACTOR)); } - // horizontal (x axis) Frequency loop - osd_x = 1, osd_y = 2, col = 0, max_bin = 0; - // x loop - for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) - { - start: - - if (x % SCAN_RBW_FACTOR == 0) - new_pixel = true; - else - new_pixel = false; - if (ANIMATED_RELOAD && SCAN_RBW_FACTOR == 1) - { - UI_drawCursor(x); - } - if (new_pixel && ANIMATED_RELOAD && SCAN_RBW_FACTOR > 1) - { - UI_drawCursor((int)(x / SCAN_RBW_FACTOR)); - } - #ifdef PRINT_PROFILE_TIME - scan_start_time = millis(); + scan_start_time = millis(); #endif - // Real display pixel x - axis. - // Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore - // x > STEPS on SCAN_RBW_FACTOR - int display_x = x / SCAN_RBW_FACTOR; - waterfall[display_x] = false; - float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); + // Real display pixel x - axis. + // Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore + // x > STEPS on SCAN_RBW_FACTOR + int display_x = x / SCAN_RBW_FACTOR; + waterfall[display_x] = false; + float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); - freq = fr_begin + step; + freq = fr_begin + step; #ifdef PRINT_DEBUG - Serial.println("setFrequency:" + String(freq)); + Serial.println("setFrequency:" + String(freq)); #endif #ifdef LILYGO - state = - radio.setFrequency(freq, false); // false = no calibration need here + state = radio.setFrequency(freq, false); // false = no calibration need here #else - state = - radio.setFrequency(freq, false); // false = no calibration need here + state = radio.setFrequency(freq, false); // false = no calibration need here #endif - int radio_error_count = 0; - if (state != RADIOLIB_ERR_NONE) + int radio_error_count = 0; + if (state != RADIOLIB_ERR_NONE) + { + display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); + // display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); + Serial.println("E:setFrequency:" + String(freq)); + display.display(); + delay(2); + radio_error_count++; + if (radio_error_count > 10) + continue; + } + +#ifdef PRINT_DEBUG + Serial.printf("Step:%d Freq: %f\n", x, freq); +#endif + // SpectralScan Method +#ifdef METHOD_SPECTRAL + { + // start spectral scan third parameter is a sleep interval + radio.spectralScanStart(SAMPLES, 1); + // wait for spectral scan to finish + radio_error_count = 0; + while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) { - display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); - // display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); - Serial.println("E:setFrequency:" + String(freq)); + Serial.println("radio.spectralScanGetStatus ERROR: "); + Serial.println(radio.spectralScanGetStatus()); + display.drawString(0, 64 - 20, + "E:specScSta:" + + String(radio.spectralScanGetStatus())); display.display(); - delay(2); + heltec_delay(ONE_MILLISEC * 2); radio_error_count++; if (radio_error_count > 10) continue; } -#ifdef PRINT_DEBUG - Serial.printf("Step:%d Freq: %f\n", x, freq); -#endif - // SpectralScan Method -#ifdef METHOD_SPECTRAL - { - // start spectral scan third parameter is a sleep interval - radio.spectralScanStart(SAMPLES, 1); - // wait for spectral scan to finish - radio_error_count = 0; - while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) - { - Serial.println("radio.spectralScanGetStatus ERROR: "); - Serial.println(radio.spectralScanGetStatus()); - display.drawString(0, 64 - 20, - "E:specScSta:" + - String(radio.spectralScanGetStatus())); - display.display(); - heltec_delay(ONE_MILLISEC * 2); - radio_error_count++; - if (radio_error_count > 10) - continue; - } - - // read the results Array to which the results will be saved - state = radio.spectralScanGetResult(result); - display.drawString(0, 64 - 10, "scanGetResult:" + String(state)); - } + // read the results Array to which the results will be saved + state = radio.spectralScanGetResult(result); + display.drawString(0, 64 - 10, "scanGetResult:" + String(state)); + } #endif #ifdef METHOD_RSSI - // Spectrum analyzer using getRSSI + // Spectrum analyzer using getRSSI + { +#ifdef PRINT_DEBUG + Serial.println("METHOD RSSI"); +#endif + // memset + // memset(result, 0, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); + // Some issues with memset function + for (i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) { -#ifdef PRINT_DEBUG - Serial.println("METHOD RSSI"); -#endif - // memset - // memset(result, 0, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); - // Some issues with memset function - for (i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) - { - result[i] = 0; - } - result_index = 0; - // N of samples - for (int r = 0; r < SAMPLES_RSSI; r++) - { - rssi = radio.getRSSI(false); - // ToDO: check if 4 is correct value for 33 power bins - // Now we have more space because we are ignoring low dB values - // we can / 3 default 4 - if (RSSI_OUTPUT_FORMULA == 1) - { - result_index = - /// still not clear formula but it works - uint8_t(abs(rssi) / 4); - } - else if (RSSI_OUTPUT_FORMULA == 2) - { - // I like this formula better - result_index = uint8_t(abs(rssi) / 2) - 22; - } - -#ifdef PRINT_DEBUG - Serial.printf("RSSI: %d IDX: %d\n", rssi, result_index); -#endif - // avoid buffer overflow - if (result_index < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) - { - // Saving max value only rss is negative so smaller is bigger - if (result[result_index] > rssi) - { - result[result_index] = rssi; - } - } - else - { - Serial.print("Out-of-Range: result_index %d\n"); - } - } + result[i] = 0; } -#endif // SCAN_METHOD == METHOD_RSSI - - // if this code is not executed LORA radio doesn't work - // basically SX1262 requires delay - // osd.displayString(12, 1, String(FREQ_BEGIN)); - // osd.displayString(12, 30 - 8, String(FREQ_END)); - // delay(2); - -#ifdef OSD_ENABLED - osdProcess(); -#endif -#ifdef JOYSTICK_ENABLED - if (display_x == cursor_x_position) - { - display.setColor(BLACK); - display.fillRect(display_x - 20, 3, 36, 11); - display.setColor(WHITE); - } -#endif - detected = false; - detected_y[display_x] = false; - max_rssi_x = 999; - - for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + result_index = 0; + // N of samples + for (int r = 0; r < SAMPLES_RSSI; r++) { + rssi = radio.getRSSI(false); + // ToDO: check if 4 is correct value for 33 power bins + // Now we have more space because we are ignoring low dB values + // we can / 3 default 4 + if (RSSI_OUTPUT_FORMULA == 1) + { + result_index = + /// still not clear formula but it works + uint8_t(abs(rssi) / 4); + } + else if (RSSI_OUTPUT_FORMULA == 2) + { + // I like this formula better + result_index = uint8_t(abs(rssi) / 2) - 22; + } #ifdef PRINT_DEBUG - Serial.print(String(y) + ":"); - Serial.print(String(result[y]) + ","); + Serial.printf("RSSI: %d IDX: %d\n", rssi, result_index); #endif -#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false - if (result[y] && result[y] != 0) + // avoid buffer overflow + if (result_index < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) { - filtered_result[y] = 1; + // Saving max value only rss is negative so smaller is bigger + if (result[result_index] > rssi) + { + result[result_index] = rssi; + } } else { - filtered_result[y] = 0; + Serial.print("Out-of-Range: result_index %d\n"); } + } + } +#endif // SCAN_METHOD == METHOD_RSSI + + // if this code is not executed LORA radio doesn't work + // basically SX1262 requires delay + // osd.displayString(12, 1, String(FREQ_BEGIN)); + // osd.displayString(12, 30 - 8, String(FREQ_END)); + // delay(2); + +#ifdef OSD_ENABLED + osdProcess(); +#endif +#ifdef JOYSTICK_ENABLED + if (display_x == cursor_x_position) + { + display.setColor(BLACK); + display.fillRect(display_x - 20, 3, 36, 11); + display.setColor(WHITE); + } +#endif + detected = false; + detected_y[display_x] = false; + max_rssi_x = 999; + + for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { + +#ifdef PRINT_DEBUG + Serial.print(String(y) + ":"); + Serial.print(String(result[y]) + ","); +#endif +#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false + if (result[y] && result[y] != 0) + { + filtered_result[y] = 1; + } + else + { + filtered_result[y] = 0; + } #endif // if samples low ~1 filter removes all values #if FILTER_SPECTRUM_RESULTS - filtered_result[y] = 0; - // Filter Elements without neighbors - // if RSSI method actual value is -xxx dB - if (result[y] > 0 && samples > 1) + filtered_result[y] = 0; + // Filter Elements without neighbors + // if RSSI method actual value is -xxx dB + if (result[y] > 0 && samples > 1) + { + // do not process 'first' and 'last' row to avoid out of index + // access. + if ((y > 0) && (y != (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 3))) { - // do not process 'first' and 'last' row to avoid out of index - // access. - if ((y > 0) && - (y != (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 3))) + if (((result[y + 1] != 0) && (result[y + 2] != 0)) || + (result[y - 1] != 0)) + { + filtered_result[y] = 1; + } + else { - if (((result[y + 1] != 0) && (result[y + 2] != 0)) || - (result[y - 1] != 0)) - { - filtered_result[y] = 1; - } - else - { #ifdef PRINT_DEBUG - Serial.print("Filtered:" + String(x) + ":" + String(y) + - ","); + Serial.print("Filtered:" + String(x) + ":" + String(y) + ","); #endif - } } - } // not filtering if samples == 1 - else if (result[y] > 0 && samples == 1) - { - filtered_result[y] = 1; } + } // not filtering if samples == 1 + else if (result[y] > 0 && samples == 1) + { + filtered_result[y] = 1; + } #endif - // check if we should alarm about a drone presence - if ((filtered_result[y] == 1) // we have some data and - && (y <= drone_detection_level) && - detected_y[display_x] == false) // detection threshold match - { - // Set LED to ON (filtered in UI component) - UI_setLedFlag(true); + // check if we should alarm about a drone presence + if ((filtered_result[y] == 1) // we have some data and + && (y <= drone_detection_level) && + detected_y[display_x] == false) // detection threshold match + { + // Set LED to ON (filtered in UI component) + UI_setLedFlag(true); #if (WATERFALL_ENABLED == true) - if (single_page_scan) - { - // Drone detection true for waterfall - if (!waterfall[display_x]) - { - waterfall[display_x] = true; - display.setColor(WHITE); - display.setPixel(display_x, w); - } - } -#endif - if (drone_detected_frequency_start == 0) - { - // mark freq start - drone_detected_frequency_start = freq; - } - - // mark freq end ... will shift right to last detected range - drone_detected_frequency_end = freq; - if (SOUND_ON == true) - { - drone_sound_alarm(drone_detection_level, detection_count); - } - - if (DRAW_DETECTION_TICKS == true) - { - // draw vertical line on top of display for "drone detected" - // frequencies - if (!detected_y[display_x]) - { - display.drawLine(display_x, 1, display_x, 4); - detected_y[display_x] = true; - } - } - } -#if (WATERFALL_ENABLED == true) - if ((filtered_result[y] == 1) && (y <= drone_detection_level) && - (single_page_scan) && (waterfall[display_x] != true) && new_pixel) + if (single_page_scan) { - // If drone not found set dark pixel on the waterfall - // TODO: make something like scrolling up if possible - waterfall[display_x] = false; - display.setColor(BLACK); - display.setPixel(display_x, w); - display.setColor(WHITE); + // Drone detection true for waterfall + if (!waterfall[display_x]) + { + waterfall[display_x] = true; + display.setColor(WHITE); + display.setPixel(display_x, w); + } } #endif - // next 2 If's ... adds !!!! 10ms of runtime ......tfk ??? + if (drone_detected_frequency_start == 0) + { + // mark freq start + drone_detected_frequency_start = freq; + } + + // mark freq end ... will shift right to last detected range + drone_detected_frequency_end = freq; + if (SOUND_ON == true) + { + drone_sound_alarm(drone_detection_level, detection_count); + } + + if (DRAW_DETECTION_TICKS == true) + { + // draw vertical line on top of display for "drone detected" + // frequencies + if (!detected_y[display_x]) + { + display.drawLine(display_x, 1, display_x, 4); + detected_y[display_x] = true; + } + } + } +#if (WATERFALL_ENABLED == true) + if ((filtered_result[y] == 1) && (y <= drone_detection_level) && + (single_page_scan) && (waterfall[display_x] != true) && new_pixel) + { + // If drone not found set dark pixel on the waterfall + // TODO: make something like scrolling up if possible + waterfall[display_x] = false; + display.setColor(BLACK); + display.setPixel(display_x, w); + display.setColor(WHITE); + } +#endif + // next 2 If's ... adds !!!! 10ms of runtime ......tfk ??? + if (filtered_result[y] == 1) + { +#ifdef PRINT_DEBUG + Serial.print("Pixel:" + String(display_x) + "(" + String(x) + ")" + + ":" + String(y) + ","); +#endif + if (max_rssi_x > y) + { + max_rssi_x = y; + } + // Set signal level pixel + if (y < MAX_POWER_LEVELS - START_LOW) + { + display.setPixel(display_x, y + START_LOW); + } + if (!detected) + { + detected = true; + } + } + + // ------------------------------------------------------------- + // Draw "Detection Level line" every 2 pixel + // ------------------------------------------------------------- + if ((y == drone_detection_level) && (display_x % 2 == 0)) + { + display.setColor(WHITE); if (filtered_result[y] == 1) { -#ifdef PRINT_DEBUG - Serial.print("Pixel:" + String(display_x) + "(" + String(x) + - ")" + ":" + String(y) + ","); -#endif - if (max_rssi_x > y) - { - max_rssi_x = y; - } - // Set signal level pixel - if (y < MAX_POWER_LEVELS - START_LOW) - { - display.setPixel(display_x, y + START_LOW); - } - if (!detected) - { - detected = true; - } + display.setColor(INVERSE); } + display.setPixel(display_x, y + START_LOW); + // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide - // ------------------------------------------------------------- - // Draw "Detection Level line" every 2 pixel - // ------------------------------------------------------------- - if ((y == drone_detection_level) && (display_x % 2 == 0)) - { - display.setColor(WHITE); - if (filtered_result[y] == 1) - { - display.setColor(INVERSE); - } - display.setPixel(display_x, y + START_LOW); - // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide - - display.setColor(WHITE); - } + display.setColor(WHITE); } + } #ifdef JOYSTICK_ENABLED - if (display_x == cursor_x_position) - { - - display.drawString(display_x - 1, 0, String((int)freq)); - display.drawLine(display_x, 1, display_x, 12); - // if method scan RSSI we can get exact RSSI value - display.drawString(display_x + 17, 0, - "-" + String((int)max_rssi_x * 4)); - } + // Draw joystick cursor and Frequency RSSI value + if (display_x == cursor_x_position) + { + display.drawString(display_x - 1, 0, String((int)freq)); + display.drawLine(display_x, 1, display_x, 12); + // if method scan RSSI we can get exact RSSI value + display.drawString(display_x + 17, 0, "-" + String((int)max_rssi_x * 4)); + } #endif #ifdef PRINT_PROFILE_TIME - scan_time += (millis() - scan_start_time); + scan_time += (millis() - scan_start_time); #endif - // count detected - if (detected) - { - detection_count++; - } + // count detected + if (detected) + { + detection_count++; + } #ifdef PRINT_DEBUG - Serial.println("....\n"); + Serial.println("....\n"); #endif - if (first_run || ANIMATED_RELOAD) - { - display.display(); - } + if (first_run || ANIMATED_RELOAD) + { + display.display(); + } +// LiLyGo doesn't have button ;( +// ToDO: Check if we use BOOT button #ifndef LILYGO - // Detection level button short press - if (button.pressedFor(100) -#ifdef JOYSTICK_ENABLED - || joy_btn_click() -#endif - ) - { - button.update(); - button_pressed_counter = 0; - // if long press stop - while (button.pressedNow() -#ifdef JOYSTICK_ENABLED - || joy_btn_click() -#endif - ) - { - delay(10); - // Print Curent frequency - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(128 / 2, 0, String(freq)); - display.display(); - button_pressed_counter++; - if (button_pressed_counter > 150) - { - digitalWrite(LED, HIGH); - delay(150); - digitalWrite(LED, LOW); - } - } - if (button_pressed_counter > 150) - { - // Remove Curent Frequency Text - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setColor(BLACK); - display.drawString(128 / 2, 0, String(freq)); - display.setColor(WHITE); - display.display(); - break; - } - if (button_pressed_counter > 50 && button_pressed_counter < 150) - { - if (!joy_btn_clicked) - { - // 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 drone detection level value - display.setColor(BLACK); - display.fillRect(128 - 13, 0, 13, 13); - display.setColor(WHITE); - drone_detection_level++; - // print new value - display.drawString(128, 0, String(drone_detection_level)); - tone(BUZZER_PIN, 104, 150); - if (drone_detection_level > 30) - { - drone_detection_level = 1; - } - } - + if (buttonPressHandler() == false) + break; #endif // END LILYGO - // wait a little bit before the next scan, - // otherwise the SX1262 hangs - // Add more logic before instead of long delay... - int delay_cnt = 1; + // wait a little bit before the next scan, + // otherwise the SX1262 hangs + // Add more logic before instead of long delay... + int delay_cnt = 1; #ifdef METHOD_SPECTRAL - if (false && state != RADIOLIB_ERR_NONE) + if (false && state != RADIOLIB_ERR_NONE) + { + if (delay_cnt == 1) { - if (delay_cnt == 1) - { - Serial.println("E:getResult"); - display.drawString(0, 64 - 10, "E:getResult"); - // trying to use display as delay.. - display.display(); - } - else - { - heltec_delay(ONE_MILLISEC * 2); - Serial.println("E:getStatus"); - display.drawString(0, 64 - 10, "E:getResult"); - // trying to use display as delay.. - display.display(); - } - - Serial.println("spectralScanGetStatus ERROR(" + - String(radio.spectralScanGetStatus()) + - ") hard delay(2) - " + String(delay_cnt)); - // if error than speed is slow animating chart - ANIMATED_RELOAD = true; - delay(50); - delay_cnt++; + Serial.println("E:getResult"); + display.drawString(0, 64 - 10, "E:getResult"); + // trying to use display as delay.. + display.display(); } + else + { + heltec_delay(ONE_MILLISEC * 2); + Serial.println("E:getStatus"); + display.drawString(0, 64 - 10, "E:getResult"); + // trying to use display as delay.. + display.display(); + } + + Serial.println("spectralScanGetStatus ERROR(" + + String(radio.spectralScanGetStatus()) + + ") hard delay(2) - " + String(delay_cnt)); + // if error than speed is slow animating chart + ANIMATED_RELOAD = true; + delay(50); + delay_cnt++; + } #endif - // TODO: move osd logic here as a daley ;) - // Loop is needed if heltec_delay(1) not used - heltec_loop(); + // TODO: move osd logic here as a daley ;) + // Loop is needed if heltec_delay(1) not used + heltec_loop(); // Move joystick #ifdef JOYSTICK_ENABLED - int joy_x_pressed = get_joy_x(true); - if (joy_x_pressed > 0) - { - cursor_x_position--; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } - else if (joy_x_pressed < 0) - { - cursor_x_position++; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } - if (cursor_x_position > DISPLAY_WIDTH || cursor_x_position < 0) - { - cursor_x_position = 0; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } -#endif - } - w++; - if (w > ROW_STATUS_TEXT + 1) - { - w = WATERFALL_START; - } -#if (WATERFALL_ENABLED == true) - // Draw waterfall position cursor - if (single_page_scan) - { - display.setColor(BLACK); - display.drawHorizontalLine(0, w, STEPS); - display.setColor(WHITE); - } -#endif - // Render display data here - display.display(); -#ifdef OSD_ENABLED - // Sometimes OSD prints entire screen with the digits. - // We need clean the screen to fix it. - // We can do it every time but to optimise doing every N times - if (global_counter != 0 && global_counter % 10 == 0) - { -#if !defined(BT_SCANNING_ENABLED) && !defined(WIFI_SCANNING_ENABLED) - osd.clear(); - osd.displayChar(14, 1, 0x10f); - global_counter = 0; -#endif - } - ANIMATED_RELOAD = false; - global_counter++; + int joy_x_pressed = get_joy_x(true); + joystickMoveCursor(joy_x_pressed); #endif } + w++; + if (w > ROW_STATUS_TEXT + 1) + { + w = WATERFALL_START; + } +#if (WATERFALL_ENABLED == true) + // Draw waterfall position cursor + if (single_page_scan) + { + display.setColor(BLACK); + display.drawHorizontalLine(0, w, STEPS); + display.setColor(WHITE); + } +#endif + // Render display data here + display.display(); +#ifdef OSD_ENABLED + // Sometimes OSD prints entire screen with the digits. + // We need clean the screen to fix it. + // We can do it every time but to optimise doing every N times + if (global_counter != 0 && global_counter % 10 == 0) + { +#if !defined(BT_SCANNING_ENABLED) && !defined(WIFI_SCANNING_ENABLED) + osd.clear(); + osd.displayChar(14, 1, 0x10f); + global_counter = 0; +#endif + } + ANIMATED_RELOAD = false; + global_counter++; +#endif } #ifdef PRINT_DEBUG // Serial.println("----"); diff --git a/tft_src/images.h b/tft_src/images.h new file mode 100644 index 0000000..5021a8f --- /dev/null +++ b/tft_src/images.h @@ -0,0 +1,109 @@ +constexpr unsigned char epd_bitmap_ucog[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x10, 0x84, 0xC3, 0x81, 0x03, 0x00, 0x60, 0x00, 0xCC, 0x07, 0x00, 0x00, 0x00, 0x70, + 0x00, 0x00, 0x30, 0xE6, 0xF3, 0xE3, 0x07, 0x00, 0x60, 0x00, 0x0C, 0x3E, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x30, 0x66, 0x10, 0x36, 0x00, 0x00, 0x60, 0x00, 0x06, 0xF8, + 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x30, 0x26, 0x18, 0x36, 0x00, 0x00, 0x60, 0x00, + 0x07, 0xE0, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x30, 0x26, 0x18, 0x36, 0x07, 0x00, + 0x60, 0x00, 0x03, 0x00, 0x1F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x30, 0x26, 0x18, 0x36, + 0x06, 0x00, 0x60, 0x80, 0x01, 0x00, 0x7C, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x30, 0x66, + 0x38, 0x76, 0x06, 0x0C, 0x60, 0xC0, 0x01, 0x00, 0xF0, 0x01, 0x78, 0x00, 0x00, 0x00, + 0xE0, 0xE3, 0xF3, 0xE3, 0x07, 0x0E, 0x60, 0xC0, 0x03, 0x00, 0x80, 0x0F, 0x1C, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x07, 0x60, 0xE0, 0x07, 0x00, 0x00, 0x3E, + 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x60, 0x60, 0x0E, 0x00, + 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x01, 0x60, 0x70, + 0x1C, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, + 0x60, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x70, 0x00, 0x60, 0x18, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x38, 0x00, 0xF0, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xFC, 0x0D, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0xFE, 0x0F, 0xC0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x67, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x61, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, + 0x60, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x60, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x7E, 0xE0, 0xE0, 0x01, 0x00, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x67, 0xE0, 0x83, 0x03, 0x00, 0x00, 0xE0, 0xFF, 0xE1, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x02, 0xD0, 0x63, 0x60, 0x07, 0x07, 0x00, 0xC0, 0xFF, + 0x03, 0x80, 0x03, 0x00, 0x00, 0x08, 0x00, 0x02, 0xF0, 0x61, 0x60, 0x1C, 0x1F, 0x80, + 0xFF, 0x07, 0x00, 0x00, 0x0E, 0x00, 0x00, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xF8, + 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x18, 0x00, 0x02, 0xF0, 0x7F, + 0x60, 0xDC, 0x1F, 0x80, 0xFF, 0x07, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, 0x02, + 0xD0, 0x61, 0x60, 0x07, 0x0F, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x90, 0x67, 0xE0, 0x83, 0x03, 0x00, 0x00, 0xF0, 0xFF, 0xC1, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0xE0, 0xC1, 0x01, 0x00, 0x00, 0x00, 0xF8, 0x7F, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x60, 0xF0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x60, 0x38, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x61, 0x1C, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x67, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xEE, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x1C, 0x00, 0xFC, 0x0D, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0xF0, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x60, 0x18, 0x70, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x60, 0x30, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x60, 0x70, + 0x3C, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, + 0x60, 0x60, 0x1E, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x07, 0x60, 0xE0, 0x0F, 0x00, 0x00, 0x3E, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x07, 0x03, 0x00, 0x0F, 0x60, 0xC0, 0x03, 0x00, 0x80, 0x0F, 0x1C, 0x00, 0x00, 0x00, + 0x00, 0x80, 0x01, 0x07, 0x00, 0x0C, 0x60, 0xC0, 0x01, 0x00, 0xF0, 0x01, 0x38, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x81, 0x05, 0x00, 0x08, 0x60, 0xC0, 0x01, 0x00, 0x7C, 0x00, + 0xE0, 0x00, 0x00, 0x00, 0x00, 0x80, 0x83, 0x0C, 0x00, 0x00, 0x60, 0x00, 0x03, 0x00, + 0x1F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x8E, 0x0C, 0x00, 0x00, 0x60, 0x00, + 0x07, 0xE0, 0x03, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x0F, 0x00, 0x00, + 0x60, 0x00, 0x06, 0xF8, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x1F, + 0x00, 0x00, 0x60, 0x00, 0x0E, 0x3E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x80, + 0x67, 0x18, 0x00, 0x00, 0x60, 0x00, 0xCC, 0x07, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xF8, 0x01, 0x00, 0x00, 0x00, 0xE0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0xFC, 0x01, 0x00, 0x00, + 0x00, 0xE0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, +}; + +const uint8_t batteryfull[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery6[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery5[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0xF8, 0x03, 0xF8, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery4[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0xF8, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery3[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, + 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery2[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, + 0x03, 0x18, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery1[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, + 0x03, 0x18, 0x03, 0x18, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; +const uint8_t battery0[] = { + 0x00, 0x00, 0xE0, 0x00, 0xF8, 0x03, 0xF8, 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, + 0x03, 0x18, 0x03, 0x18, 0x03, 0x18, 0x03, 0xF8, 0x03, 0xF8, 0x03, 0x00, 0x00, +}; diff --git a/tft_src/main.cpp b/tft_src/main.cpp new file mode 100644 index 0000000..4411a0e --- /dev/null +++ b/tft_src/main.cpp @@ -0,0 +1,572 @@ +/* Heltec Automation Ink screen example + * NOTE!!!: to upload we new code you need to press button BOOT and RESET or you will + * have serial error. After upload you need reset device... + * + * Description: + * 1.Inherited from ssd1306 for drawing points, lines, and functions + * + * All code e link examples you cand find here: + * */ +// Variables required to boot Heltec E290 defined at platformio.ini +// #define HELTEC_BOARD 37 +// #define SLOW_CLK_TPYE 1 +// #define ARDUINO_USB_CDC_ON_BOOT 1 +// #define LoRaWAN_DEBUG_LEVEL 0 +#include "HT_ST7789spi.h" +#include "global_config.h" +#include "images.h" +#include "ui.h" +#include +#include + +#define st7789_CS_Pin 39 +#define st7789_REST_Pin 40 +#define st7789_DC_Pin 47 +#define st7789_SCLK_Pin 38 +#define st7789_MOSI_Pin 48 +#define st7789_LED_K_Pin 17 +#define st7789_VTFT_CTRL_Pin 7 + +// lcd object pointer, it's a 240x135 lcd display, Adafruit dependcy +static HT_ST7789 *st7789 = NULL; +static SPIClass *gspi_lcd = NULL; + +char buffer[256]; + +// Disabling default Heltec lib OLED display +#define HELTEC_NO_DISPLAY +#define DISPLAY_WIDTH 320 +#define DISPLAY_HEIGHT 170 +// Without this line Lora Radio doesn't work with heltec lib +#define ARDUINO_heltec_wifi_32_lora_V3 +#include "heltec_unofficial.h" + +// We are not using spectral scan here only RSSI method +// #include "modules/SX126x/patches/SX126x_patch_scan.h" +// #define PRINT_DEBUG + +// TODO: move variables to common file +// <--- Spectrum display Variables START +#define SCAN_METHOD +#define METHOD_SPECTRAL +// numbers of the spectrum screen lines = width of screen +#define STEPS DISPLAY_WIDTH // 128 +// Number of samples for each scan. Fewer samples = better temporal resolution. +#define MAX_POWER_LEVELS 33 +// multiplies STEPS * N to increase scan resolution. +#define SCAN_RBW_FACTOR 1 // 2 +// Print spectrum values pixels at once or by line +bool ANIMATED_RELOAD = false; +// Remove reading without neighbors +#define FILTER_SPECTRUM_RESULTS true +#define FILTER_SAMPLES_MIN +constexpr bool DRAW_DETECTION_TICKS = true; +// Number of samples for each frequency scan. Fewer samples = better temporal resolution. +// if more than 100 it can freez +#define SAMPLES 35 //(scan time = 1294) +// number of samples for RSSI method +#define SAMPLES_RSSI 5 // 21 // + +#define FREQ_BEGIN 650 + +#define RANGE (int)(FREQ_END - FREQ_BEGIN) + +#define SINGLE_STEP (float)(RANGE / (STEPS * SCAN_RBW_FACTOR)) + +uint64_t range = (int)(FREQ_END - FREQ_BEGIN); +uint64_t fr_begin = FREQ_BEGIN; +uint64_t fr_end = FREQ_BEGIN; + +// Feature to scan diapasones. Other frequency settings will be ignored. +// int SCAN_RANGES[] = {850890, 920950}; +int SCAN_RANGES[] = {}; + +// MHZ per page +// to put everything into one page set RANGE_PER_PAGE = FREQ_END - 800 +// uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN + +// Override or e-ink +uint64_t RANGE_PER_PAGE = FREQ_BEGIN + DISPLAY_WIDTH; + +uint64_t iterations = RANGE / RANGE_PER_PAGE; + +// uint64_t range_frequency = FREQ_END - FREQ_BEGIN; +uint64_t median_frequency = FREQ_BEGIN + FREQ_END - FREQ_BEGIN / 2; + +// #define DISABLE_PLOT_CHART false // unused + +// Array to store the scan results +uint16_t result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t result_display_set[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t result_detections[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; +uint16_t filtered_result[RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE]; + +// Waterfall array +bool waterfall[STEPS], detected_y[STEPS]; // 20 - ??? steps of the waterfall + +// global variable + +// Used as a Led Light and Buzzer/count trigger +bool first_run, new_pixel, detected_x = false; +// drone detection flag +bool detected = false; +uint64_t drone_detection_level = 90; +uint64_t drone_detected_frequency_start = 0; +uint64_t drone_detected_frequency_end = 0; +uint64_t detection_count = 0; +bool single_page_scan = false; +bool SOUND_ON = false; + +// #define PRINT_DEBUG +#define PRINT_PROFILE_TIME + +#ifdef PRINT_PROFILE_TIME +uint64_t loop_start = 0; +uint64_t loop_time = 0; +uint64_t scan_time = 0; +uint64_t scan_start_time = 0; +#endif + +#define WATERFALL_START 115 +#define WATERFALL_END DISPLAY_HEIGHT - 10 - 2 + +uint64_t x, y, range_item, w = WATERFALL_START, i = 0; +int osd_x = 1, osd_y = 2, col = 0, max_bin = 32; +uint64_t ranges_count = 0; + +float freq = 0; +int rssi = 0; +int state = 0; + +#ifdef METHOD_SPECTRAL +constexpr int samples = SAMPLES; +#endif +#ifdef METHOD_RSSI +constexpr int samples = SAMPLES_RSSI; +#endif + +uint8_t result_index = 0; +uint8_t button_pressed_counter = 0; +uint64_t loop_cnt = 0; +// <--- Spectrum display Variables END + +#define DIRECTION ANGLE_0_DEGREE + +// TODO: move to common file +void init_radio() +{ + // initialize SX1262 FSK modem at the initial frequency + Serial.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 + Serial.println("Upload SX1262 patch"); + + // Upload binary patch into the SX126x device RAM. Patch is needed to e.g., + // enable spectral scan and must be uploaded again on every power cycle. + // RADIOLIB_OR_HALT(radio.uploadPatch(sx126x_patch_scan, sizeof(sx126x_patch_scan))); + // configure scan bandwidth and disable the data shaping + + Serial.println("Setting up radio"); + RADIOLIB_OR_HALT(radio.setRxBandwidth(BANDWIDTH)); + + // and disable the data shaping + RADIOLIB_OR_HALT(radio.setDataShaping(RADIOLIB_SHAPING_NONE)); + Serial.println("Starting scanning..."); + + // calibrate only once ,,, at startup + // TODO: check documentation (9.2.1) if we must calibrate in certain ranges + radio.setFrequency(FREQ_BEGIN, true); + delay(50); +} + +#define HEIGHT 4 + +void drawText(uint16_t x, uint16_t y, String text, uint16_t color = ST7789_WHITE) +{ + st7789->setCursor(x, y); + st7789->setTextColor(color); + st7789->setTextWrap(true); + st7789->print(text.c_str()); +} + +void drawSetupText() +{ + // create more fonts at http://oleddisplay.squix.ch/ + /** *display.setTextAlignment(TEXT_ALIGN_LEFT); + display.setFont(ArialMT_Plain_10); + display.drawString(0, 0, "Spectrum Analyzer Lora SA"); + display.setFont(ArialMT_Plain_16); + display.drawString(0, 10, "SX 1262"); + display.setFont(ArialMT_Plain_24); + display.drawString(0, 26, "TFT display"); + display.drawString(0, 56, "RF Spectrum TFT-ray"); + display.setFont(ArialMT_Plain_24); + **/ +} + +#define battery_w 13 +#define battery_h 13 +#define BATTERY_PIN 7 + +void battery() +{ + analogReadResolution(12); + int battery_levl = analogRead(BATTERY_PIN) / 238.7; // battary/4096*3.3* coefficient + float battery_one = 0.4125; +#ifdef PRINT_DEBUG + Serial.printf("ADC analog value = %.2f\n", battery_levl); +#endif + // display.drawString(257, 0, String(heltec_battery_percent(battery_levl)) + "%"); + // TODO: battery voltage doesn't work + if (battery_levl < battery_one) + { + // display.drawXbm(275, 0, battery_w, battery_h, battery0); + } + else if (battery_levl < 2 * battery_one && battery_levl > battery_one) + { + // display.drawXbm(285, 0, battery_w, battery_h, battery1); + } + else if (battery_levl < 3 * battery_one && battery_levl > 2 * battery_one) + { + // display.drawXbm(285, 0, battery_w, battery_h, battery2); + } + else if (battery_levl < 4 * battery_one && battery_levl > 3 * battery_one) + { + // display.drawXbm(285, 0, battery_w, battery_h, battery3); + } + else if (battery_levl < 5 * battery_one && battery_levl > 4 * battery_one) + { + // display.drawXbm(285, 0, battery_w, battery_h, battery4); + } + else if (battery_levl < 6 * battery_one && battery_levl > 5 * battery_one) + { + // display.drawXbm(285, 0, battery_w, battery_h, battery5); + } + else if (battery_levl < 7 * battery_one && battery_levl > 6 * battery_one) + { + // display.drawXbm(285, 0, battery_w, battery_h, battery6); + } + else if (battery_levl < 7 * battery_one && battery_levl > 6 * battery_one) + { + // display.drawXbm(285, 0, battery_w, battery_h, batteryfull); + } +} + +void VextON(void) +{ + pinMode(18, OUTPUT); + digitalWrite(18, HIGH); +} +void VextOFF(void) // Vext default OFF +{ + pinMode(18, OUTPUT); + digitalWrite(18, LOW); +} + +constexpr int lower_level = 108; +constexpr int up_level = 40; +int rssiToPix(int rssi) +{ + // Bigger is lower signal + if (abs(rssi) >= lower_level) + { + return lower_level - 1; + } + if (abs(rssi) <= up_level) + { + return up_level; + } + return abs(rssi); +} + +// +int rssiToColor(int rssi, bool waterfall = false) +{ + if (rssi < 80) + return 63488; + if (rssi < 85) + return 0xfa08; + if (rssi < 90) + return 0xcfe0; + if (rssi < 95) + return 0x01ff; + if (rssi < 100) + return 0x8d5f; + if (waterfall) + return ST7789_BLACK; + return ST7789_WHITE; +} + +long timeSinceLastModeSwitch = 0; + +float fr = FREQ_BEGIN, fr_x[STEPS + 5], vbat = 0; +// MHz in one screen pix step +// END will be Begin + 289 * mhz_step +constexpr int mhz_step = 1; +// TODO: make end_freq +// Measure RSS every step +constexpr float rssi_mhz_step = 0.33; +int rssi2 = 0; +int x1 = 0, y2 = 0; +unsigned int screen_update_loop_counter = 0; +unsigned int x_screen_update = 0; +int rssi_printed = 0; +constexpr int rssi_window_size = 30; +int max_i_rssi = -999; +int window_max_rssi = -999; +int window_max_fr = -999; +int max_scan_rssi[STEPS + 2]; +int max_history_rssi[STEPS + 2]; +long display_scan_start = 0; +long display_scan_end = 0; +long display_scan_i_end = 0; +int scan_iterations = 0; +// will be changed to false after first run +bool clear_rssi_history = true; + +constexpr unsigned int SCANS_PER_DISPLAY = 1; +constexpr unsigned int STATUS_BAR_HEIGHT = 5; + +void loop() +{ + if (screen_update_loop_counter == 0) + { + // Zero arrays + for (int i = 0; i < STEPS; i++) + { + fr_x[x1] = 0; + max_scan_rssi[i] = -999; + if (clear_rssi_history == true) + max_history_rssi[i] = -999; + } + clear_rssi_history = false; + display_scan_start = millis(); + } + fr_x[x1] = fr; + // Draw max history line + st7789->drawLine(x1, rssiToPix(max_history_rssi[x1]), x1, lower_level, + 12710 /*gray*/); + int u = 0; + // Fetch samples + for (int i = 0; i < SAMPLES_RSSI; i++) + { + + radio.setFrequency((float)fr + (float)(rssi_mhz_step * u), + false); // false = no calibration need here + u++; + if (rssi_mhz_step * u >= mhz_step) + { + u = 0; + } + + rssi2 = radio.getRSSI(false); + scan_iterations++; + if (rssi2 > lower_level) + continue; +#ifdef PRINT_DEBUG + Serial.println(String(fr) + ":" + String(rssi2)); +#endif + // display.drawString(x1, (int)y2, String(fr) + ":" + String(rssi2)); + // display.setPixel(x1, rssiToPix(rssi2)); + st7789->drawPixel(x1, rssiToPix(rssi2), rssiToColor(abs(rssi2))); + st7789->drawPixel(x1, rssiToPix(rssi2) - 1, rssiToColor(abs(rssi2))); + st7789->drawPixel(x1, rssiToPix(rssi2) - 2, rssiToColor(abs(rssi2))); + // Draw Update Cursor + st7789->drawFastVLine(x1 + 1, lower_level, -lower_level + 25, ST7789_BLACK); + st7789->drawFastVLine(x1 + 2, lower_level, -lower_level + 25, ST7789_BLACK); + st7789->drawFastVLine(x1 + 3, lower_level, -lower_level + 25, ST7789_BLACK); + + if (max_scan_rssi[x1] < rssi2) + { + max_scan_rssi[x1] = rssi2; + if (max_history_rssi[x1] < max_scan_rssi[x1]) + { + max_history_rssi[x1] = rssi2; + } + } + } + // Waterfall Pixel + st7789->drawPixel(x1, w, rssiToColor(abs(max_scan_rssi[x1]), true)); + + // Waterfall cursor + st7789->drawFastHLine(0, w + 1, DISPLAY_WIDTH, ST7789_BLACK); + st7789->drawFastHLine(0, w + 2, DISPLAY_WIDTH, ST7789_BLACK); + + // drone detection level line + if (x1 % 2 == 0) + { + // display.setPixel(x1, rssiToPix(drone_detection_level)); + st7789->drawPixel(x1, rssiToPix(drone_detection_level) + 3, ST7789_GREEN); + } + fr += mhz_step; + x1++; + if (display_scan_i_end == 0) + { + display_scan_i_end = millis(); + } + // Main N x-axis full loop end logic + if (x1 >= STEPS) + { + w++; + if (w > WATERFALL_END) + w = WATERFALL_START; + if (screen_update_loop_counter + 1 == SCANS_PER_DISPLAY) + { + // max Mhz and dB in window + for (int i = 0; i < STEPS; i++) + { + // Max dB in window + if (window_max_rssi < max_scan_rssi[i]) + { + // Max Mhz in window + window_max_fr = fr_x[i]; + window_max_rssi = max_scan_rssi[i]; + } + if (i % rssi_window_size == 0 || (i % (DISPLAY_WIDTH - 1)) == 0) + { + + if (abs(window_max_rssi) < drone_detection_level) + { + y2 = 10; + + /** display.setFont(ArialMT_Plain_10); + display.drawStringMaxWidth(i - rssi_window_size, y2, + rssi_window_size, + String(window_max_rssi) + "dB"); + display.drawString(i - rssi_window_size + 5, y2 + 10, + String(window_max_fr)); + */ + drawText(i - rssi_window_size, y2, String(window_max_rssi) + "dB", + rssiToColor(window_max_rssi)); + drawText(i - rssi_window_size + 5, y2, + String(String(window_max_fr)) + "dB", + rssiToColor(window_max_rssi)); + // Vertical lines between windows + for (int l = y2; l < 100; l += 4) + { + st7789->drawPixel(i, l, ST7789_YELLOW); + // display.setPixel(i, l); + } + } + window_max_rssi = -999; + } + } + + display_scan_end = millis(); + + // display.setFont(ArialMT_Plain_10); + drawText(0, 0, + "T:" + String(display_scan_end - display_scan_start) + "/" + + String(display_scan_i_end - display_scan_start) + " L:-" + + String(drone_detection_level) + "dB", + ST7789_BLUE); + + /// battery(); + // iteration full scan / samples pixel step / numbers of scan per display + drawText(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2) + 20, 0, + "i:" + String(scan_iterations) + "/" + String(SAMPLES_RSSI) + "/" + + String(SCANS_PER_DISPLAY), + ST7789_GREEN); + // Scan resolution - r + // Mhz in pixel - s + drawText(DISPLAY_WIDTH - ((DISPLAY_WIDTH / 6) * 2) - 55, 0, + "r:" + String(rssi_mhz_step) + " s:" + String(mhz_step), ST7789_RED); + + // Draw a line horizontally + st7789->drawFastHLine(0, lower_level + 1, DISPLAY_WIDTH, ST7789_WHITE); + // Generate Ticks + for (int x = 0; x < DISPLAY_WIDTH; x++) + { + if (x % (DISPLAY_WIDTH / 2) == 0 && x > 5) + { + st7789->drawFastVLine(x, lower_level + 1, 11, ST7789_WHITE); + // central tick width + st7789->drawFastVLine(x - 1, lower_level + 1, 8, ST7789_WHITE); + st7789->drawFastVLine(x + 1, lower_level + 1, 8, ST7789_WHITE); + } + if (x % 10 == 0 || x == 0) + st7789->drawFastVLine(x, lower_level + 1, 6, ST7789_WHITE); + if (x % 5 == 0) + st7789->drawFastVLine(x, lower_level + 1, 3, ST7789_WHITE); + } + // st7789.setFont(ArialMT_Plain_10); + + // Begin Mhz + drawText(1, DISPLAY_HEIGHT - 10, String(FREQ_BEGIN)); + // Median -1/2 Mhz + drawText((DISPLAY_WIDTH / 4) - 10, DISPLAY_HEIGHT - 10, + String(FREQ_BEGIN + (((int)fr - FREQ_BEGIN) / 4))); + // Median Mhz + drawText((DISPLAY_WIDTH / 2) - 10, DISPLAY_HEIGHT - 10, + String(FREQ_BEGIN + (((int)fr - FREQ_BEGIN) / 2))); + // Median + 1/2 Mhz + drawText((DISPLAY_WIDTH - (DISPLAY_WIDTH / 4)) - 10, DISPLAY_HEIGHT - 10, + String(FREQ_BEGIN + + (((int)fr - FREQ_BEGIN) - ((int)fr - FREQ_BEGIN) / 4))); + // End Mhz + drawText(DISPLAY_WIDTH - 24, DISPLAY_HEIGHT - 10, String((int)fr)); + + // display.display(); + // display will be cleared next scan iteration. it is just buffer clear + // memset(buffer, 0, displayBufferSize); + // display.clear(); + // st7789->fillRect(0, 0, DISPLAY_WIDTH, lower_level, ST7789_BLACK); + screen_update_loop_counter = 0; + scan_iterations = 0; + display_scan_i_end = 0; + } + fr = FREQ_BEGIN; + x1 = 0; + rssi_printed = 0; + // Prevent screen_update_loop_counter++ when it is just nulled + if (scan_iterations > 0) + { + screen_update_loop_counter++; + } + } +#ifdef PRINT_DEBUG + Serial.println("Full Scan:" + String(screen_update_loop_counter)); +#endif +} + +void setup() +{ + Serial.begin(115200); + pinMode(7, OUTPUT); + digitalWrite(7, LOW); + delay(20); + gspi_lcd = new SPIClass(HSPI); + st7789 = + new HT_ST7789(240, 320, gspi_lcd, st7789_CS_Pin, st7789_DC_Pin, st7789_REST_Pin); + gspi_lcd->begin(st7789_SCLK_Pin, -1, st7789_MOSI_Pin, st7789_CS_Pin); + // set up slave select pins as outputs as the Arduino API + pinMode(gspi_lcd->pinSS(), OUTPUT); + st7789->init(170, 320); + + Serial.printf("Ready!\r\n"); + st7789->setRotation(1); + st7789->fillScreen(ST7789_BLACK); + drawText(0, 0, "init >>> ", ST7789_WHITE); + + pinMode(st7789_LED_K_Pin, OUTPUT); + digitalWrite(st7789_LED_K_Pin, HIGH); + // pinMode(5, OUTPUT); + // digitalWrite(5, HIGH); + + st7789->fillScreen(ST7789_BLACK); + // st7789->drawFastHLine(0, 15, 320, ST7789_WHITE); + st7789->drawXBitmap(100, 50, epd_bitmap_ucog, 128, 64, ST7789_WHITE); + init_radio(); + state = radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_NONE); + if (state != RADIOLIB_ERR_NONE) + { + Serial.print(F("Failed to start receive mode, error code: ")); + Serial.println(state); + } + heltec_setup(); + delay(2500); + st7789->fillScreen(ST7789_BLACK); +} From 567dbb01bba0e61f3ea24504a93266e811980aa4 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sun, 8 Sep 2024 01:50:14 -0700 Subject: [PATCH 15/17] return default src --- platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index 51f29ca..0b7648d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -10,7 +10,7 @@ [platformio] ; for env:vision-master-e190 -src_dir = tft_src +; src_dir = tft_src ; for env:vision-master-e290 ; src_dir = eink_src ; for env:heltec_wifi_lora_32_V3 From ef5a6d137d3a99694d56926397789b9c9d3692a8 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Sun, 8 Sep 2024 21:44:43 -0700 Subject: [PATCH 16/17] small fixes --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index ccc69f1..46e996e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -591,7 +591,7 @@ int binToRSSI(int bin) return 11 + (bin * 4); } -// returns tru if continue the code is false breake the loop +// return true if continue the code is false break the loop bool buttonPressHandler(float freq) { // Detection level button short press From e6205733a2a201284185641d845e5635f03bcdd3 Mon Sep 17 00:00:00 2001 From: Egor Shitikov Date: Tue, 10 Sep 2024 19:16:05 -0700 Subject: [PATCH 17/17] Add Color TFT display fixes --- src/main.cpp | 2 +- tft_src/main.cpp | 260 +++++++++++++++++++++++++++++------------------ 2 files changed, 162 insertions(+), 100 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 46e996e..acfc13b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1164,7 +1164,7 @@ void loop(void) // LiLyGo doesn't have button ;( // ToDO: Check if we use BOOT button #ifndef LILYGO - if (buttonPressHandler() == false) + if (buttonPressHandler(freq) == false) break; #endif // END LILYGO diff --git a/tft_src/main.cpp b/tft_src/main.cpp index 4411a0e..4064c97 100644 --- a/tft_src/main.cpp +++ b/tft_src/main.cpp @@ -39,6 +39,9 @@ char buffer[256]; #define DISPLAY_HEIGHT 170 // Without this line Lora Radio doesn't work with heltec lib #define ARDUINO_heltec_wifi_32_lora_V3 +// T190 button pin +#define BUTTON GPIO_NUM_21 +#define HELTEC_POWER_BUTTON #include "heltec_unofficial.h" // We are not using spectral scan here only RSSI method @@ -68,6 +71,7 @@ constexpr bool DRAW_DETECTION_TICKS = true; #define SAMPLES_RSSI 5 // 21 // #define FREQ_BEGIN 650 +#define DEFAULT_DRONE_DETECTION_LEVEL 90 #define RANGE (int)(FREQ_END - FREQ_BEGIN) @@ -110,7 +114,7 @@ bool waterfall[STEPS], detected_y[STEPS]; // 20 - ??? steps of the waterfall bool first_run, new_pixel, detected_x = false; // drone detection flag bool detected = false; -uint64_t drone_detection_level = 90; +uint64_t drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL; uint64_t drone_detected_frequency_start = 0; uint64_t drone_detected_frequency_end = 0; uint64_t detection_count = 0; @@ -138,6 +142,10 @@ float freq = 0; int rssi = 0; int state = 0; +#define MAX_MHZ_INTERVAL 2000 +// 2KB ToDo: make dynamic array or sam structure +uint16_t detailed_scan_candidate[MAX_MHZ_INTERVAL]; + #ifdef METHOD_SPECTRAL constexpr int samples = SAMPLES; #endif @@ -192,21 +200,6 @@ void drawText(uint16_t x, uint16_t y, String text, uint16_t color = ST7789_WHITE st7789->print(text.c_str()); } -void drawSetupText() -{ - // create more fonts at http://oleddisplay.squix.ch/ - /** *display.setTextAlignment(TEXT_ALIGN_LEFT); - display.setFont(ArialMT_Plain_10); - display.drawString(0, 0, "Spectrum Analyzer Lora SA"); - display.setFont(ArialMT_Plain_16); - display.drawString(0, 10, "SX 1262"); - display.setFont(ArialMT_Plain_24); - display.drawString(0, 26, "TFT display"); - display.drawString(0, 56, "RF Spectrum TFT-ray"); - display.setFont(ArialMT_Plain_24); - **/ -} - #define battery_w 13 #define battery_h 13 #define BATTERY_PIN 7 @@ -219,7 +212,6 @@ void battery() #ifdef PRINT_DEBUG Serial.printf("ADC analog value = %.2f\n", battery_levl); #endif - // display.drawString(257, 0, String(heltec_battery_percent(battery_levl)) + "%"); // TODO: battery voltage doesn't work if (battery_levl < battery_one) { @@ -255,17 +247,6 @@ void battery() } } -void VextON(void) -{ - pinMode(18, OUTPUT); - digitalWrite(18, HIGH); -} -void VextOFF(void) // Vext default OFF -{ - pinMode(18, OUTPUT); - digitalWrite(18, LOW); -} - constexpr int lower_level = 108; constexpr int up_level = 40; int rssiToPix(int rssi) @@ -286,18 +267,18 @@ int rssiToPix(int rssi) int rssiToColor(int rssi, bool waterfall = false) { if (rssi < 80) - return 63488; + return ST7789_RED; // Red if (rssi < 85) - return 0xfa08; + return ST7789_GREEN; // Green if (rssi < 90) - return 0xcfe0; + return ST7789_YELLOW; // Yellow if (rssi < 95) - return 0x01ff; + return ST7789_BLUE; // Blue if (rssi < 100) - return 0x8d5f; + return ST7789_MAGENTA; // Magenta if (waterfall) - return ST7789_BLACK; - return ST7789_WHITE; + return ST7789_BLACK; // Black on waterfall + return ST7789_WHITE; // White on chart } long timeSinceLastModeSwitch = 0; @@ -314,7 +295,7 @@ int x1 = 0, y2 = 0; unsigned int screen_update_loop_counter = 0; unsigned int x_screen_update = 0; int rssi_printed = 0; -constexpr int rssi_window_size = 30; +constexpr int rssi_window_size = 45; int max_i_rssi = -999; int window_max_rssi = -999; int window_max_fr = -999; @@ -323,6 +304,8 @@ int max_history_rssi[STEPS + 2]; long display_scan_start = 0; long display_scan_end = 0; long display_scan_i_end = 0; +long rssi_single_start = 0; +long rssi_single_end = 0; int scan_iterations = 0; // will be changed to false after first run bool clear_rssi_history = true; @@ -334,10 +317,10 @@ void loop() { if (screen_update_loop_counter == 0) { + fr_x[x1] = 0; // Zero arrays for (int i = 0; i < STEPS; i++) { - fr_x[x1] = 0; max_scan_rssi[i] = -999; if (clear_rssi_history == true) max_history_rssi[i] = -999; @@ -346,13 +329,27 @@ void loop() display_scan_start = millis(); } fr_x[x1] = fr; + + int u = 0; + int additional_samples = 10; + + // Clear old data with the cursor ... + st7789->drawFastVLine(x1, lower_level, -lower_level + 11, ST7789_BLACK); // Draw max history line st7789->drawLine(x1, rssiToPix(max_history_rssi[x1]), x1, lower_level, 12710 /*gray*/); - int u = 0; // Fetch samples for (int i = 0; i < SAMPLES_RSSI; i++) { + // Checking more times curtain freq + if (additional_samples > 0 && + (detailed_scan_candidate[(int)fr] + detailed_scan_candidate[(int)fr + 1] + + detailed_scan_candidate[(int)fr + 2] > + 0)) + { + i--; + additional_samples--; + } radio.setFrequency((float)fr + (float)(rssi_mhz_step * u), false); // false = no calibration need here @@ -361,35 +358,97 @@ void loop() { u = 0; } - + if (rssi_single_start == 0) + { + rssi_single_start = millis(); + } rssi2 = radio.getRSSI(false); scan_iterations++; - if (rssi2 > lower_level) + if (rssi_single_end == 0) + { + rssi_single_end = millis(); + } + if (abs(rssi2) > lower_level) + { +#ifdef PRINT_DEBUG + Serial.print("SKIP -> " + String(fr) + ":" + String(rssi2)); +#endif + // if lower than detection level set any + if (max_scan_rssi[x1] == -999) + { + max_scan_rssi[x1] = rssi2; + } continue; + } #ifdef PRINT_DEBUG Serial.println(String(fr) + ":" + String(rssi2)); #endif - // display.drawString(x1, (int)y2, String(fr) + ":" + String(rssi2)); - // display.setPixel(x1, rssiToPix(rssi2)); st7789->drawPixel(x1, rssiToPix(rssi2), rssiToColor(abs(rssi2))); st7789->drawPixel(x1, rssiToPix(rssi2) - 1, rssiToColor(abs(rssi2))); st7789->drawPixel(x1, rssiToPix(rssi2) - 2, rssiToColor(abs(rssi2))); // Draw Update Cursor - st7789->drawFastVLine(x1 + 1, lower_level, -lower_level + 25, ST7789_BLACK); - st7789->drawFastVLine(x1 + 2, lower_level, -lower_level + 25, ST7789_BLACK); - st7789->drawFastVLine(x1 + 3, lower_level, -lower_level + 25, ST7789_BLACK); + st7789->drawFastVLine(x1 + 1, lower_level, -lower_level + 11, ST7789_BLACK); + st7789->drawFastVLine(x1 + 2, lower_level, -lower_level + 11, ST7789_BLACK); + st7789->drawFastVLine(x1 + 3, lower_level, -lower_level + 11, ST7789_BLACK); + if (max_scan_rssi[x1] == -999) + { + max_scan_rssi[x1] = rssi2; + } + /// -999 < -100 if (max_scan_rssi[x1] < rssi2) { +#ifdef PRINT_DEBUG + Serial.println("MAx Scan x-" + String(x1) + ": " + String(max_scan_rssi[x1]) + + "< " + String(rssi2)); +#endif max_scan_rssi[x1] = rssi2; if (max_history_rssi[x1] < max_scan_rssi[x1]) { max_history_rssi[x1] = rssi2; } } + // Max dB in window + if (window_max_rssi < max_scan_rssi[x1]) + { + // Max Mhz in window + window_max_fr = fr_x[x1]; + window_max_rssi = max_scan_rssi[x1]; + } + } + // Writing pixel only if it is bigger than drone detection level + if (abs(max_scan_rssi[x1]) < drone_detection_level) + { + // Waterfall Pixel + st7789->drawPixel(x1, w, rssiToColor(abs(max_scan_rssi[x1]), true)); + + detailed_scan_candidate[(int)fr] = (int)fr; + } + else + { + detailed_scan_candidate[(int)fr] = (int)0; + } + // Draw legend for windows + if (x1 % rssi_window_size == 0 || x1 == DISPLAY_WIDTH) + { + if (abs(window_max_rssi) < drone_detection_level && window_max_rssi != 0 && + window_max_rssi != -999) + { + y2 = 15; + + drawText(x1 - rssi_window_size + 3, y2, String(window_max_rssi) + "dB", + rssiToColor(abs(window_max_rssi))); + drawText(x1 - rssi_window_size + 3, y2 + 10, + String((int)window_max_fr) + "MHz", + rssiToColor(abs(window_max_rssi))); + // Vertical lines between windows + for (int l = y2; l < 100; l += 4) + { + st7789->drawPixel(x1, l, ST7789_YELLOW); + } + } + window_max_rssi = -999; } - // Waterfall Pixel - st7789->drawPixel(x1, w, rssiToColor(abs(max_scan_rssi[x1]), true)); // Waterfall cursor st7789->drawFastHLine(0, w + 1, DISPLAY_WIDTH, ST7789_BLACK); @@ -398,69 +457,63 @@ void loop() // drone detection level line if (x1 % 2 == 0) { - // display.setPixel(x1, rssiToPix(drone_detection_level)); - st7789->drawPixel(x1, rssiToPix(drone_detection_level) + 3, ST7789_GREEN); + st7789->drawPixel(x1, rssiToPix(drone_detection_level), ST7789_GREEN); } fr += mhz_step; - x1++; + if (display_scan_i_end == 0) { display_scan_i_end = millis(); } + // Button Logic + heltec_loop(); + button_pressed_counter = 0; + if (button.pressed()) + { + drone_detection_level++; + if (drone_detection_level > 107) + drone_detection_level = DEFAULT_DRONE_DETECTION_LEVEL - 20; + } + if (button.pressedFor(500)) + { + while (button.pressedNow()) + { + button_pressed_counter++; + // button.update(); + delay(50); + if (button_pressed_counter > 18) + { + drawText(320 - 5, 5, "*", ST7789_WHITE); + } + } + drone_detection_level--; + } + if (button_pressed_counter < 18 && button_pressed_counter > 10) + { + heltec_deep_sleep(); + } + // Main N x-axis full loop end logic if (x1 >= STEPS) { w++; if (w > WATERFALL_END) + { w = WATERFALL_START; + } +#ifdef PRINT_DEBUG + Serial.println("Screen End for Output: " + String(screen_update_loop_counter)); +#endif + // Doing output only after full scan if (screen_update_loop_counter + 1 == SCANS_PER_DISPLAY) { - // max Mhz and dB in window - for (int i = 0; i < STEPS; i++) - { - // Max dB in window - if (window_max_rssi < max_scan_rssi[i]) - { - // Max Mhz in window - window_max_fr = fr_x[i]; - window_max_rssi = max_scan_rssi[i]; - } - if (i % rssi_window_size == 0 || (i % (DISPLAY_WIDTH - 1)) == 0) - { - - if (abs(window_max_rssi) < drone_detection_level) - { - y2 = 10; - - /** display.setFont(ArialMT_Plain_10); - display.drawStringMaxWidth(i - rssi_window_size, y2, - rssi_window_size, - String(window_max_rssi) + "dB"); - display.drawString(i - rssi_window_size + 5, y2 + 10, - String(window_max_fr)); - */ - drawText(i - rssi_window_size, y2, String(window_max_rssi) + "dB", - rssiToColor(window_max_rssi)); - drawText(i - rssi_window_size + 5, y2, - String(String(window_max_fr)) + "dB", - rssiToColor(window_max_rssi)); - // Vertical lines between windows - for (int l = y2; l < 100; l += 4) - { - st7789->drawPixel(i, l, ST7789_YELLOW); - // display.setPixel(i, l); - } - } - window_max_rssi = -999; - } - } - + // Scan results to max Mhz and dB in window display_scan_end = millis(); - // display.setFont(ArialMT_Plain_10); + st7789->fillRect(0, 0, DISPLAY_WIDTH, 11, ST7789_BLACK); drawText(0, 0, "T:" + String(display_scan_end - display_scan_start) + "/" + - String(display_scan_i_end - display_scan_start) + " L:-" + + String(rssi_single_end - rssi_single_start) + " L:-" + String(drone_detection_level) + "dB", ST7789_BLUE); @@ -509,16 +562,13 @@ void loop() // End Mhz drawText(DISPLAY_WIDTH - 24, DISPLAY_HEIGHT - 10, String((int)fr)); - // display.display(); - // display will be cleared next scan iteration. it is just buffer clear - // memset(buffer, 0, displayBufferSize); - // display.clear(); - // st7789->fillRect(0, 0, DISPLAY_WIDTH, lower_level, ST7789_BLACK); screen_update_loop_counter = 0; scan_iterations = 0; display_scan_i_end = 0; } fr = FREQ_BEGIN; + rssi_single_start = 0; + rssi_single_end = 0; x1 = 0; rssi_printed = 0; // Prevent screen_update_loop_counter++ when it is just nulled @@ -527,13 +577,23 @@ void loop() screen_update_loop_counter++; } } + // not increase at the end of scan when nulled + else + { + x1++; + } + #ifdef PRINT_DEBUG - Serial.println("Full Scan:" + String(screen_update_loop_counter)); + Serial.println("Full Scan Counter:" + String(screen_update_loop_counter)); #endif } void setup() { + for (int i = 0; i < MAX_MHZ_INTERVAL; i++) + { + detailed_scan_candidate[i] = 0; + } Serial.begin(115200); pinMode(7, OUTPUT); digitalWrite(7, LOW); @@ -545,6 +605,8 @@ void setup() // set up slave select pins as outputs as the Arduino API pinMode(gspi_lcd->pinSS(), OUTPUT); st7789->init(170, 320); + st7789->setSPISpeed(40000000); + /// st7789->setSPISpeed(3000000); /// default ~ 1000000 Serial.printf("Ready!\r\n"); st7789->setRotation(1); @@ -557,7 +619,7 @@ void setup() // digitalWrite(5, HIGH); st7789->fillScreen(ST7789_BLACK); - // st7789->drawFastHLine(0, 15, 320, ST7789_WHITE); + st7789->drawXBitmap(100, 50, epd_bitmap_ucog, 128, 64, ST7789_WHITE); init_radio(); state = radio.startReceive(RADIOLIB_SX126X_RX_TIMEOUT_NONE);