diff --git a/README.md b/README.md index 5cc1732..7ac2249 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. @@ -182,6 +185,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 : 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/eink_src/images.h b/eink_src/images.h new file mode 100644 index 0000000..5021a8f --- /dev/null +++ b/eink_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/eink_src/main.cpp b/eink_src/main.cpp new file mode 100644 index 0000000..a87ece8 --- /dev/null +++ b/eink_src/main.cpp @@ -0,0 +1,497 @@ +/* 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_DEPG0290BxS800FxX_BW.h" +#include "global_config.h" +#include "images.h" +#include "ui.h" +#include + +// 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 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 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 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 + +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 + +// Initialize the display +DEPG0290BxS800FxX_BW display(5, 4, 3, 6, 2, 1, -1, + 6000000); // rst,dc,cs,busy,sck,mosi,miso,frequency +/* screen rotation + * ANGLE_0_DEGREE + * ANGLE_90_DEGREE + * ANGLE_180_DEGREE + * ANGLE_270_DEGREE + */ +#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 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, "e-ink display"); + display.drawString(0, 56, "RF Spectrum X-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); +} + +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]; +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; +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; + } + display_scan_start = millis(); + } + fr_x[x1] = fr; + int u = 0; + 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)); + + if (max_scan_rssi[x1] < rssi2) + { + max_scan_rssi[x1] = rssi2; + } + } + + // drone detection level line + if (x1 % 2 == 0) + { + display.setPixel(x1, rssiToPix(drone_detection_level)); + } + 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) + { + if (screen_update_loop_counter == 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)); + // 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) + + "/" + String(display_scan_i_end - display_scan_start) + + " L:-" + String(drone_detection_level) + "dB"); + + // 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.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, 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); + if (x % 5 == 0) + display.drawVerticalLine(x, lower_level + 1, 3); + } + display.setFont(ArialMT_Plain_10); + + // Begin Mhz + 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 + (((int)fr - FREQ_BEGIN) / 4))); + // Median Mhz + display.drawString((DISPLAY_WIDTH / 2) - 10, DISPLAY_HEIGHT - 10, + 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 + (((int)fr - FREQ_BEGIN) - + ((int)fr - FREQ_BEGIN) / 4))); + // End Mhz + 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 + // memset(buffer, 0, displayBufferSize); + display.clear(); + 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() +{ + // 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(1000); + 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(); + + drawSetupText(); + display.display(); + display.clear(); + delay(100); +} diff --git a/include/BT_WIFI_scan.h b/include/BT_WIFI_scan.h index 5a4722b..d0b2be5 100644 --- a/include/BT_WIFI_scan.h +++ b/include/BT_WIFI_scan.h @@ -1,4 +1,110 @@ #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(DFRobot_OSD osd) +{ + 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); +} + +//********************** +// 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/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 115bf4a..d169fff 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 @@ -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/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/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 5c24979..0b7648d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -8,12 +8,124 @@ ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html +[platformio] +; 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 board = heltec_wifi_lora_32_V3 framework = arduino +upload_speed = 921600 +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 +framework = arduino +upload_speed = 921600 +monitor_speed = 115200 +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 + -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 + +[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 +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] +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=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 + 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 + +[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/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, diff --git a/src/main.cpp b/src/main.cpp index 6d3d619..acfc13b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,14 +21,30 @@ https://jgromes.github.io/RadioLib/ */ +// #define HELTEC_NO_DISPLAY + #include -#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 +#ifndef LILYGO +#include +// This file contains a binary patch for the SX1262 +#include "modules/SX126x/patches/SX126x_patch_scan.h" +#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 long noDevicesMillis = 0, cycleCnt = 0; @@ -41,9 +57,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] = { @@ -112,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; @@ -127,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" @@ -152,15 +157,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. @@ -177,16 +186,17 @@ 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 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 // @@ -241,7 +251,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; @@ -260,110 +270,28 @@ uint8_t result_index = 0; uint8_t button_pressed_counter = 0; uint64_t loop_cnt = 0; -#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); -} +#ifndef LILYGO +// #define JOYSTICK_ENABLED #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++; +#include "joyStick.h" - 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); +// project components +#if (defined(WIFI_SCANNING_ENABLED) || defined(BT_SCANNING_ENABLED)) && \ + defined(OSD_ENABLED) +#include "BT_WIFI_scan.h" #endif - BLEScanResults foundDevices = pBLEScan->start(BT_SCAN_TIME); - int count = foundDevices.getCount(); -#ifdef PRINT_DEBUG - Serial.printf("Found devices: %d \n", count); +#if defined(WIFI_SCANNING_ENABLED) && defined(OSD_ENABLED) +scanWiFi(osd) #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) { @@ -380,14 +308,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 +347,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 +371,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 { @@ -473,6 +396,51 @@ void osdProcess() } #endif +void init_radio() +{ + // initialize SX1262 FSK modem at the initial frequency + both.println("Init radio"); + 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); + } + } + +#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 + 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 +#endif + + 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 @@ -502,6 +470,10 @@ void setup(void) 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++) { @@ -517,28 +489,11 @@ void setup(void) } } - // 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..."); + 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(); @@ -565,7 +520,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"); @@ -610,17 +565,15 @@ 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); 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 @@ -631,16 +584,179 @@ 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); } +// return true if continue the code is false break 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, + // 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 + } + } +} + +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 + detection_count = 0; drone_detected_frequency_start = 0; ranges_count = 0; @@ -648,7 +764,7 @@ void loop(void) // reset scan time scan_time = 0; - // general purpose loop conter + // general purpose loop counter loop_cnt++; #ifdef PRINT_PROFILE_TIME @@ -683,25 +799,7 @@ 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; - } + check_ranges(); // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz for (range_item = 0; range_item < iterations; range_item++) @@ -745,11 +843,7 @@ void loop(void) // x loop for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) { - - if (x % SCAN_RBW_FACTOR == 0) - new_pixel = true; - else - new_pixel = false; + new_pixel = is_new_x_pixel(x); if (ANIMATED_RELOAD && SCAN_RBW_FACTOR == 1) { UI_drawCursor(x); @@ -765,13 +859,32 @@ 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; +#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); @@ -782,15 +895,26 @@ void loop(void) // 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.print("radio.spectralScanGetStatus ERROR: "); + Serial.println("radio.spectralScanGetStatus ERROR: "); Serial.println(radio.spectralScanGetStatus()); - heltec_delay(ONE_MILLISEC * 10); + 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 - radio.spectralScanGetResult(result); + state = radio.spectralScanGetResult(result); + display.drawString(0, 64 - 10, "scanGetResult:" + String(state)); } + #endif #ifdef METHOD_RSSI // Spectrum analyzer using getRSSI @@ -810,9 +934,20 @@ void loop(void) 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 + // 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); @@ -835,16 +970,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++) { @@ -853,7 +997,6 @@ void loop(void) 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) { @@ -867,6 +1010,7 @@ void loop(void) // 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 @@ -893,24 +1037,24 @@ void loop(void) { 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[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); - #if (WATERFALL_ENABLED == true) 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 @@ -922,70 +1066,50 @@ void loop(void) // mark freq end ... will shift right to last detected range drone_detected_frequency_end = freq; - - // 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 (SOUND_ON == true) { - 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 everey 5th time - } - } - else - { - if (detection_count % 20 == 0 && SOUND_ON) - { - tone(BUZZER_PIN, 205, - 10); // same action ??? but everey 20th detection - } + 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[dispaly_x]) + if (!detected_y[display_x]) { - display.drawLine(dispaly_x, 1, dispaly_x, 6); - 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 - -#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(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 - display.setPixel(dispaly_x, y); + if (y < MAX_POWER_LEVELS - START_LOW) + { + display.setPixel(display_x, y + START_LOW); + } if (!detected) { detected = true; @@ -995,20 +1119,31 @@ 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); - display.setPixel(dispaly_x, y - 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 + // 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); #endif @@ -1026,75 +1161,34 @@ void loop(void) display.display(); } - // Detection level button short press - if (button.pressedFor(100)) - { - button.update(); - button_pressed_counter = 0; - // if long press stop - while (button.pressedNow()) - { - delay(10); - // Print Curent frequency - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(128 / 2, 0, String(freq)); - display.display(); - button_pressed_counter++; - if (button_pressed_counter > 150) - { - digitalWrite(LED, HIGH); - delay(150); - digitalWrite(LED, LOW); - } - } - if (button_pressed_counter > 150) - { - // Remove Curent Freqancy Text - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setColor(BLACK); - display.drawString(128 / 2, 0, String(freq)); - display.setColor(WHITE); - display.display(); - break; - } - if (button_pressed_counter > 50 && button_pressed_counter < 150) - { - // Visually confirm it's off so user releases button - display.displayOff(); - // Deep sleep (has wait for release so we don't wake up - // immediately) - heltec_deep_sleep(); - break; - } - button.update(); - display.setTextAlignment(TEXT_ALIGN_RIGHT); - // erase old 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; - } - } +// LiLyGo doesn't have button ;( +// ToDO: Check if we use BOOT button +#ifndef LILYGO + if (buttonPressHandler(freq) == false) + break; +#endif // END LILYGO + // wait a little bit before the next scan, // otherwise the SX1262 hangs - // Add more logic before insead of long delay... + // Add more logic before instead of long delay... int delay_cnt = 1; - while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) +#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(" + @@ -1102,12 +1196,18 @@ void loop(void) ") hard delay(2) - " + String(delay_cnt)); // if error than speed is slow animating chart ANIMATED_RELOAD = true; - + delay(50); delay_cnt++; } - // TODO: move osd logic here as a dalay ;) +#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); + joystickMoveCursor(joy_x_pressed); +#endif } w++; if (w > ROW_STATUS_TEXT + 1) @@ -1126,8 +1226,8 @@ void loop(void) // 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. + // 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) { @@ -1141,12 +1241,12 @@ void loop(void) global_counter++; #endif } - #ifdef PRINT_DEBUG // Serial.println("----"); #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); 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; } 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..4064c97 --- /dev/null +++ b/tft_src/main.cpp @@ -0,0 +1,634 @@ +/* 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 +// 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 +// #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 DEFAULT_DRONE_DETECTION_LEVEL 90 + +#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 = 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 + +#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; + +#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 +#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()); +} + +#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 + // 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); + } +} + +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 ST7789_RED; // Red + if (rssi < 85) + return ST7789_GREEN; // Green + if (rssi < 90) + return ST7789_YELLOW; // Yellow + if (rssi < 95) + return ST7789_BLUE; // Blue + if (rssi < 100) + return ST7789_MAGENTA; // Magenta + if (waterfall) + return ST7789_BLACK; // Black on waterfall + return ST7789_WHITE; // White on chart +} + +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 = 45; +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; +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; + +constexpr unsigned int SCANS_PER_DISPLAY = 1; +constexpr unsigned int STATUS_BAR_HEIGHT = 5; + +void loop() +{ + if (screen_update_loop_counter == 0) + { + fr_x[x1] = 0; + // Zero arrays + for (int i = 0; i < STEPS; i++) + { + 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; + + 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*/); + // 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 + u++; + if (rssi_mhz_step * u >= mhz_step) + { + u = 0; + } + if (rssi_single_start == 0) + { + rssi_single_start = millis(); + } + rssi2 = radio.getRSSI(false); + scan_iterations++; + 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 + 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 + 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 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) + { + st7789->drawPixel(x1, rssiToPix(drone_detection_level), ST7789_GREEN); + } + fr += mhz_step; + + 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) + { + // Scan results to max Mhz and dB in window + display_scan_end = millis(); + + st7789->fillRect(0, 0, DISPLAY_WIDTH, 11, ST7789_BLACK); + drawText(0, 0, + "T:" + String(display_scan_end - display_scan_start) + "/" + + String(rssi_single_end - rssi_single_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)); + + 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 + if (scan_iterations > 0) + { + screen_update_loop_counter++; + } + } + // not increase at the end of scan when nulled + else + { + x1++; + } + +#ifdef PRINT_DEBUG + 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); + 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); + st7789->setSPISpeed(40000000); + /// st7789->setSPISpeed(3000000); /// default ~ 1000000 + + 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->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); +}