diff --git a/boards/t3_s3_v1_x.json b/boards/t3_s3_v1_x.json new file mode 100644 index 0000000..2ecfff8 --- /dev/null +++ b/boards/t3_s3_v1_x.json @@ -0,0 +1,45 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "partitions": "default.csv", + "memory_type": "qio_qspi" + }, + "core": "esp32", + "extra_flags": [ + "-DARDUINO_LILYGO_T3_S3_V1_X", + "-DBOARD_HAS_PSRAM", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1", + "-DARDUINO_USB_MODE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "mcu": "esp32s3", + "variant": "esp32s3" + }, + "connectivity": [ + "wifi" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino", + "espidf" + ], + "name": "LilyGo T3-S3 Radio", + "upload": { + "flash_size": "4MB", + "maximum_ram_size": 327680, + "maximum_size": 4194304, + "use_1200bps_touch": true, + "wait_for_upload_port": true, + "require_upload_port": true, + "speed": 460800 + }, + "url": "https://www.lilygo.cc", + "vendor": "LilyGo" +} diff --git a/include/BT_WIFI_scan.h b/include/BT_WIFI_scan.h index 5a4722b..8313111 100644 --- a/include/BT_WIFI_scan.h +++ b/include/BT_WIFI_scan.h @@ -1,4 +1,52 @@ #pragma once -extern void scanWiFiWithOSDOut(); -extern void scanBTWithOSDOut(); +#ifdef WIFI_SCANNING_ENABLED +#include "WiFi.h" +#endif +#ifdef BT_SCANNING_ENABLED +#include +#include +#include +#include +#endif +#include "DFRobot_OSD.h" + +void setOSD() {} +// TODO: Make Async Scan +// https://arduino-esp8266.readthedocs.io/en/latest/esp8266wifi/scan-examples.html#async-scan +void scanWiFi(void) +{ + osd.clear(); + osd.displayString(14, 2, "Scanning WiFi.."); + int n = WiFi.scanNetworks(); +#ifdef PRINT_DEBUG + Serial.println("scan done"); + if (n == 0) + { + Serial.println("no networks found"); + } +#endif + if (n > 0) + { +#ifdef PRINT_DEBUG + Serial.print(n); + Serial.println(" networks found"); +#endif + for (int i = 0; i < n; ++i) + { +// Print SSID and RSSI for each network found +#ifdef PRINT_DEBUG + Serial.print(i + 1); + Serial.print(": "); + Serial.print(WiFi.SSID(i)); + Serial.print(" ("); + Serial.print(WiFi.RSSI(i)); + Serial.print(")"); + Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN) ? " " : "*"); +#endif + osd.displayString(i + 1, 1, + "WF:" + String((WiFi.SSID(i) + ":" + WiFi.RSSI(i)))); + } + } + osd.displayChar(14, 1, 0x10f); +} diff --git a/include/LiLyGo.h b/include/LiLyGo.h new file mode 100644 index 0000000..ec8754c --- /dev/null +++ b/include/LiLyGo.h @@ -0,0 +1,167 @@ + +#define UNUSED_PIN (0) +// LilyGo defined + +#define I2C_SDA 18 +#define I2C_SCL 17 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 3 +#define RADIO_MOSI_PIN 6 +#define RADIO_CS_PIN 7 + +#define SDCARD_MOSI 11 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 37 +#define LED_ON HIGH + +#define BUTTON_PIN 0 +#define ADC_PIN 1 + +#define RADIO_RST_PIN 8 + +#define RADIO_DIO1_PIN 33 +#define RADIO_BUSY_PIN 34 + +// Define for our code +#define RST_OLED UNUSED_PIN +#define LED BOARD_LED + +#include "RadioLib.h" +// make sure the power off button works when using RADIOLIB_OR_HALT +// (See RadioLib_convenience.h) +#define RADIOLIB_DO_DURING_HALT heltec_delay(10) +#include "RadioLib_convenience.h" +#ifdef HELTEC_NO_DISPLAY +#define HELTEC_NO_DISPLAY_INSTANCE +#else +#define DISPLAY_WIDTH 128 +#define DISPLAY_HEIGHT 64 +#include "OLEDDisplayUi.h" +#include "SSD1306Wire.h" +#endif +#define ARDUINO_heltec_wifi_32_lora_V3 +#ifndef HELTEC_NO_RADIO_INSTANCE +#ifndef ARDUINO_heltec_wifi_32_lora_V3 +// Assume MISO and MOSI being wrong when not using Heltec's board definition +// and use hspi to make it work anyway. See heltec_setup() for the actual SPI setup. +#include +SPIClass *hspi = new SPIClass(2); +SX1262 radio = new Module(SS, DIO1, RST_LoRa, BUSY_LoRa, *hspi); +#else +// Default SPI on pins from pins_arduino.h +SX1262 radio = new Module(RADIO_CS_PIN, RADIO_DIO1_PIN, RADIO_RST_PIN, RADIO_BUSY_PIN); +#endif +#endif + +void heltec_loop() {} + +void heltec_led(int led) {} + +void heltec_deep_sleep() {} + +void heltec_delay(int millisec) { delay(millisec); } + +#ifndef HELTEC_NO_DISPLAY_INSTANCE +/** + * @class PrintSplitter + * @brief A class that splits the output of the Print class to two different + * Print objects. + * + * The PrintSplitter class is used to split the output of the Print class to two + * different Print objects. It overrides the write() function to write the data + * to both Print objects. + */ +class PrintSplitter : public Print +{ + public: + PrintSplitter(Print &_a, Print &_b) : a(_a), b(_b) {} + size_t write(uint8_t c) + { + a.write(c); + return b.write(c); + } + size_t write(const char *str) + { + a.write(str); + return b.write(str); + } + + private: + Print &a; + Print &b; +}; + +#ifdef HELTEC_WIRELESS_STICK +#define DISPLAY_GEOMETRY GEOMETRY_64_32 +#else +#define DISPLAY_GEOMETRY GEOMETRY_128_64 +#endif +SSD1306Wire display(0x3c, 18, 17, DISPLAY_GEOMETRY); +PrintSplitter both(Serial, display); +#else +Print &both = Serial; +#endif +// some fake pin +#define BUTTON 38 +#include "HotButton.h" +HotButton button(BUTTON); + +// This file contains a binary patch for the SX1262 +#include "modules/SX126x/patches/SX126x_patch_scan.h" + +void heltec_display_power(bool on) +{ +#ifndef HELTEC_NO_DISPLAY_INSTANCE + if (on) + { +#ifdef HELTEC_WIRELESS_STICK + // They hooked the display to "external" power, and didn't tell anyone + heltec_ve(true); + delay(5); +#endif + pinMode(RST_OLED, OUTPUT); + digitalWrite(RST_OLED, HIGH); + delay(1); + digitalWrite(RST_OLED, LOW); + delay(20); + digitalWrite(RST_OLED, HIGH); + } + else + { +#ifdef HELTEC_WIRELESS_STICK + heltec_ve(false); +#else + display.displayOff(); +#endif + } +#endif +} +void heltec_setup() +{ + Serial.begin(115200); + Serial.println("LILYGO BOARD"); + +#if defined(ARDUINO_ARCH_ESP32) + SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN); +#elif defined(ARDUINO_ARCH_STM32) + SPI.setMISO(RADIO_MISO_PIN); + SPI.setMOSI(RADIO_MOSI_PIN); + SPI.setSCLK(RADIO_SCLK_PIN); + SPI.begin(); +#endif + +#ifndef ARDUINO_heltec_wifi_32_lora_V3 + hspi->begin(SCK, MISO, MOSI, SS); +#endif +#ifndef HELTEC_NO_DISPLAY_INSTANCE + heltec_display_power(true); + display.init(); + display.setContrast(200); + display.flipScreenVertically(); +#endif +} diff --git a/include/LoRaBoards.cpp b/include/LoRaBoards.cpp new file mode 100644 index 0000000..04c93a6 --- /dev/null +++ b/include/LoRaBoards.cpp @@ -0,0 +1,929 @@ +/** + * @file boards.cpp + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd + * @date 2024-04-24 + * @last-update 2024-08-07 + * + */ + +#include "LoRaBoards.h" + +#if defined(HAS_SDCARD) +SPIClass SDCardSPI(HSPI); +#endif + +#if defined(ARDUINO_ARCH_STM32) +HardwareSerial SerialGPS(GPS_RX_PIN, GPS_TX_PIN); +#endif + +#if defined(ARDUINO_ARCH_ESP32) +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) +#include "hal/gpio_hal.h" +#endif +#include "driver/gpio.h" +#endif // ARDUINO_ARCH_ESP32 + +DISPLAY_MODEL *u8g2 = NULL; +static DevInfo_t devInfo; + +#ifdef HAS_GPS +static bool find_gps = false; +#endif + +#ifdef HAS_PMU +XPowersLibInterface *PMU = NULL; +bool pmuInterrupt; + +static void setPmuFlag() { pmuInterrupt = true; } +#endif + +bool beginPower() +{ +#ifdef HAS_PMU + if (!PMU) + { + PMU = new XPowersAXP2101(PMU_WIRE_PORT); + if (!PMU->init()) + { + Serial.println("Warning: Failed to find AXP2101 power management"); + delete PMU; + PMU = NULL; + } + else + { + Serial.println("AXP2101 PMU init succeeded, using AXP2101 PMU"); + } + } + + if (!PMU) + { + PMU = new XPowersAXP192(PMU_WIRE_PORT); + if (!PMU->init()) + { + Serial.println("Warning: Failed to find AXP192 power management"); + delete PMU; + PMU = NULL; + } + else + { + Serial.println("AXP192 PMU init succeeded, using AXP192 PMU"); + } + } + + if (!PMU) + { + return false; + } + + PMU->setChargingLedMode(XPOWERS_CHG_LED_CTRL_CHG); + + pinMode(PMU_IRQ, INPUT_PULLUP); + attachInterrupt(PMU_IRQ, setPmuFlag, FALLING); + + if (PMU->getChipModel() == XPOWERS_AXP192) + { + + PMU->setProtectedChannel(XPOWERS_DCDC3); + + // lora + PMU->setPowerChannelVoltage(XPOWERS_LDO2, 3300); + // gps + PMU->setPowerChannelVoltage(XPOWERS_LDO3, 3300); + // oled + PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300); + + PMU->enablePowerOutput(XPOWERS_LDO2); + PMU->enablePowerOutput(XPOWERS_LDO3); + + // protected oled power source + PMU->setProtectedChannel(XPOWERS_DCDC1); + // protected esp32 power source + PMU->setProtectedChannel(XPOWERS_DCDC3); + // enable oled power + PMU->enablePowerOutput(XPOWERS_DCDC1); + + // disable not use channel + PMU->disablePowerOutput(XPOWERS_DCDC2); + + PMU->disableIRQ(XPOWERS_AXP192_ALL_IRQ); + + PMU->enableIRQ(XPOWERS_AXP192_VBUS_REMOVE_IRQ | XPOWERS_AXP192_VBUS_INSERT_IRQ | + XPOWERS_AXP192_BAT_CHG_DONE_IRQ | + XPOWERS_AXP192_BAT_CHG_START_IRQ | XPOWERS_AXP192_BAT_REMOVE_IRQ | + XPOWERS_AXP192_BAT_INSERT_IRQ | XPOWERS_AXP192_PKEY_SHORT_IRQ); + } + else if (PMU->getChipModel() == XPOWERS_AXP2101) + { + +#if defined(CONFIG_IDF_TARGET_ESP32) + // Unuse power channel + PMU->disablePowerOutput(XPOWERS_DCDC2); + PMU->disablePowerOutput(XPOWERS_DCDC3); + PMU->disablePowerOutput(XPOWERS_DCDC4); + PMU->disablePowerOutput(XPOWERS_DCDC5); + PMU->disablePowerOutput(XPOWERS_ALDO1); + PMU->disablePowerOutput(XPOWERS_ALDO4); + PMU->disablePowerOutput(XPOWERS_BLDO1); + PMU->disablePowerOutput(XPOWERS_BLDO2); + PMU->disablePowerOutput(XPOWERS_DLDO1); + PMU->disablePowerOutput(XPOWERS_DLDO2); + + // GNSS RTC PowerVDD 3300mV + PMU->setPowerChannelVoltage(XPOWERS_VBACKUP, 3300); + PMU->enablePowerOutput(XPOWERS_VBACKUP); + + // ESP32 VDD 3300mV + // ! No need to set, automatically open , Don't close it + // PMU->setPowerChannelVoltage(XPOWERS_DCDC1, 3300); + // PMU->setProtectedChannel(XPOWERS_DCDC1); + PMU->setProtectedChannel(XPOWERS_DCDC1); + + // LoRa VDD 3300mV + PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO2); + + // GNSS VDD 3300mV + PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO3); + +#endif /*CONFIG_IDF_TARGET_ESP32*/ + +#if defined(T_BEAM_S3_SUPREME) + + // t-beam m.2 inface + // gps + PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO4); + + // lora + PMU->setPowerChannelVoltage(XPOWERS_ALDO3, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO3); + + // In order to avoid bus occupation, during initialization, the SD card and QMC + // sensor are powered off and restarted + if (ESP_SLEEP_WAKEUP_UNDEFINED == esp_sleep_get_wakeup_cause()) + { + Serial.println("Power off and restart ALDO BLDO.."); + PMU->disablePowerOutput(XPOWERS_ALDO1); + PMU->disablePowerOutput(XPOWERS_ALDO2); + PMU->disablePowerOutput(XPOWERS_BLDO1); + delay(250); + } + + // Sensor + PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO1); + + PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO2); + + // Sdcard + + PMU->setPowerChannelVoltage(XPOWERS_BLDO1, 3300); + PMU->enablePowerOutput(XPOWERS_BLDO1); + + PMU->setPowerChannelVoltage(XPOWERS_BLDO2, 3300); + PMU->enablePowerOutput(XPOWERS_BLDO2); + + // face m.2 + PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC3); + + PMU->setPowerChannelVoltage(XPOWERS_DCDC4, XPOWERS_AXP2101_DCDC4_VOL2_MAX); + PMU->enablePowerOutput(XPOWERS_DCDC4); + + PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC5); + + // not use channel + PMU->disablePowerOutput(XPOWERS_DCDC2); + // PMU->disablePowerOutput(XPOWERS_DCDC4); + // PMU->disablePowerOutput(XPOWERS_DCDC5); + PMU->disablePowerOutput(XPOWERS_DLDO1); + PMU->disablePowerOutput(XPOWERS_DLDO2); + PMU->disablePowerOutput(XPOWERS_VBACKUP); + +#elif defined(T_BEAM_S3_BPF) + + // gps + PMU->setPowerChannelVoltage(XPOWERS_ALDO4, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO4); + + // Sdcard + PMU->setPowerChannelVoltage(XPOWERS_ALDO2, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO2); + + // Extern Power source + PMU->setPowerChannelVoltage(XPOWERS_DCDC3, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC3); + + PMU->setPowerChannelVoltage(XPOWERS_DCDC5, 3300); + PMU->enablePowerOutput(XPOWERS_DCDC5); + + PMU->setPowerChannelVoltage(XPOWERS_ALDO1, 3300); + PMU->enablePowerOutput(XPOWERS_ALDO1); + + // not use channel + PMU->disablePowerOutput(XPOWERS_BLDO1); + PMU->disablePowerOutput(XPOWERS_BLDO2); + PMU->disablePowerOutput(XPOWERS_DCDC4); + PMU->disablePowerOutput(XPOWERS_DCDC2); + PMU->disablePowerOutput(XPOWERS_DCDC4); + PMU->disablePowerOutput(XPOWERS_DCDC5); + PMU->disablePowerOutput(XPOWERS_DLDO1); + PMU->disablePowerOutput(XPOWERS_DLDO2); + PMU->disablePowerOutput(XPOWERS_VBACKUP); + +#endif + + // Set constant current charge current limit + PMU->setChargerConstantCurr(XPOWERS_AXP2101_CHG_CUR_500MA); + + // Set charge cut-off voltage + PMU->setChargeTargetVoltage(XPOWERS_AXP2101_CHG_VOL_4V2); + + // Disable all interrupts + PMU->disableIRQ(XPOWERS_AXP2101_ALL_IRQ); + // Clear all interrupt flags + PMU->clearIrqStatus(); + // Enable the required interrupt function + PMU->enableIRQ( + XPOWERS_AXP2101_BAT_INSERT_IRQ | XPOWERS_AXP2101_BAT_REMOVE_IRQ | // BATTERY + XPOWERS_AXP2101_VBUS_INSERT_IRQ | XPOWERS_AXP2101_VBUS_REMOVE_IRQ | // VBUS + XPOWERS_AXP2101_PKEY_SHORT_IRQ | XPOWERS_AXP2101_PKEY_LONG_IRQ | // POWER KEY + XPOWERS_AXP2101_BAT_CHG_DONE_IRQ | XPOWERS_AXP2101_BAT_CHG_START_IRQ // CHARGE + // XPOWERS_AXP2101_PKEY_NEGATIVE_IRQ | XPOWERS_AXP2101_PKEY_POSITIVE_IRQ | + // //POWER KEY + ); + } + + PMU->enableSystemVoltageMeasure(); + PMU->enableVbusVoltageMeasure(); + PMU->enableBattVoltageMeasure(); + + Serial.printf("=========================================\n"); + if (PMU->isChannelAvailable(XPOWERS_DCDC1)) + { + Serial.printf("DC1 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC1) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC1)); + } + if (PMU->isChannelAvailable(XPOWERS_DCDC2)) + { + Serial.printf("DC2 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC2) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC2)); + } + if (PMU->isChannelAvailable(XPOWERS_DCDC3)) + { + Serial.printf("DC3 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC3) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC3)); + } + if (PMU->isChannelAvailable(XPOWERS_DCDC4)) + { + Serial.printf("DC4 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC4) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC4)); + } + if (PMU->isChannelAvailable(XPOWERS_DCDC5)) + { + Serial.printf("DC5 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_DCDC5) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_DCDC5)); + } + if (PMU->isChannelAvailable(XPOWERS_LDO2)) + { + Serial.printf("LDO2 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_LDO2) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_LDO2)); + } + if (PMU->isChannelAvailable(XPOWERS_LDO3)) + { + Serial.printf("LDO3 : %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_LDO3) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_LDO3)); + } + if (PMU->isChannelAvailable(XPOWERS_ALDO1)) + { + Serial.printf("ALDO1: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_ALDO1) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_ALDO1)); + } + if (PMU->isChannelAvailable(XPOWERS_ALDO2)) + { + Serial.printf("ALDO2: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_ALDO2) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_ALDO2)); + } + if (PMU->isChannelAvailable(XPOWERS_ALDO3)) + { + Serial.printf("ALDO3: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_ALDO3) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_ALDO3)); + } + if (PMU->isChannelAvailable(XPOWERS_ALDO4)) + { + Serial.printf("ALDO4: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_ALDO4) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_ALDO4)); + } + if (PMU->isChannelAvailable(XPOWERS_BLDO1)) + { + Serial.printf("BLDO1: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_BLDO1) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_BLDO1)); + } + if (PMU->isChannelAvailable(XPOWERS_BLDO2)) + { + Serial.printf("BLDO2: %s Voltage: %04u mV \n", + PMU->isPowerChannelEnable(XPOWERS_BLDO2) ? "+" : "-", + PMU->getPowerChannelVoltage(XPOWERS_BLDO2)); + } + Serial.printf("=========================================\n"); + + // Set the time of pressing the button to turn off + PMU->setPowerKeyPressOffTime(XPOWERS_POWEROFF_4S); + uint8_t opt = PMU->getPowerKeyPressOffTime(); + Serial.print("PowerKeyPressOffTime:"); + switch (opt) + { + case XPOWERS_POWEROFF_4S: + Serial.println("4 Second"); + break; + case XPOWERS_POWEROFF_6S: + Serial.println("6 Second"); + break; + case XPOWERS_POWEROFF_8S: + Serial.println("8 Second"); + break; + case XPOWERS_POWEROFF_10S: + Serial.println("10 Second"); + break; + default: + break; + } +#endif + return true; +} + +void disablePeripherals() +{ + +#ifdef HAS_PMU + if (!PMU) + return; +#if defined(T_BEAM_S3_BPF) + PMU->disablePowerOutput(XPOWERS_ALDO4); // gps + PMU->disablePowerOutput(XPOWERS_ALDO2); // Sdcard + PMU->disablePowerOutput(XPOWERS_DCDC3); // Extern Power source + PMU->disablePowerOutput(XPOWERS_DCDC5); + PMU->disablePowerOutput(XPOWERS_ALDO1); +#endif +#endif +} + +void loopPMU() +{ +#ifdef HAS_PMU + if (!PMU) + { + return; + } + if (!pmuInterrupt) + { + return; + } + + pmuInterrupt = false; + // Get PMU Interrupt Status Register + uint32_t status = PMU->getIrqStatus(); + Serial.print("STATUS => HEX:"); + Serial.print(status, HEX); + Serial.print(" BIN:"); + Serial.println(status, BIN); + + if (PMU->isVbusInsertIrq()) + { + Serial.println("isVbusInsert"); + } + if (PMU->isVbusRemoveIrq()) + { + Serial.println("isVbusRemove"); + } + if (PMU->isBatInsertIrq()) + { + Serial.println("isBatInsert"); + } + if (PMU->isBatRemoveIrq()) + { + Serial.println("isBatRemove"); + } + if (PMU->isPekeyShortPressIrq()) + { + Serial.println("isPekeyShortPress"); + } + if (PMU->isPekeyLongPressIrq()) + { + Serial.println("isPekeyLongPress"); + } + if (PMU->isBatChagerDoneIrq()) + { + Serial.println("isBatChagerDone"); + } + if (PMU->isBatChagerStartIrq()) + { + Serial.println("isBatChagerStart"); + } + // Clear PMU Interrupt Status Register + PMU->clearIrqStatus(); +#endif +} + +bool beginDisplay() +{ + Wire.beginTransmission(DISPLAY_ADDR); + if (Wire.endTransmission() == 0) + { + Serial.printf("Find Display model at 0x%X address\n", DISPLAY_ADDR); + u8g2 = new DISPLAY_MODEL(U8G2_R0, U8X8_PIN_NONE); + u8g2->begin(); + u8g2->clearBuffer(); + u8g2->setFont(u8g2_font_inb19_mr); + u8g2->drawStr(0, 30, "LilyGo"); + u8g2->drawHLine(2, 35, 47); + u8g2->drawHLine(3, 36, 47); + u8g2->drawVLine(45, 32, 12); + u8g2->drawVLine(46, 33, 12); + u8g2->setFont(u8g2_font_inb19_mf); + u8g2->drawStr(58, 60, "LoRa"); + u8g2->sendBuffer(); + u8g2->setFont(u8g2_font_fur11_tf); + delay(3000); + return true; + } + + Serial.printf("Warning: Failed to find Display at 0x%0X address\n", DISPLAY_ADDR); + return false; +} + +bool beginSDCard() +{ +#ifdef SDCARD_CS + if (SD.begin(SDCARD_CS, SDCardSPI)) + { + uint32_t cardSize = SD.cardSize() / (1024 * 1024); + Serial.print("Sd Card init succeeded, The current available capacity is "); + Serial.print(cardSize / 1024.0); + Serial.println(" GB"); + return true; + } + else + { + Serial.println("Warning: Failed to init Sd Card"); + } +#endif + return false; +} + +void beginWiFi() +{ + if (!WiFi.softAP(BOARD_VARIANT_NAME)) + { + log_e("Soft AP creation failed."); + } + IPAddress myIP = WiFi.softAPIP(); + Serial.print("AP IP address: "); + Serial.println(myIP); +} + +void printWakeupReason() +{ +#ifdef ESP32 + Serial.print("Reset reason:"); + esp_sleep_wakeup_cause_t wakeup_reason; + wakeup_reason = esp_sleep_get_wakeup_cause(); + switch (wakeup_reason) + { + case ESP_SLEEP_WAKEUP_UNDEFINED: + Serial.println( + " In case of deep sleep, reset was not caused by exit from deep sleep"); + break; + case ESP_SLEEP_WAKEUP_ALL: + break; + case ESP_SLEEP_WAKEUP_EXT0: + Serial.println("Wakeup caused by external signal using RTC_IO"); + break; + case ESP_SLEEP_WAKEUP_EXT1: + Serial.println("Wakeup caused by external signal using RTC_CNTL"); + break; + case ESP_SLEEP_WAKEUP_TIMER: + Serial.println("Wakeup caused by timer"); + break; + case ESP_SLEEP_WAKEUP_TOUCHPAD: + Serial.println("Wakeup caused by touchpad"); + break; + case ESP_SLEEP_WAKEUP_ULP: + Serial.println("Wakeup caused by ULP program"); + break; + default: + Serial.printf("Wakeup was not caused by deep sleep: %d\n", wakeup_reason); + break; + } +#endif +} + +void getChipInfo() +{ +#if defined(ARDUINO_ARCH_ESP32) + + Serial.println("-----------------------------------"); + + printWakeupReason(); + +#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3) + + if (psramFound()) + { + uint32_t psram = ESP.getPsramSize(); + devInfo.psramSize = psram / 1024.0 / 1024.0; + Serial.printf("PSRAM is enable! PSRAM: %.2fMB\n", devInfo.psramSize); + } + else + { + Serial.println("PSRAM is disable!"); + devInfo.psramSize = 0; + } + +#endif + + Serial.print("Flash:"); + devInfo.flashSize = ESP.getFlashChipSize() / 1024.0 / 1024.0; + devInfo.flashSpeed = ESP.getFlashChipSpeed() / 1000 / 1000; + devInfo.chipModel = ESP.getChipModel(); + devInfo.chipModelRev = ESP.getChipRevision(); + devInfo.chipFreq = ESP.getCpuFreqMHz(); + + Serial.print(devInfo.flashSize); + Serial.println(" MB"); + Serial.print("Flash speed:"); + Serial.print(devInfo.flashSpeed); + Serial.println(" M"); + Serial.print("Model:"); + + Serial.println(devInfo.chipModel); + Serial.print("Chip Revision:"); + Serial.println(devInfo.chipModelRev); + Serial.print("Freq:"); + Serial.print(devInfo.chipFreq); + Serial.println(" MHZ"); + Serial.print("SDK Ver:"); + Serial.println(ESP.getSdkVersion()); + Serial.print("DATE:"); + Serial.println(__DATE__); + Serial.print("TIME:"); + Serial.println(__TIME__); + + Serial.print("EFUSE MAC: "); + Serial.print(ESP.getEfuseMac(), HEX); + Serial.println(); + + Serial.println("-----------------------------------"); + +#elif defined(ARDUINO_ARCH_STM32) + uint32_t uid[3]; + + uid[0] = HAL_GetUIDw0(); + uid[1] = HAL_GetUIDw1(); + uid[2] = HAL_GetUIDw2(); + Serial.print("STM UID: 0X"); + Serial.print(uid[0], HEX); + Serial.print(uid[1], HEX); + Serial.print(uid[2], HEX); + Serial.println(); +#endif +} + +void setupBoards(bool disable_u8g2) +{ + Serial.begin(115200); + + // while (!Serial); + + Serial.println("setupBoards"); + + getChipInfo(); + +#if defined(ARDUINO_ARCH_ESP32) + SPI.begin(RADIO_SCLK_PIN, RADIO_MISO_PIN, RADIO_MOSI_PIN); +#elif defined(ARDUINO_ARCH_STM32) + SPI.setMISO(RADIO_MISO_PIN); + SPI.setMOSI(RADIO_MOSI_PIN); + SPI.setSCLK(RADIO_SCLK_PIN); + SPI.begin(); +#endif + +#ifdef HAS_SDCARD + SDCardSPI.begin(SDCARD_SCLK, SDCARD_MISO, SDCARD_MOSI); +#endif + +#ifdef I2C_SDA + Wire.begin(I2C_SDA, I2C_SCL); + scanDevices(&Wire); +#endif + +#ifdef I2C1_SDA + Wire1.begin(I2C1_SDA, I2C1_SCL); +#endif + +#ifdef HAS_GPS +#if defined(ARDUINO_ARCH_ESP32) + SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); +#elif defined(ARDUINO_ARCH_STM32) + SerialGPS.setRx(GPS_RX_PIN); + SerialGPS.setTx(GPS_TX_PIN); + SerialGPS.begin(GPS_BAUD_RATE); +#endif // ARDUINO_ARCH_ +#endif // HAS_GPS + +#if OLED_RST + pinMode(OLED_RST, OUTPUT); + digitalWrite(OLED_RST, HIGH); + delay(20); + digitalWrite(OLED_RST, LOW); + delay(20); + digitalWrite(OLED_RST, HIGH); + delay(20); +#endif + +#ifdef BOARD_LED + /* + * T-Beam LED defaults to low level as turn on, + * so it needs to be forced to pull up + * * * * */ +#if LED_ON == LOW +#if defined(ARDUINO_ARCH_ESP32) + gpio_hold_dis((gpio_num_t)BOARD_LED); +#endif // ARDUINO_ARCH_ESP32 +#endif + + pinMode(BOARD_LED, OUTPUT); + digitalWrite(BOARD_LED, LED_ON); +#endif + +#ifdef GPS_EN_PIN + pinMode(GPS_EN_PIN, OUTPUT); + digitalWrite(GPS_EN_PIN, HIGH); +#endif + +#ifdef GPS_RST_PIN + pinMode(GPS_RST_PIN, OUTPUT); + digitalWrite(GPS_RST_PIN, HIGH); +#endif + +#if defined(ARDUINO_ARCH_STM32) + SerialGPS.println("@GSR"); + delay(300); + SerialGPS.println("@GSR"); + delay(300); + SerialGPS.println("@GSR"); + delay(300); + SerialGPS.println("@GSR"); + delay(300); + SerialGPS.println("@GSR"); + delay(300); +#endif + +#ifdef RADIO_LDO_EN + pinMode(RADIO_LDO_EN, OUTPUT); + digitalWrite(RADIO_LDO_EN, HIGH); +#endif + + beginPower(); + + beginSDCard(); + + if (!disable_u8g2) + { + beginDisplay(); + } + + beginWiFi(); + +#ifdef HAS_GPS +#ifdef T_BEAM_S3_BPF + find_gps = beginGPS(); +#endif +#endif + + Serial.println("init done . "); +} + +void printResult(bool radio_online) +{ + Serial.print("Radio : "); + Serial.println((radio_online) ? "+" : "-"); + +#if defined(CONFIG_IDF_TARGET_ESP32) || defined(CONFIG_IDF_TARGET_ESP32S3) + + Serial.print("PSRAM : "); + Serial.println((psramFound()) ? "+" : "-"); + + Serial.print("Display : "); + Serial.println((u8g2) ? "+" : "-"); + +#ifdef HAS_SDCARD + Serial.print("Sd Card : "); + Serial.println((SD.cardSize() != 0) ? "+" : "-"); +#endif + +#ifdef HAS_PMU + Serial.print("Power : "); + Serial.println((PMU) ? "+" : "-"); +#endif + +#ifdef HAS_GPS +#ifdef T_BEAM_S3_BPF + Serial.print("GPS : "); + Serial.println((find_gps) ? "+" : "-"); +#endif +#endif + + if (u8g2) + { + + u8g2->clearBuffer(); + u8g2->setFont(u8g2_font_NokiaLargeBold_tf); + uint16_t str_w = u8g2->getStrWidth(BOARD_VARIANT_NAME); + u8g2->drawStr((u8g2->getWidth() - str_w) / 2, 16, BOARD_VARIANT_NAME); + u8g2->drawHLine(5, 21, u8g2->getWidth() - 5); + + u8g2->drawStr(0, 38, "Disp:"); + u8g2->drawStr(45, 38, (u8g2) ? "+" : "-"); + +#ifdef HAS_SDCARD + u8g2->drawStr(0, 54, "SD :"); + u8g2->drawStr(45, 54, (SD.cardSize() != 0) ? "+" : "-"); +#endif + + u8g2->drawStr(62, 38, "Radio:"); + u8g2->drawStr(120, 38, (radio_online) ? "+" : "-"); + +#ifdef HAS_PMU + u8g2->drawStr(62, 54, "Power:"); + u8g2->drawStr(120, 54, (PMU) ? "+" : "-"); +#endif + + u8g2->sendBuffer(); + + delay(2000); + } +#endif +} + +static uint8_t ledState = LOW; +static const uint32_t debounceDelay = 50; +static uint32_t lastDebounceTime = 0; + +void flashLed() +{ +#ifdef BOARD_LED + if ((millis() - lastDebounceTime) > debounceDelay) + { + ledState = !ledState; + if (ledState) + { + digitalWrite(BOARD_LED, LED_ON); + } + else + { + digitalWrite(BOARD_LED, !LED_ON); + } + lastDebounceTime = millis(); + } +#endif +} + +void scanDevices(TwoWire *w) +{ + uint8_t err, addr; + int nDevices = 0; + uint32_t start = 0; + + Serial.println("I2C Devices scanning"); + for (addr = 1; addr < 127; addr++) + { + start = millis(); + w->beginTransmission(addr); + delay(2); + err = w->endTransmission(); + if (err == 0) + { + nDevices++; + switch (addr) + { + case 0x77: + case 0x76: + Serial.println("\tFind BMX280 Sensor!"); + break; + case 0x34: + Serial.println("\tFind AXP192/AXP2101 PMU!"); + break; + case 0x3C: + Serial.println("\tFind SSD1306/SH1106 dispaly!"); + break; + case 0x51: + Serial.println("\tFind PCF8563 RTC!"); + break; + case 0x1C: + Serial.println("\tFind QMC6310 MAG Sensor!"); + break; + default: + Serial.print("\tI2C device found at address 0x"); + if (addr < 16) + { + Serial.print("0"); + } + Serial.print(addr, HEX); + Serial.println(" !"); + break; + } + } + else if (err == 4) + { + Serial.print("Unknow error at address 0x"); + if (addr < 16) + { + Serial.print("0"); + } + Serial.println(addr, HEX); + } + } + if (nDevices == 0) + Serial.println("No I2C devices found\n"); + + Serial.println("Scan devices done."); + Serial.println("\n"); +} + +#ifdef HAS_GPS +bool beginGPS() +{ + SerialGPS.begin(GPS_BAUD_RATE, SERIAL_8N1, GPS_RX_PIN, GPS_TX_PIN); + bool result = false; + uint32_t startTimeout; + for (int i = 0; i < 3; ++i) + { + SerialGPS.write("$PCAS03,0,0,0,0,0,0,0,0,0,0,,,0,0*02\r\n"); + delay(5); + // Get version information + startTimeout = millis() + 3000; + Serial.print("Try to init L76K . Wait stop ."); + while (SerialGPS.available()) + { + Serial.print("."); + SerialGPS.readString(); + if (millis() > startTimeout) + { + Serial.println("Wait L76K stop NMEA timeout!"); + return false; + } + }; + Serial.println(); + SerialGPS.flush(); + delay(200); + + SerialGPS.write("$PCAS06,0*1B\r\n"); + startTimeout = millis() + 500; + String ver = ""; + while (!SerialGPS.available()) + { + if (millis() > startTimeout) + { + Serial.println("Get L76K timeout!"); + return false; + } + } + SerialGPS.setTimeout(10); + ver = SerialGPS.readStringUntil('\n'); + if (ver.startsWith("$GPTXT,01,01,02")) + { + Serial.println("L76K GNSS init succeeded, using L76K GNSS Module\n"); + result = true; + break; + } + delay(500); + } + // Initialize the L76K Chip, use GPS + GLONASS + SerialGPS.write("$PCAS04,5*1C\r\n"); + delay(250); + // only ask for RMC and GGA + SerialGPS.write("$PCAS03,1,0,0,0,1,0,0,0,0,0,,,0,0*02\r\n"); + delay(250); + // Switch to Vehicle Mode, since SoftRF enables Aviation < 2g + SerialGPS.write("$PCAS11,3*1E\r\n"); + return result; +} +#endif diff --git a/include/LoRaBoards.h b/include/LoRaBoards.h new file mode 100644 index 0000000..655376e --- /dev/null +++ b/include/LoRaBoards.h @@ -0,0 +1,97 @@ +/** + * @file boards.h + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd + * @date 2024-04-25 + * @last-update 2024-08-07 + */ + +#pragma once + +#include "utilities.h" + +#ifdef HAS_SDCARD +#include +#endif + +#if defined(ARDUINO_ARCH_ESP32) +#include +#include +#endif + +#include +#include +#include +#include +#include + +#ifndef DISPLAY_MODEL +#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C +#endif + +#ifndef OLED_WIRE_PORT +#define OLED_WIRE_PORT Wire +#endif + +#ifndef PMU_WIRE_PORT +#define PMU_WIRE_PORT Wire +#endif + +#ifndef DISPLAY_ADDR +#define DISPLAY_ADDR 0x3C +#endif + +#ifndef LORA_FREQ_CONFIG +#define LORA_FREQ_CONFIG 915.0 +#endif + +typedef struct +{ + String chipModel; + float psramSize; + uint8_t chipModelRev; + uint8_t chipFreq; + uint8_t flashSize; + uint8_t flashSpeed; +} DevInfo_t; + +void setupBoards(bool disable_u8g2 = false); + +bool beginSDCard(); + +bool beginDisplay(); + +void disablePeripherals(); + +bool beginPower(); + +void printResult(bool radio_online); + +void flashLed(); + +void scanDevices(TwoWire *w); + +bool beginGPS(); + +void loopPMU(); + +#ifdef HAS_PMU +extern XPowersLibInterface *PMU; +extern bool pmuInterrupt; +#endif +extern DISPLAY_MODEL *u8g2; + +#define U8G2_HOR_ALIGN_CENTER(t) ((u8g2->getDisplayWidth() - (u8g2->getUTF8Width(t))) / 2) +#define U8G2_HOR_ALIGN_RIGHT(t) (u8g2->getDisplayWidth() - u8g2->getUTF8Width(t)) + +#if defined(ARDUINO_ARCH_ESP32) + +#if defined(HAS_SDCARD) +extern SPIClass SDCardSPI; +#endif + +#define SerialGPS Serial1 +#elif defined(ARDUINO_ARCH_STM32) +extern HardwareSerial SerialGPS; +#endif diff --git a/include/global_config.h b/include/global_config.h index ded70ae..d169fff 100644 --- a/include/global_config.h +++ b/include/global_config.h @@ -22,4 +22,7 @@ #define WATERFALL_ENABLED true #define WATERFALL_START 37 +#ifdef LILYGO +#define LED 46 +#endif // end not LILYGO #endif diff --git a/include/joyStick.h b/include/joyStick.h new file mode 100644 index 0000000..ae10fd8 --- /dev/null +++ b/include/joyStick.h @@ -0,0 +1,63 @@ +// Joystick integration +constexpr int JOY_X_PIN = 19; +int cursor_x_position = 0; +// Not integrated yet constexpr int JOY_Y_PIN = N/A; +constexpr int JOY_BTN_PIN = 46; +bool joy_btn_clicked = false; + +// Joystick integration +bool joy_btn_click() +{ + joy_btn_clicked = true; + // is the output from the pushbutton inside the joystick. It’s normally open. If we + // use a pull-up resistor in this pin, the SW pin will be HIGH + // when it is not pressed, and LOW when Pressed. + return digitalRead(JOY_BTN_PIN) == HIGH ? false : true; +} + +int joyXMid = 0; +int cal_X = 0, cal_Y = 0; + +void calibrate_joy() +{ + for (int i = 0; i < 100; i++) + { + cal_X += analogRead(JOY_X_PIN); + } + // calibrate center + joyXMid = cal_X / 100; +} + +int MID = 100; // 10 mid point delta arduino, use 4 for attiny +int get_joy_x(bool logical = false) +{ + int joyX = analogRead(JOY_X_PIN); + + /* + Serial.print("Calibrated_X_Voltage = "); + Serial.print(joyXMid); + Serial.print("X_Voltage = "); + Serial.print(joyX); + Serial.print("\t"); + */ + + if (logical) + { + // 4095 + if (joyX < joyXMid - MID) + { + return -1; + } + // 0-5 + else if (joyX > joyXMid + MID) + { + return 1; + } + else + { + return 0; + } + } + + return joyX; +} diff --git a/include/utilities.h b/include/utilities.h new file mode 100644 index 0000000..1d1b3ef --- /dev/null +++ b/include/utilities.h @@ -0,0 +1,551 @@ +/** + * @file utilities.h + * @author Lewis He (lewishe@outlook.com) + * @license MIT + * @copyright Copyright (c) 2024 ShenZhen XinYuan Electronic Technology Co., Ltd + * @date 2024-05-12 + * @last-update 2024-08-07 + */ +#pragma once + +// Support board list , Macro definition below, select the board definition to be used + +// #define T3_V1_3_SX1276 +// #define T3_V1_3_SX1278 + +// #define T3_V1_6_SX1276 +// #define T3_V1_6_SX1278 + +// #define T3_V1_6_SX1276_TCXO +// #define T3_V3_0_SX1276_TCXO + +// #define T_BEAM_SX1262 +// #define T_BEAM_SX1276 +// #define T_BEAM_SX1278 + +// #define T_BEAM_S3_SUPREME + +// #define T3_S3_V1_2_SX1262 +// #define T3_S3_V1_2_SX1276 +// #define T3_S3_V1_2_SX1278 +// #define T3_S3_V1_2_SX1280 +// #define T3_S3_V1_2_SX1280_PA +// #define T3_S3_V1_2_LR1121 + +// #define T_MOTION + +// #define T3_C6 + +// #define T_BEAM_S3_BPF + +#define UNUSED_PIN (0) + +#if defined(T_BEAM_SX1262) || defined(T_BEAM_SX1276) || defined(T_BEAM_SX1278) + +#if defined(T_BEAM_SX1262) +#ifndef USING_SX1262 +#define USING_SX1262 +#endif +#elif defined(T_BEAM_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T_BEAM_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#endif // T_BEAM_SX1262 + +#define GPS_RX_PIN 34 +#define GPS_TX_PIN 12 +#define BUTTON_PIN 38 +#define BUTTON_PIN_MASK GPIO_SEL_38 +#define I2C_SDA 21 +#define I2C_SCL 22 +#define PMU_IRQ 35 + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN 33 +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + +#define BOARD_LED 4 +#define LED_ON LOW +#define LED_OFF HIGH + +#define GPS_BAUD_RATE 9600 +#define HAS_GPS +#define HAS_DISPLAY // Optional, bring your own board, no OLED !! +#define HAS_PMU + +#define BOARD_VARIANT_NAME "T-Beam" + +#elif defined(T3_V1_3_SX1276) || defined(T3_V1_3_SX1278) + +#if defined(T3_V1_3_SX1276) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + +#elif defined(T3_V1_3_SX1278) + +#ifndef USING_SX1278 +#define USING_SX1278 +#endif + +#endif // T3_V1_3_SX1276 + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 14 +#define RADIO_DIO1_PIN 33 + +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + +#define ADC_PIN 35 +#define HAS_DISPLAY +#define BOARD_VARIANT_NAME "T3 V1.3" + +#elif defined(T3_V1_6_SX1276) || defined(T3_V1_6_SX1278) + +#if defined(T3_V1_6_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T3_V1_6_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#endif // T3_V1_6_SX1276 + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN 33 +// SX1276/78 +#define RADIO_DIO2_PIN 32 +// SX1262 +#define RADIO_BUSY_PIN 32 + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V1.6" + +#elif defined(T3_V1_6_SX1276_TCXO) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_DIO0_PIN 26 +#define RADIO_RST_PIN 23 +#define RADIO_DIO1_PIN -1 // 33 +/* + * In the T3 V1.6.1 TCXO version, Radio DIO1 is connected to Radio’s + * internal temperature-compensated crystal oscillator enable + * */ +// TCXO pin must be set to HIGH before enabling Radio +#define RADIO_TCXO_ENABLE 33 +#define RADIO_BUSY_PIN 32 + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V1.6 TCXO" + +#elif defined(T3_V3_0) + +#define I2C_SDA 21 +#define I2C_SCL 22 +#define OLED_RST 4 + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 19 +#define RADIO_MOSI_PIN 27 +#define RADIO_CS_PIN 18 +#define RADIO_RST_PIN 23 + +// TCXO pin must be set to HIGH before enabling Radio +#define RADIO_TCXO_ENABLE 12 // only sx1276 tcxo version +#define RADIO_BUSY_PIN 32 + +#if defined(USING_SX1262) + +#define RADIO_DIO1_PIN 26 +#define RADIO_BUSY_PIN 32 + +#elif defined(USING_SX1276) || defined(USING_SX1278) +//! SX1276/78 module only + +#define RADIO_DIO0_PIN 26 +#define RADIO_DIO1_PIN 32 + +#elif defined(USING_LR1121) + +#define RADIO_DIO9_PIN 26 // LR1121 DIO9 +#define RADIO_BUSY_PIN 32 // LR1121 BUSY + +#endif + +#define SDCARD_MOSI 15 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 25 +#define LED_ON HIGH + +#define ADC_PIN 35 + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 V3.0" + +#define BUTTON_PIN 0 +#define BAT_ADC_PIN 35 + +#elif defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) || \ + defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) || \ + defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) || \ + defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) || \ + defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) || \ + defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) + +#if defined(T3_S3_V1_2_SX1262) || defined(ARDUINO_LILYGO_T3S3_SX1262) +#ifndef USING_SX1262 +#define USING_SX1262 +#endif +#elif defined(T3_S3_V1_2_SX1276) || defined(ARDUINO_LILYGO_T3S3_SX1276) +#ifndef USING_SX1276 +#define USING_SX1276 +#endif +#elif defined(T3_S3_V1_2_SX1278) || defined(ARDUINO_LILYGO_T3S3_SX1278) +#ifndef USING_SX1278 +#define USING_SX1278 +#endif +#elif defined(T3_S3_V1_2_SX1280) || defined(ARDUINO_LILYGO_T3S3_SX1280) +#ifndef USING_SX1280 +#define USING_SX1280 +#endif +#elif defined(T3_S3_V1_2_SX1280_PA) || defined(ARDUINO_LILYGO_T3S3_SX1280PA) +#ifndef USING_SX1280PA +#define USING_SX1280PA +#endif +#elif defined(T3_S3_V1_2_LR1121) || defined(ARDUINO_LILYGO_T3S3_LR1121) +#ifndef USING_LR1121 +#define USING_LR1121 +#endif + +#endif // T3_S3_V1_2_SX1262 + +#define I2C_SDA 18 +#define I2C_SCL 17 +#define OLED_RST UNUSED_PIN + +#define RADIO_SCLK_PIN 5 +#define RADIO_MISO_PIN 3 +#define RADIO_MOSI_PIN 6 +#define RADIO_CS_PIN 7 + +#define SDCARD_MOSI 11 +#define SDCARD_MISO 2 +#define SDCARD_SCLK 14 +#define SDCARD_CS 13 + +#define BOARD_LED 37 +#define LED_ON HIGH + +#define BUTTON_PIN 0 +#define ADC_PIN 1 + +#define RADIO_RST_PIN 8 + +#if defined(USING_SX1262) + +#define RADIO_DIO1_PIN 33 +#define RADIO_BUSY_PIN 34 + +#elif defined(USING_SX1276) || defined(USING_SX1278) +//! SX1276/78 module only +#define RADIO_BUSY_PIN 33 // DIO1 + +#define RADIO_DIO0_PIN 9 +#define RADIO_DIO1_PIN 33 +#define RADIO_DIO2_PIN 34 +#define RADIO_DIO3_PIN 21 +#define RADIO_DIO4_PIN 10 +#define RADIO_DIO5_PIN 36 + +#elif defined(USING_SX1280) + +#define RADIO_DIO1_PIN 9 // SX1280 DIO1 = IO9 +#define RADIO_BUSY_PIN 36 // SX1280 BUSY = IO36 + +#elif defined(USING_SX1280PA) + +#define RADIO_DIO1_PIN 9 // SX1280 DIO1 = IO9 +#define RADIO_BUSY_PIN 36 // SX1280 BUSY = IO36 +#define RADIO_RX_PIN 21 +#define RADIO_TX_PIN 10 + +#elif defined(USING_LR1121) + +#define RADIO_DIO9_PIN 36 // LR1121 DIO9 = IO36 +#define RADIO_BUSY_PIN 34 // LR1121 BUSY = IO34 + +#endif + +#define HAS_SDCARD +#define HAS_DISPLAY + +#define BOARD_VARIANT_NAME "T3 S3 V1.X" + +#elif defined(T_BEAM_S3_SUPREME) + +#ifndef USING_SX1262 +#define USING_SX1262 +#endif + +#define I2C_SDA 17 +#define I2C_SCL 18 + +#define I2C1_SDA 42 +#define I2C1_SCL 41 +#define PMU_IRQ 40 + +#define GPS_RX_PIN 9 +#define GPS_TX_PIN 8 +#define GPS_WAKEUP_PIN 7 +#define GPS_PPS_PIN 6 + +#define BUTTON_PIN 0 +#define BUTTON_PIN_MASK GPIO_SEL_0 +#define BUTTON_CONUT (1) +#define BUTTON_ARRAY {BUTTON_PIN} + +#define RADIO_SCLK_PIN (12) +#define RADIO_MISO_PIN (13) +#define RADIO_MOSI_PIN (11) +#define RADIO_CS_PIN (10) +#define RADIO_DIO0_PIN (-1) +#define RADIO_RST_PIN (5) +#define RADIO_DIO1_PIN (1) +#define RADIO_BUSY_PIN (4) + +#define SPI_MOSI (35) +#define SPI_SCK (36) +#define SPI_MISO (37) +#define SPI_CS (47) +#define IMU_CS (34) +#define IMU_INT (33) + +#define SDCARD_MOSI SPI_MOSI +#define SDCARD_MISO SPI_MISO +#define SDCARD_SCLK SPI_SCK +#define SDCARD_CS SPI_CS + +#define PIN_NONE (-1) +#define RTC_INT (14) + +#define GPS_BAUD_RATE 9600 + +#define HAS_SDCARD +#define HAS_GPS +#define HAS_DISPLAY +#define HAS_PMU + +#define __HAS_SPI1__ +#define __HAS_SENSOR__ + +#define PMU_WIRE_PORT Wire1 +#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C +#define BOARD_VARIANT_NAME "T-Beam S3" + +#elif defined(T_MOTION_S76G) + +#ifndef USING_SX1276 +#define USING_SX1276 +#endif + +#define RADIO_SCLK_PIN PB13 +#define RADIO_MISO_PIN PB14 +#define RADIO_MOSI_PIN PB15 +#define RADIO_CS_PIN PB12 +#define RADIO_RST_PIN PB10 + +#define RADIO_DIO0_PIN PB11 +#define RADIO_DIO1_PIN PC13 +#define RADIO_DIO2_PIN PB9 +#define RADIO_DIO3_PIN PB4 +#define RADIO_DIO4_PIN PB3 +#define RADIO_DIO5_PIN PA15 + +#undef RADIO_BUSY_PIN +#undef RADIO_DIO1_PIN +#define RADIO_BUSY_PIN PC13 // DIO1 +#define RADIO_DIO1_PIN PB11 // DIO0 + +#define RADIO_SWITCH_PIN PA1 // 1:Rx, 0:Tx + +#define GPS_EN_PIN PC6 +#define GPS_RST_PIN PB2 +#define GPS_RX_PIN PC11 +#define GPS_TX_PIN PC10 +#define GPS_ENABLE_PIN PC6 +#define GPS_BAUD_RATE 115200 +#define GPS_PPS_PIN PB5 + +#define UART_RX_PIN PA10 +#define UART_TX_PIN PA9 + +#define I2C_SCL PB6 +#define I2C_SDA PB7 + +#define BOARD_VARIANT_NAME "T-Motion S76G" + +#define HAS_GPS + +#elif defined(T3_C6) + +#ifndef USING_SX1262 +#define USING_SX1262 +#endif + +#define RADIO_SCLK_PIN 6 +#define RADIO_MISO_PIN 1 +#define RADIO_MOSI_PIN 0 +#define RADIO_CS_PIN 18 +#define RADIO_DIO1_PIN 23 +#define RADIO_BUSY_PIN 22 +#define RADIO_RST_PIN 21 + +#define I2C_SDA 8 +#define I2C_SCL 9 + +#define BOARD_LED 7 +#define LED_ON HIGH +#define RADIO_RX_PIN 15 +#define RADIO_TX_PIN 14 + +#define BOARD_VARIANT_NAME "T3-C6" + +#define USING_DIO2_AS_RF_SWITCH + +#elif defined(T_BEAM_S3_BPF) + +#ifndef USING_SX1278 +#define USING_SX1278 +#endif + +#define I2C_SDA 8 +#define I2C_SCL 9 + +#define PMU_IRQ 4 + +#define GPS_RX_PIN 5 +#define GPS_TX_PIN 6 +#define GPS_PPS_PIN 7 + +#define BUTTON_PIN 0 +#define BUTTON_PIN_MASK GPIO_SEL_0 +#define BUTTON_CONUT (2) +#define BUTTON_ARRAY {BUTTON_PIN, 3} + +#define RADIO_SCLK_PIN (41) +#define RADIO_MISO_PIN (42) +#define RADIO_MOSI_PIN (2) +#define RADIO_CS_PIN (1) +#define RADIO_RST_PIN (18) + +#define RADIO_DIO0_PIN (14) +#define RADIO_DIO1_PIN (21) +#define RADIO_DIO2_PIN (15) + +#define RADIO_TCXO_ENABLE (17) +#define RADIO_LDO_EN (16) +#define RADIO_BUSY_PIN (RADIO_DIO1_PIN) + +#define SPI_MOSI (11) +#define SPI_SCK (12) +#define SPI_MISO (13) +#define SPI_CS (10) + +#define SDCARD_MOSI SPI_MOSI +#define SDCARD_MISO SPI_MISO +#define SDCARD_SCLK SPI_SCK +#define SDCARD_CS SPI_CS + +#define PIN_NONE (-1) + +#define GPS_BAUD_RATE 9600 + +#define HAS_SDCARD +#define HAS_GPS +#define HAS_DISPLAY +#define HAS_PMU + +#define __HAS_SPI1__ +#define __HAS_SENSOR__ + +#define PMU_WIRE_PORT Wire +#define DISPLAY_MODEL U8G2_SH1106_128X64_NONAME_F_HW_I2C +#define BOARD_VARIANT_NAME "T-Beam BPF" + +#else +#error "When using it for the first time, please define the board model in " +#endif diff --git a/platformio.ini b/platformio.ini index e7d2dec..e89e8e3 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,13 +18,36 @@ platform = espressif32 board = heltec_wifi_lora_32_V3 framework = arduino -upload_speed = 115200 +upload_speed = 921600 monitor_speed = 115200 board_build.f_cpu = 240000000 lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 build_flags = -DHELTEC_POWER_BUTTON +[env:lilygo-T3S3-v1-2] +platform = espressif32 +board = t3_s3_v1_x ;platformio doesn't have right boatd check local boards bolder +framework = arduino +upload_speed = 921600 +monitor_speed = 115200 +board_build.f_cpu = 240000000 +lib_deps = + ropg/Heltec_ESP32_LoRa_v3@^0.9.1 + RadioLib +build_flags = + -DLILYGO ; flag for our code + -DT3_S3_V1_2_SX1262 + -DT3_V1_3_SX1262 + -DARDUINO_LILYGO_T3S3_SX1262 + -DESP32 + -DUSING_SX1262 + -DARDUINO_ARCH_ESP32 + -DARDUINO_USB_CDC_ON_BOOT=1 + -DARDUINO_LILYGO_T3_S3_V1_X + -DARDUINO_USB_MODE=1 + ;-UARDUINO_USB_CDC_ON_BOOT + [env:heltec_wifi_lora_32_V3-test-signal-generator] platform = espressif32 board = heltec_wifi_lora_32_V3 @@ -32,9 +55,10 @@ framework = arduino upload_speed = 115200 monitor_speed = 115200 board_build.f_cpu = 240000000 +board_build.flash_size = 80000000L lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 -build_flags = -DHELTEC_POWER_BUTTON +build_flags = -DLILYGO [env:vision-master-e290] platform = espressif32 diff --git a/src/main.cpp b/src/main.cpp index d6f50e8..349d856 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -24,12 +24,26 @@ // #define HELTEC_NO_DISPLAY #include + +// #define OSD_ENABLED true +// #define WIFI_SCANNING_ENABLED true +// #define BT_SCANNING_ENABLED true + +#ifndef LILYGO #include // This file contains a binary patch for the SX1262 #include "modules/SX126x/patches/SX126x_patch_scan.h" -// #define OSD_ENABLED true -// #define WIFI_SCANNING_ENABLED true -// #define BT_SCANNING_ENABLED true +#elif defined(LILYGO) +// LiLyGO device does not support the auto download mode, you need to get into the +// download mode manually. To do so, press and hold the BOOT button and then press the +// RESET button once. After that release the BOOT button. Or OFF->ON together with BOOT + +// Default LilyGO code +#include "utilities.h" +// Our Code +#include "LiLyGo.h" + +#endif // end LILYGO #define BT_SCAN_DELAY 60 * 1 * 1000 #define WF_SCAN_DELAY 60 * 2 * 1000 @@ -114,7 +128,7 @@ static constexpr uint16_t power_level[MAX_POWER_LEVELS + 1] = { #define OSD_X_START 1 #define OSD_Y_START 16 -// TODO: Calculate dinammicaly: +// TODO: Calculate dynamically: // osd_steps = osd_mhz_in_bin / (FM range / LORA radio x Steps) int osd_mhz_in_bin = 5; int osd_steps = 12; @@ -154,15 +168,19 @@ typedef enum } TSCAN_METOD_ENUM; #define SCAN_METHOD -#define METHOD_SPECTRAL -// #define METHOD_RSSI // Uncomment this and comment METHOD_SPECTRAL fot RSSI +// #define METHOD_SPECTRAL // Spectral scan method +#define METHOD_RSSI // Uncomment this and comment METHOD_SPECTRAL fot RSSI -// Feature to scan diapazones. Other frequency settings will be ignored. +// Output Pixel Formula +// 1 = rssi / 4, 2 = (rssi / 2) - 22 or 20 +constexpr int RSSI_OUTPUT_FORMULA = 2; + +// Feature to scan diapasones. Other frequency settings will be ignored. // int SCAN_RANGES[] = {850890, 920950}; int SCAN_RANGES[] = {}; // MHZ per page -// to put everething into one page set RANGE_PER_PAGE = FREQ_END - 800 +// to put everything into one page set RANGE_PER_PAGE = FREQ_END - 800 uint64_t RANGE_PER_PAGE = FREQ_END - FREQ_BEGIN; // FREQ_END - FREQ_BEGIN // multiplies STEPS * N to increase scan resolution. @@ -189,7 +207,7 @@ bool ANIMATED_RELOAD = false; constexpr bool DRAW_DETECTION_TICKS = true; // Number of samples for each frequency scan. Fewer samples = better temporal resolution. -// if more than 100 it can freez +// if more than 100 it can freeze #define SAMPLES 35 //(scan time = 1294) // number of samples for RSSI method #define SAMPLES_RSSI 20 // 21 // @@ -263,69 +281,11 @@ uint8_t result_index = 0; uint8_t button_pressed_counter = 0; uint64_t loop_cnt = 0; -// Joystick integration -constexpr int JOY_X_PIN = 19; -int cursor_x_position = 0; -// Not integrated yet constexpr int JOY_Y_PIN = N/A; -constexpr int JOY_BTN_PIN = 46; -bool joy_btn_clicked = false; -#define JOYSTICK_ENABLED +#ifndef LILYGO +// #define JOYSTICK_ENABLED +#endif -bool joy_btn_click() -{ - joy_btn_clicked = true; - // is the output from the pushbutton inside the joystick. It’s normally open. If we - // use a pull-up resistor in this pin, the SW pin will be HIGH - // when it is not pressed, and LOW when Pressed. - return digitalRead(JOY_BTN_PIN) == HIGH ? false : true; -} - -int joyXMid = 0; -int cal_X = 0, cal_Y = 0; - -void calibrate_joy() -{ - for (int i = 0; i < 100; i++) - { - cal_X += analogRead(JOY_X_PIN); - } - // calibrate center - joyXMid = cal_X / 100; -} - -int MID = 100; // 10 mid point delta arduino, use 4 for attiny -int get_joy_x(bool logical = false) -{ - int joyX = analogRead(JOY_X_PIN); - - /* - Serial.print("Calibrated_X_Voltage = "); - Serial.print(joyXMid); - Serial.print("X_Voltage = "); - Serial.print(joyX); - Serial.print("\t"); - */ - - if (logical) - { - // 4095 - if (joyX < joyXMid - MID) - { - return -1; - } - // 0-5 - else if (joyX > joyXMid + MID) - { - return 1; - } - else - { - return 0; - } - } - - return joyX; -} +#include "joyStick.h" #ifdef WIFI_SCANNING_ENABLED // WiFi Scan @@ -539,7 +499,21 @@ void init_radio() { // initialize SX1262 FSK modem at the initial frequency both.println("Init radio"); - RADIOLIB_OR_HALT(radio.beginFSK(FREQ_BEGIN)); + state == radio.beginFSK(FREQ_BEGIN); + + if (state == RADIOLIB_ERR_NONE) + { + Serial.println(F("success!")); + } + else + { + Serial.print(F("failed, code ")); + Serial.println(state); + while (true) + { + delay(5); + } + } // upload a patch to the SX1262 to enable spectral scan // NOTE: this patch is uploaded into volatile memory, @@ -613,9 +587,10 @@ void setup(void) } init_radio(); - +#ifndef LILYGO vbat = heltec_vbat(); both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); +#endif // end not LILYGO #ifdef WIFI_SCANNING_ENABLED WiFi.mode(WIFI_STA); WiFi.disconnect(); @@ -642,7 +617,7 @@ void setup(void) { both.println("Single Page Screen MODE"); both.println("Multi Screen View Press P - button"); - both.println("Multi Screan Res: " + String(resolution) + "Mhz/tick"); + both.println("Multi Screen Res: " + String(resolution) + "Mhz/tick"); both.println( "Resolution: " + String((float)RANGE_PER_PAGE / (STEPS * SCAN_RBW_FACTOR)) + "MHz/tick"); @@ -693,6 +668,9 @@ void setup(void) if (state != RADIOLIB_ERR_NONE) { Serial.print(F("Failed to start receive mode, error code: ")); + display.drawString(0, 64 - 10, "E:startReceive"); + display.display(); + delay(500); Serial.println(state); } #endif @@ -703,51 +681,83 @@ void setup(void) #endif } -// Formula to translate 33 bin to aproximate RSSI value +// Formula to translate 33 bin to approximate RSSI value int binToRSSI(int bin) { // the first the strongest RSSI in bin value is 0 return 11 + (bin * 4); } +void drone_sound_alarm(int drone_detection_level, int detection_count) +{ + // If level is set to sensitive, + // start beeping every 10th frequency and shorter + // it improves performance less short beep delays... + if (drone_detection_level <= 25) + { + if (detection_count == 1 && SOUND_ON) + { + tone(BUZZER_PIN, 205, + 10); // same action ??? but first time + } + if (detection_count % 5 == 0 && SOUND_ON) + { + tone(BUZZER_PIN, 205, + 10); // same action ??? but every 5th time + } + } + else + { + if (detection_count % 20 == 0 && SOUND_ON) + { + tone(BUZZER_PIN, 205, + 10); // same action ??? but every 20th detection + } + } +} + // MAX Frequency RSSI value of the samples int max_rssi_x = 999; + void loop(void) { - UI_displayDecorate(0, 0, false); // some default values - detection_count = 0; - drone_detected_frequency_start = 0; - ranges_count = 0; - // reset scan time - scan_time = 0; + { + UI_displayDecorate(0, 0, false); // some default values - // general purpose loop conter - loop_cnt++; + detection_count = 0; + drone_detected_frequency_start = 0; + ranges_count = 0; + + // reset scan time + scan_time = 0; + + // general purpose loop counter + loop_cnt++; #ifdef PRINT_PROFILE_TIME - loop_start = millis(); + loop_start = millis(); #endif - if (!ANIMATED_RELOAD || !single_page_scan) - { - // clear the scan plot rectangle - UI_clearPlotter(); - } + if (!ANIMATED_RELOAD || !single_page_scan) + { + // clear the scan plot rectangle + UI_clearPlotter(); + } - // do the scan - range = FREQ_END - FREQ_BEGIN; - if (RANGE_PER_PAGE > range) - { - RANGE_PER_PAGE = range; - } + // do the scan + range = FREQ_END - FREQ_BEGIN; + if (RANGE_PER_PAGE > range) + { + RANGE_PER_PAGE = range; + } - fr_begin = FREQ_BEGIN; - fr_end = fr_begin; + fr_begin = FREQ_BEGIN; + fr_end = fr_begin; - // 50 is a single-screen range - // TODO: Make 50 a variable with the option to show the full range - iterations = range / RANGE_PER_PAGE; + // 50 is a single-screen range + // TODO: Make 50 a variable with the option to show the full range + iterations = range / RANGE_PER_PAGE; #if 0 // disabled code if (range % RANGE_PER_PAGE != 0) @@ -757,529 +767,563 @@ void loop(void) } #endif - if (RANGE_PER_PAGE == range) - { - single_page_scan = true; - } - else - { - single_page_scan = false; - } - - for (int range : SCAN_RANGES) - { - ranges_count++; - } - - if (ranges_count > 0) - { - iterations = ranges_count; - single_page_scan = false; - } - - // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz - for (range_item = 0; range_item < iterations; range_item++) - { - range = RANGE_PER_PAGE; - if (ranges_count == 0) + if (RANGE_PER_PAGE == range) { - fr_begin = (range_item == 0) ? fr_begin : fr_begin += range; - fr_end = fr_begin + RANGE_PER_PAGE; + single_page_scan = true; } else { - fr_begin = SCAN_RANGES[range_item] / 1000; - fr_end = SCAN_RANGES[range_item] % 1000; - range = fr_end - fr_begin; + single_page_scan = false; } + for (int range : SCAN_RANGES) + { + ranges_count++; + } + + if (ranges_count > 0) + { + iterations = ranges_count; + single_page_scan = false; + } + + // Iterating by small ranges by 50 Mhz each pixel is 0.4 Mhz + for (range_item = 0; range_item < iterations; range_item++) + { + range = RANGE_PER_PAGE; + if (ranges_count == 0) + { + fr_begin = (range_item == 0) ? fr_begin : fr_begin += range; + fr_end = fr_begin + RANGE_PER_PAGE; + } + else + { + fr_begin = SCAN_RANGES[range_item] / 1000; + fr_end = SCAN_RANGES[range_item] % 1000; + range = fr_end - fr_begin; + } + #ifdef DISABLED_CODE - if (!ANIMATED_RELOAD || !single_page_scan) - { - // clear the scan plot rectangle - UI_clearPlotter(); - } + if (!ANIMATED_RELOAD || !single_page_scan) + { + // clear the scan plot rectangle + UI_clearPlotter(); + } #endif - if (single_page_scan == false) - { - UI_displayDecorate(fr_begin, fr_end, true); - } - - drone_detected_frequency_start = 0; - display.setTextAlignment(TEXT_ALIGN_RIGHT); - - for (int i = 0; i < MAX_POWER_LEVELS; i++) - { - max_bins_array_value[i] = 0; - } - - // horizontal (x axis) Frequency loop - osd_x = 1, osd_y = 2, col = 0, max_bin = 0; - // x loop - for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) - { - - if (x % SCAN_RBW_FACTOR == 0) - new_pixel = true; - else - new_pixel = false; - if (ANIMATED_RELOAD && SCAN_RBW_FACTOR == 1) + if (single_page_scan == false) { - UI_drawCursor(x); + UI_displayDecorate(fr_begin, fr_end, true); } - if (new_pixel && ANIMATED_RELOAD && SCAN_RBW_FACTOR > 1) + + drone_detected_frequency_start = 0; + display.setTextAlignment(TEXT_ALIGN_RIGHT); + + for (int i = 0; i < MAX_POWER_LEVELS; i++) { - UI_drawCursor((int)(x / SCAN_RBW_FACTOR)); + max_bins_array_value[i] = 0; } + // horizontal (x axis) Frequency loop + osd_x = 1, osd_y = 2, col = 0, max_bin = 0; + // x loop + for (x = 0; x < STEPS * SCAN_RBW_FACTOR; x++) + { + start: + + if (x % SCAN_RBW_FACTOR == 0) + new_pixel = true; + else + new_pixel = false; + if (ANIMATED_RELOAD && SCAN_RBW_FACTOR == 1) + { + UI_drawCursor(x); + } + if (new_pixel && ANIMATED_RELOAD && SCAN_RBW_FACTOR > 1) + { + UI_drawCursor((int)(x / SCAN_RBW_FACTOR)); + } + #ifdef PRINT_PROFILE_TIME - scan_start_time = millis(); + scan_start_time = millis(); #endif - // Real display pixel x - axis. - // Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore - // x > STEPS on SCAN_RBW_FACTOR - int display_x = x / SCAN_RBW_FACTOR; - waterfall[display_x] = false; - float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); + // Real display pixel x - axis. + // Because of the SCAN_RBW_FACTOR x is not a display coordinate anymore + // x > STEPS on SCAN_RBW_FACTOR + int display_x = x / SCAN_RBW_FACTOR; + waterfall[display_x] = false; + float step = (range * ((float)x / (STEPS * SCAN_RBW_FACTOR))); - freq = fr_begin + step; + freq = fr_begin + step; +#ifdef PRINT_DEBUG + Serial.println("setFrequency:" + String(freq)); +#endif - radio.setFrequency(freq, false); // false = no calibration need here +#ifdef LILYGO + state = + radio.setFrequency(freq, false); // false = no calibration need here +#else + state = + radio.setFrequency(freq, false); // false = no calibration need here +#endif + int radio_error_count = 0; + if (state != RADIOLIB_ERR_NONE) + { + display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); + // display.drawString(0, 64 - 10, "E:setFrequency:" + String(freq)); + Serial.println("E:setFrequency:" + String(freq)); + display.display(); + delay(2); + radio_error_count++; + if (radio_error_count > 10) + continue; + } #ifdef PRINT_DEBUG - Serial.printf("Step:%d Freq: %f\n", x, freq); + Serial.printf("Step:%d Freq: %f\n", x, freq); #endif - // SpectralScan Method + // SpectralScan Method #ifdef METHOD_SPECTRAL - { - // start spectral scan third parameter is a sleep interval - radio.spectralScanStart(SAMPLES, 1); - // wait for spectral scan to finish - while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) { - Serial.print("radio.spectralScanGetStatus ERROR: "); - Serial.println(radio.spectralScanGetStatus()); - heltec_delay(ONE_MILLISEC * 10); + // start spectral scan third parameter is a sleep interval + radio.spectralScanStart(SAMPLES, 1); + // wait for spectral scan to finish + radio_error_count = 0; + while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) + { + Serial.println("radio.spectralScanGetStatus ERROR: "); + Serial.println(radio.spectralScanGetStatus()); + display.drawString(0, 64 - 20, + "E:specScSta:" + + String(radio.spectralScanGetStatus())); + display.display(); + heltec_delay(ONE_MILLISEC * 2); + radio_error_count++; + if (radio_error_count > 10) + continue; + } + + // read the results Array to which the results will be saved + state = radio.spectralScanGetResult(result); + display.drawString(0, 64 - 10, "scanGetResult:" + String(state)); } - // read the results Array to which the results will be saved - radio.spectralScanGetResult(result); - } + #endif #ifdef METHOD_RSSI - // Spectrum analyzer using getRSSI - { + // Spectrum analyzer using getRSSI + { #ifdef PRINT_DEBUG - Serial.println("METHOD RSSI"); + Serial.println("METHOD RSSI"); #endif - // memset - // memset(result, 0, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); - // Some issues with memset function - for (i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) - { - result[i] = 0; - } - result_index = 0; - // N of samples - for (int r = 0; r < SAMPLES_RSSI; r++) - { - rssi = radio.getRSSI(false); - // delay(ONE_MILLISEC); - // ToDO: check if 4 is correct value for 33 power bins - result_index = uint8_t(abs(rssi) / 4); /// still not clear formula + // memset + // memset(result, 0, RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE); + // Some issues with memset function + for (i = 0; i < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; i++) + { + result[i] = 0; + } + result_index = 0; + // N of samples + for (int r = 0; r < SAMPLES_RSSI; r++) + { + rssi = radio.getRSSI(false); + // ToDO: check if 4 is correct value for 33 power bins + // Now we have more space because we are ignoring low dB values + // we can / 3 default 4 + if (RSSI_OUTPUT_FORMULA == 1) + { + result_index = + /// still not clear formula but it works + uint8_t(abs(rssi) / 4); + } + else if (RSSI_OUTPUT_FORMULA == 2) + { + // I like this formula better + result_index = uint8_t(abs(rssi) / 2) - 22; + } #ifdef PRINT_DEBUG - Serial.printf("RSSI: %d IDX: %d\n", rssi, result_index); + Serial.printf("RSSI: %d IDX: %d\n", rssi, result_index); #endif - // avoid buffer overflow - if (result_index < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) - { - // Saving max value only rss is negative so smaller is bigger - if (result[result_index] > rssi) + // avoid buffer overflow + if (result_index < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE) { - result[result_index] = rssi; + // Saving max value only rss is negative so smaller is bigger + if (result[result_index] > rssi) + { + result[result_index] = rssi; + } } + else + { + Serial.print("Out-of-Range: result_index %d\n"); + } + } + } +#endif // SCAN_METHOD == METHOD_RSSI + + // if this code is not executed LORA radio doesn't work + // basically SX1262 requires delay + // osd.displayString(12, 1, String(FREQ_BEGIN)); + // osd.displayString(12, 30 - 8, String(FREQ_END)); + // delay(2); + +#ifdef OSD_ENABLED + osdProcess(); +#endif +#ifdef JOYSTICK_ENABLED + if (display_x == cursor_x_position) + { + display.setColor(BLACK); + display.fillRect(display_x - 20, 3, 36, 11); + display.setColor(WHITE); + } +#endif + detected = false; + detected_y[display_x] = false; + max_rssi_x = 999; + + for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) + { + +#ifdef PRINT_DEBUG + Serial.print(String(y) + ":"); + Serial.print(String(result[y]) + ","); +#endif +#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false + if (result[y] && result[y] != 0) + { + filtered_result[y] = 1; } else { - Serial.print("Out-of-Range: result_index %d\n"); + filtered_result[y] = 0; } - } - } -#endif // SCAN_METHOD == METHOD_RSSI - - // if this code is not executed LORA radio doesn't work - // basically SX1262 requires delay - // osd.displayString(12, 1, String(FREQ_BEGIN)); - // osd.displayString(12, 30 - 8, String(FREQ_END)); - // delay(2); - -#ifdef OSD_ENABLED - osdProcess(); -#endif -#ifdef JOYSTICK_ENABLED - if (display_x == cursor_x_position) - { - display.setColor(BLACK); - display.fillRect(display_x - 20, 3, 36, 11); - display.setColor(WHITE); - } -#endif - detected = false; - detected_y[display_x] = false; - max_rssi_x = 999; - for (y = 0; y < RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE; y++) - { - -#ifdef PRINT_DEBUG - Serial.print(String(y) + ":"); - Serial.print(String(result[y]) + ","); -#endif - -#if !defined(FILTER_SPECTRUM_RESULTS) || FILTER_SPECTRUM_RESULTS == false - if (result[y] && result[y] != 0) - { - filtered_result[y] = 1; - } - else - { - filtered_result[y] = 0; - } #endif // if samples low ~1 filter removes all values #if FILTER_SPECTRUM_RESULTS - filtered_result[y] = 0; - // Filter Elements without neighbors - // if RSSI method actual value is -xxx dB - if (result[y] > 0 && samples > 1) - { - // do not process 'first' and 'last' row to avoid out of index - // access. - if ((y > 0) && (y != (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 3))) + + filtered_result[y] = 0; + // Filter Elements without neighbors + // if RSSI method actual value is -xxx dB + if (result[y] > 0 && samples > 1) { - if (((result[y + 1] != 0) && (result[y + 2] != 0)) || - (result[y - 1] != 0)) - { - filtered_result[y] = 1; - } - else + // do not process 'first' and 'last' row to avoid out of index + // access. + if ((y > 0) && + (y != (RADIOLIB_SX126X_SPECTRAL_SCAN_RES_SIZE - 3))) { + if (((result[y + 1] != 0) && (result[y + 2] != 0)) || + (result[y - 1] != 0)) + { + filtered_result[y] = 1; + } + else + { #ifdef PRINT_DEBUG - Serial.print("Filtered:" + String(x) + ":" + String(y) + ","); + Serial.print("Filtered:" + String(x) + ":" + String(y) + + ","); #endif + } } + } // not filtering if samples == 1 + else if (result[y] > 0 && samples == 1) + { + filtered_result[y] = 1; } - } // not filtering if samples == 1 - else if (result[y] > 0 && samples == 1) - { - filtered_result[y] = 1; - } -#endif - // check if we should alarm about a drone presence - if ((filtered_result[y] == 1) // we have some data and - && (y <= drone_detection_level) && - detected_y[display_x] == false) // detection threshold match - { - // Set LED to ON (filtered in UI component) - UI_setLedFlag(true); +#endif + // check if we should alarm about a drone presence + if ((filtered_result[y] == 1) // we have some data and + && (y <= drone_detection_level) && + detected_y[display_x] == false) // detection threshold match + { + // Set LED to ON (filtered in UI component) + UI_setLedFlag(true); #if (WATERFALL_ENABLED == true) - if (single_page_scan) - { - // Drone detection true for waterfall - if (!waterfall[display_x]) + if (single_page_scan) { - waterfall[display_x] = true; - display.setColor(WHITE); - display.setPixel(display_x, w); + // Drone detection true for waterfall + if (!waterfall[display_x]) + { + waterfall[display_x] = true; + display.setColor(WHITE); + display.setPixel(display_x, w); + } } - } #endif - if (drone_detected_frequency_start == 0) - { - // mark freq start - drone_detected_frequency_start = freq; - } + if (drone_detected_frequency_start == 0) + { + // mark freq start + drone_detected_frequency_start = freq; + } - // mark freq end ... will shift right to last detected range - drone_detected_frequency_end = freq; + // mark freq end ... will shift right to last detected range + drone_detected_frequency_end = freq; + if (SOUND_ON == true) + { + drone_sound_alarm(drone_detection_level, detection_count); + } - // If level is set to sensitive, - // start beeping every 10th frequency and shorter - // it improves performance less short beep delays... - if (drone_detection_level <= 25) - { - if (detection_count == 1 && SOUND_ON) + if (DRAW_DETECTION_TICKS == true) { - tone(BUZZER_PIN, 205, - 10); // same action ??? but first time - } - if (detection_count % 5 == 0 && SOUND_ON) - { - tone(BUZZER_PIN, 205, - 10); // same action ??? but everey 5th time + // draw vertical line on top of display for "drone detected" + // frequencies + if (!detected_y[display_x]) + { + display.drawLine(display_x, 1, display_x, 4); + detected_y[display_x] = true; + } } } - else - { - if (detection_count % 20 == 0 && SOUND_ON) - { - tone(BUZZER_PIN, 205, - 10); // same action ??? but everey 20th detection - } - } - - if (DRAW_DETECTION_TICKS == true) - { - // draw vertical line on top of display for "drone detected" - // frequencies - if (!detected_y[display_x]) - { - display.drawLine(display_x, 1, display_x, 4); - detected_y[display_x] = true; - } - } - } #if (WATERFALL_ENABLED == true) - if ((filtered_result[y] == 1) && (y <= drone_detection_level) && - (single_page_scan) && (waterfall[display_x] != true) && new_pixel) - { - // If drone not found set dark pixel on the waterfall - // TODO: make something like scrolling up if possible - waterfall[display_x] = false; - display.setColor(BLACK); - display.setPixel(display_x, w); - display.setColor(WHITE); - } + if ((filtered_result[y] == 1) && (y <= drone_detection_level) && + (single_page_scan) && (waterfall[display_x] != true) && new_pixel) + { + // If drone not found set dark pixel on the waterfall + // TODO: make something like scrolling up if possible + waterfall[display_x] = false; + display.setColor(BLACK); + display.setPixel(display_x, w); + display.setColor(WHITE); + } #endif - -#if 0 - -#endif // If 0 - - // next 2 If's ... adds !!!! 10ms of runtime ......tfk ??? - if (filtered_result[y] == 1) - { -#ifdef PRINT_DEBUG - Serial.print("Pixel:" + String(display_x) + "(" + String(x) + ")" + - ":" + String(y) + ","); -#endif - if (max_rssi_x > y) - { - max_rssi_x = y; - } - // Set signal level pixel - if (y < MAX_POWER_LEVELS - START_LOW) - { - display.setPixel(display_x, y + START_LOW); - } - if (!detected) - { - detected = true; - } - } - - // ------------------------------------------------------------- - // Draw "Detection Level line" every 2 pixel - // ------------------------------------------------------------- - if ((y == drone_detection_level) && (display_x % 2 == 0)) - { - display.setColor(WHITE); + // next 2 If's ... adds !!!! 10ms of runtime ......tfk ??? if (filtered_result[y] == 1) { - display.setColor(INVERSE); +#ifdef PRINT_DEBUG + Serial.print("Pixel:" + String(display_x) + "(" + String(x) + + ")" + ":" + String(y) + ","); +#endif + if (max_rssi_x > y) + { + max_rssi_x = y; + } + // Set signal level pixel + if (y < MAX_POWER_LEVELS - START_LOW) + { + display.setPixel(display_x, y + START_LOW); + } + if (!detected) + { + detected = true; + } } - display.setPixel(display_x, y + START_LOW); - // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide - display.setColor(WHITE); + // ------------------------------------------------------------- + // Draw "Detection Level line" every 2 pixel + // ------------------------------------------------------------- + if ((y == drone_detection_level) && (display_x % 2 == 0)) + { + display.setColor(WHITE); + if (filtered_result[y] == 1) + { + display.setColor(INVERSE); + } + display.setPixel(display_x, y + START_LOW); + // display.setPixel(display_x, y + START_LOW - 1); // 2 px wide + + display.setColor(WHITE); + } } - } -#ifdef JOYSTICK_ENABLED - if (display_x == cursor_x_position) - { - display.drawString(display_x - 1, 0, String((int)freq)); - display.drawLine(display_x, 1, display_x, 12); - // if method scan RSSI we can get exact RSSI value - display.drawString(display_x + 17, 0, "-" + String((int)max_rssi_x * 4)); - } +#ifdef JOYSTICK_ENABLED + if (display_x == cursor_x_position) + { + + display.drawString(display_x - 1, 0, String((int)freq)); + display.drawLine(display_x, 1, display_x, 12); + // if method scan RSSI we can get exact RSSI value + display.drawString(display_x + 17, 0, + "-" + String((int)max_rssi_x * 4)); + } #endif #ifdef PRINT_PROFILE_TIME - scan_time += (millis() - scan_start_time); + scan_time += (millis() - scan_start_time); #endif - // count detected - if (detected) - { - detection_count++; - } + // count detected + if (detected) + { + detection_count++; + } #ifdef PRINT_DEBUG - Serial.println("....\n"); + Serial.println("....\n"); #endif - if (first_run || ANIMATED_RELOAD) - { - display.display(); - } + if (first_run || ANIMATED_RELOAD) + { + display.display(); + } - // Detection level button short press - if (button.pressedFor(100) +#ifndef LILYGO + // Detection level button short press + if (button.pressedFor(100) #ifdef JOYSTICK_ENABLED - || joy_btn_click() -#endif - ) - { - button.update(); - button_pressed_counter = 0; - // if long press stop - while (button.pressedNow() -#ifdef JOYSTICK_ENABLED - || joy_btn_click() + || joy_btn_click() #endif ) { - delay(10); - // Print Curent frequency - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(128 / 2, 0, String(freq)); - display.display(); - button_pressed_counter++; + button.update(); + button_pressed_counter = 0; + // if long press stop + while (button.pressedNow() +#ifdef JOYSTICK_ENABLED + || joy_btn_click() +#endif + ) + { + delay(10); + // Print Curent frequency + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.drawString(128 / 2, 0, String(freq)); + display.display(); + button_pressed_counter++; + if (button_pressed_counter > 150) + { + digitalWrite(LED, HIGH); + delay(150); + digitalWrite(LED, LOW); + } + } if (button_pressed_counter > 150) { - digitalWrite(LED, HIGH); - delay(150); - digitalWrite(LED, LOW); + // Remove Curent Frequency Text + display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setColor(BLACK); + display.drawString(128 / 2, 0, String(freq)); + display.setColor(WHITE); + display.display(); + break; } - } - if (button_pressed_counter > 150) - { - // Remove Curent Frequency Text - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setColor(BLACK); - display.drawString(128 / 2, 0, String(freq)); - display.setColor(WHITE); - display.display(); - break; - } - if (button_pressed_counter > 50 && button_pressed_counter < 150) - { - - if (!joy_btn_clicked) + if (button_pressed_counter > 50 && button_pressed_counter < 150) { - // Visually confirm it's off so user releases button - display.displayOff(); - // Deep sleep (has wait for release so we don't wake up - // immediately) - heltec_deep_sleep(); + if (!joy_btn_clicked) + { + // Visually confirm it's off so user releases button + display.displayOff(); + // Deep sleep (has wait for release so we don't wake up + // immediately) + heltec_deep_sleep(); + } + break; + } + button.update(); + display.setTextAlignment(TEXT_ALIGN_RIGHT); + // erase old drone detection level value + display.setColor(BLACK); + display.fillRect(128 - 13, 0, 13, 13); + display.setColor(WHITE); + drone_detection_level++; + // print new value + display.drawString(128, 0, String(drone_detection_level)); + tone(BUZZER_PIN, 104, 150); + if (drone_detection_level > 30) + { + drone_detection_level = 1; } - break; - } - button.update(); - display.setTextAlignment(TEXT_ALIGN_RIGHT); - // erase old drone detection level value - display.setColor(BLACK); - display.fillRect(128 - 13, 0, 13, 13); - display.setColor(WHITE); - drone_detection_level++; - // print new value - display.drawString(128, 0, String(drone_detection_level)); - tone(BUZZER_PIN, 104, 150); - if (drone_detection_level > 30) - { - drone_detection_level = 1; - } - } - // wait a little bit before the next scan, - // otherwise the SX1262 hangs - // Add more logic before insead of long delay... - int delay_cnt = 1; - while (radio.spectralScanGetStatus() != RADIOLIB_ERR_NONE) - { - if (delay_cnt == 1) - { - // trying to use display as delay.. - display.display(); - } - else - { - heltec_delay(ONE_MILLISEC * 2); } - Serial.println("spectralScanGetStatus ERROR(" + - String(radio.spectralScanGetStatus()) + - ") hard delay(2) - " + String(delay_cnt)); - // if error than speed is slow animating chart - ANIMATED_RELOAD = true; +#endif // END LILYGO - delay_cnt++; - } - // TODO: move osd logic here as a dalay ;) - // Loop is needed if heltec_delay(1) not used - heltec_loop(); + // wait a little bit before the next scan, + // otherwise the SX1262 hangs + // Add more logic before instead of long delay... + int delay_cnt = 1; +#ifdef METHOD_SPECTRAL + if (false && state != RADIOLIB_ERR_NONE) + { + if (delay_cnt == 1) + { + Serial.println("E:getResult"); + display.drawString(0, 64 - 10, "E:getResult"); + // trying to use display as delay.. + display.display(); + } + else + { + heltec_delay(ONE_MILLISEC * 2); + Serial.println("E:getStatus"); + display.drawString(0, 64 - 10, "E:getResult"); + // trying to use display as delay.. + display.display(); + } + + Serial.println("spectralScanGetStatus ERROR(" + + String(radio.spectralScanGetStatus()) + + ") hard delay(2) - " + String(delay_cnt)); + // if error than speed is slow animating chart + ANIMATED_RELOAD = true; + delay(50); + delay_cnt++; + } +#endif + // TODO: move osd logic here as a daley ;) + // Loop is needed if heltec_delay(1) not used + heltec_loop(); // Move joystick #ifdef JOYSTICK_ENABLED - int joy_x_pressed = get_joy_x(true); - if (joy_x_pressed > 0) - { - cursor_x_position--; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } - else if (joy_x_pressed < 0) - { - cursor_x_position++; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } - if (cursor_x_position > DISPLAY_WIDTH || cursor_x_position < 0) - { - cursor_x_position = 0; - display.drawString(cursor_x_position, 0, String((int)freq)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); - display.display(); - delay(10); - } + int joy_x_pressed = get_joy_x(true); + if (joy_x_pressed > 0) + { + cursor_x_position--; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } + else if (joy_x_pressed < 0) + { + cursor_x_position++; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } + if (cursor_x_position > DISPLAY_WIDTH || cursor_x_position < 0) + { + cursor_x_position = 0; + display.drawString(cursor_x_position, 0, String((int)freq)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.display(); + delay(10); + } #endif - } - w++; - if (w > ROW_STATUS_TEXT + 1) - { - w = WATERFALL_START; - } + } + w++; + if (w > ROW_STATUS_TEXT + 1) + { + w = WATERFALL_START; + } #if (WATERFALL_ENABLED == true) - // Draw waterfall position cursor - if (single_page_scan) - { - display.setColor(BLACK); - display.drawHorizontalLine(0, w, STEPS); - display.setColor(WHITE); - } + // Draw waterfall position cursor + if (single_page_scan) + { + display.setColor(BLACK); + display.drawHorizontalLine(0, w, STEPS); + display.setColor(WHITE); + } #endif - // Render display data here - display.display(); + // Render display data here + display.display(); #ifdef OSD_ENABLED - // Sometimes OSD prints entire screan with the digits. - // We need clean the screan to fix it. - // We can do it every time but to optimise doing every N times - if (global_counter != 0 && global_counter % 10 == 0) - { + // Sometimes OSD prints entire screen with the digits. + // We need clean the screen to fix it. + // We can do it every time but to optimise doing every N times + if (global_counter != 0 && global_counter % 10 == 0) + { #if !defined(BT_SCANNING_ENABLED) && !defined(WIFI_SCANNING_ENABLED) - osd.clear(); - osd.displayChar(14, 1, 0x10f); - global_counter = 0; + osd.clear(); + osd.displayChar(14, 1, 0x10f); + global_counter = 0; +#endif + } + ANIMATED_RELOAD = false; + global_counter++; #endif } - ANIMATED_RELOAD = false; - global_counter++; -#endif } - #ifdef PRINT_DEBUG // Serial.println("----"); #endif