Merge pull request #23 from Genaker/feature/eink

e-ink
This commit is contained in:
Egor Shitikov
2024-09-10 19:17:41 -07:00
committed by GitHub
18 changed files with 3873 additions and 313 deletions

View File

@@ -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:
<https://heltec.org/project/wifi-lora-32-v3/>
<https://www.aliexpress.us/item/3256807037422978.html>
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 :
<https://www.amazon.com/EEMB-2000mAh-Battery-Rechargeable-Connector/dp/B08214DJLJ>

45
boards/t3_s3_v1_x.json Normal file
View File

@@ -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"
}

109
eink_src/images.h Normal file
View File

@@ -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,
};

497
eink_src/main.cpp Normal file
View File

@@ -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 <Arduino.h>
// 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);
}

View File

@@ -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 <BLEAdvertisedDevice.h>
#include <BLEDevice.h>
#include <BLEScan.h>
#include <BLEUtils.h>
#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;
}

167
include/LiLyGo.h Normal file
View File

@@ -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 <SPI.h>
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
}

929
include/LoRaBoards.cpp Normal file
View File

@@ -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

97
include/LoRaBoards.h Normal file
View File

@@ -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 <SD.h>
#endif
#if defined(ARDUINO_ARCH_ESP32)
#include <FS.h>
#include <WiFi.h>
#endif
#include <Arduino.h>
#include <SPI.h>
#include <U8g2lib.h>
#include <Wire.h>
#include <XPowersLib.h>
#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

View File

@@ -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

63
include/joyStick.h Normal file
View File

@@ -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. Its 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;
}

View File

@@ -1,9 +1,12 @@
#pragma once
#ifdef Vision_Master_E290
#include "HT_DEPG0290BxS800FxX_BW.h"
#else
#include "OLEDDisplayUi.h"
#include "SSD1306Wire.h"
#include <Arduino.h>
#endif
// #include <heltec_unofficial.h>
@@ -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);

551
include/utilities.h Normal file
View File

@@ -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 Radios
* 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 <utilities.h>"
#endif

View File

@@ -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

View File

@@ -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,

File diff suppressed because it is too large Load Diff

View File

@@ -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; }

109
tft_src/images.h Normal file
View File

@@ -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,
};

634
tft_src/main.cpp Normal file
View File

@@ -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 <Adafruit_GFX.h>
#include <Arduino.h>
#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);
}