diff --git a/include/images.h b/include/images.h index bb29f07..130f629 100644 --- a/include/images.h +++ b/include/images.h @@ -1,10 +1,11 @@ #ifndef __IMAGES_H__ #define __IMAGES_H__ +#include // Array of all bitmaps for convenience. (Total bytes used to store images in // PROGMEM = 1040) -extern const unsigned char epd_bitmap_ucog[]; +extern const uint8_t epd_bitmap_ucog[]; #endif // __IMAGES_H__ diff --git a/include/ui.h b/include/ui.h index ddf7a73..0495ca2 100644 --- a/include/ui.h +++ b/include/ui.h @@ -3,8 +3,8 @@ #ifdef Vision_Master_E290 #include "HT_DEPG0290BxS800FxX_BW.h" #else -#include "OLEDDisplayUi.h" -#include "SSD1306Wire.h" +#include "Adafruit_SSD1306.h" +// #include "OLEDDisplayUi.h" #include #endif diff --git a/lib/charts/BarChart.cpp b/lib/charts/BarChart.cpp index 305cdbd..73db58e 100644 --- a/lib/charts/BarChart.cpp +++ b/lib/charts/BarChart.cpp @@ -62,21 +62,21 @@ void BarChart::drawOne(int x) if (y < height) { - display.setColor(BLACK); - display.drawVerticalLine(pos_x + x, pos_y, y); - display.setColor(WHITE); - display.drawVerticalLine(pos_x + x, pos_y + y, height - y); + // display.setColor(BLACK); + display.drawFastVLine(pos_x + x, pos_y, y, BLACK); + // display.setColor(WHITE); + display.drawFastVLine(pos_x + x, pos_y + y, height - y, WHITE); } else { - display.setColor(BLACK); - display.drawVerticalLine(pos_x + x, pos_y, height); + // display.setColor(BLACK); + display.drawFastVLine(pos_x + x, pos_y, height, BLACK); } if (x % 2 == 0) { - display.setColor(INVERSE); - display.setPixel(pos_x + x, pos_y + y2pos(level_y)); + // display.setColor(INVERSE); + display.drawPixel(pos_x + x, pos_y + y2pos(level_y), INVERSE); } changed[x] = false; @@ -130,11 +130,11 @@ void DecoratedBarChart::draw() bar.draw(); - display.setColor(BLACK); - display.fillRect(pos_x, pos_y, width, bar.pos_y - pos_y); + // display.setColor(BLACK); + display.fillRect(pos_x, pos_y, width, bar.pos_y - pos_y, BLACK); - display.setColor(WHITE); - display.setTextAlignment(TEXT_ALIGN_LEFT); + // display.setColor(WHITE); + // display.setTextAlignment(TEXT_ALIGN_LEFT); uint16_t first_untouched = 0; @@ -144,7 +144,9 @@ void DecoratedBarChart::draw() if (y >= bar.level_y) { String s = String(bar.ys[x], 0); - uint16_t w = display.getStringWidth(s); + int16_t x0, y0; // Variables to store the top-left corner + uint16_t w, h0; // Variables to store width and height + display.getTextBounds(s.c_str(), 0, 0, &x0, &y0, &w, &h0); uint16_t x1 = x; for (; x < x1 + w && x < width; x++) { @@ -152,7 +154,10 @@ void DecoratedBarChart::draw() { y = bar.ys[x]; s = String(y, 0); - w = max(w, display.getStringWidth(s)); + int16_t x0, y0; // Variables to store the top-left corner + uint16_t w1, h0; // Variables to store width and height + display.getTextBounds(s.c_str(), 0, 0, &x0, &y0, &w1, &h0); + w = max(w, w1); } } @@ -164,31 +169,34 @@ void DecoratedBarChart::draw() first_untouched = x; if (x1 + w <= width) - display.drawString(pos_x + x1, pos_y, s); + { + // Detected dB level text + display.setCursor(pos_x + x1 - 10, pos_y); + display.print(s); + } } } if (draw_axis) { - display.setColor(WHITE); uint16_t y = pos_y + height - AXIS_HEIGHT + 2; - display.fillRect(pos_x, y - 1, width, X_AXIS_WEIGHT); + display.fillRect(pos_x, y - 1, width, X_AXIS_WEIGHT, WHITE); // Start and end ticks - display.fillRect(pos_x, y - 1, 2, AXIS_HEIGHT); - display.fillRect(pos_x + width - 2, y - 1, 2, AXIS_HEIGHT); + display.fillRect(pos_x, y - 1, 2, AXIS_HEIGHT, WHITE); + display.fillRect(pos_x + width - 2, y - 1, 2, AXIS_HEIGHT, WHITE); for (float step = 0; bar.min_x + step * MAJOR_TICKS < bar.max_x; step += 1) { int tick_pos = bar.x2pos(bar.min_x + step * MAJOR_TICKS); - display.drawVerticalLine(pos_x + tick_pos, y, MAJOR_TICK_LENGTH); + display.drawFastVLine(pos_x + tick_pos, y, MAJOR_TICK_LENGTH, WHITE); } for (float step = 0; bar.min_x + step * MINOR_TICKS < bar.max_x; step += 1) { int tick_pos = bar.x2pos(bar.min_x + step * MINOR_TICKS); - display.drawVerticalLine(pos_x + tick_pos, y, MINOR_TICK_LENGTH); + display.drawFastVLine(pos_x + tick_pos, y, MINOR_TICK_LENGTH, WHITE); } } } diff --git a/lib/charts/UptimeClock.cpp b/lib/charts/UptimeClock.cpp index f7e229e..afd79f9 100644 --- a/lib/charts/UptimeClock.cpp +++ b/lib/charts/UptimeClock.cpp @@ -19,10 +19,12 @@ void UptimeClock::draw() : mils < 100 ? ".0" : ".") + String(mils); - int w = display.getStringWidth(s); - display.setColor(BLACK); - display.fillRect((display.width() - w) / 2, display.height() / 2 - 3, w, 7); - display.setColor(WHITE); - display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH); - display.drawString(display.width() / 2, display.height() / 2, s); + uint16_t w, h1 = 0; + int16_t x1, y1 = 0; + display.getTextBounds(s.c_str(), 0, 0, &x1, &y1, &w, &h1); + display.fillRect((display.width() - w) / 2, display.height() / 2 - 3, w, 7, BLACK); + display.setTextColor(WHITE); + // display.setTextAlignment(TEXT_ALIGN_CENTER_BOTH); + display.setCursor(display.width() / 2, display.height() / 2); + display.print(s); } diff --git a/lib/charts/WaterfallChart.cpp b/lib/charts/WaterfallChart.cpp index f3b6553..fc00997 100644 --- a/lib/charts/WaterfallChart.cpp +++ b/lib/charts/WaterfallChart.cpp @@ -32,14 +32,12 @@ void WaterfallChart::draw() (model->events[y][x] >= model->counts[y][x] * threshold); if (b) { - display.setColor(WHITE); + display.drawPixel(pos_x + x, pos_y + y, WHITE); } else { - display.setColor(BLACK); + display.drawPixel(pos_x + x, pos_y + y, BLACK); } - - display.setPixel(pos_x + x, pos_y + y); } } diff --git a/lib/charts/charts.h b/lib/charts/charts.h index d159cc0..e9f5b94 100644 --- a/lib/charts/charts.h +++ b/lib/charts/charts.h @@ -5,8 +5,9 @@ #include "HT_DEPG0290BxS800FxX_BW.h" typedef DEPG0290BxS800FxX_BW Display_t; #else -#include -typedef OLEDDisplay Display_t; +#include "Adafruit_GFX.h" +#include "Adafruit_SSD1306.h" +typedef Adafruit_SSD1306 Display_t; #endif #include diff --git a/lib/loraboards/LiLyGo.h b/lib/loraboards/LiLyGo.h index 103240b..9307b2b 100644 --- a/lib/loraboards/LiLyGo.h +++ b/lib/loraboards/LiLyGo.h @@ -10,7 +10,10 @@ #else #define DISPLAY_WIDTH 128 #define DISPLAY_HEIGHT 64 -#include "SSD1306Wire.h" +// #include "SSD1306Wire.h" +#include "Adafruit_GFX.h" +#include "Adafruit_SSD1306.h" + #endif #define RADIO_TYPE SX1262 @@ -36,8 +39,8 @@ extern RADIO_TYPE radio; #endif #define SCREEN_ADDRESS 0x3C -#define DISPLAY_TYPE SSD1306Wire -#define DISPLAY_INIT() SSD1306Wire(SCREEN_ADDRESS, I2C_SDA, I2C_SCL, DISPLAY_GEOMETRY) +#define DISPLAY_TYPE Adafruit_SSD1306 +#define DISPLAY_INIT() Adafruit_SSD1306(128, 64, &Wire, OLED_RST) // SH1106Wire display(0x3c, I2C_SDA, I2C_SCL, DISPLAY_GEOMETRY); #else #define DISPLAY_TYPE void * @@ -62,7 +65,13 @@ extern RADIO_TYPE radio; // #include "OLEDDisplayUi.h" // #include "SH1106Wire.h" // #include "SSD1306Brzo.h" -#include "SSD1306Wire.h" +// #include "SSD1306Wire.h" + +#define DISPLAY_WIDTH 128 +#define DISPLAY_HEIGHT 64 + +#include "Adafruit_GFX.h" +#include "Adafruit_SSD1306.h" #ifdef USING_SX1280PA #define RADIO_TYPE SX1280 @@ -125,11 +134,13 @@ class PrintSplitter : public Print Print &b; }; -#define DISPLAY_GEOMETRY GEOMETRY_128_64 +#define DISPLAY_GEOMETRY "128_64" #define SCREEN_ADDRESS 0x3C -#define DISPLAY_TYPE SSD1306Wire -#define DISPLAY_INIT() SSD1306Wire(SCREEN_ADDRESS, I2C_SDA, I2C_SCL, DISPLAY_GEOMETRY) +#define DISPLAY_TYPE Adafruit_SSD1306 +#define DISPLAY_INIT() Adafruit_SSD1306(128, 64, &Wire, OLED_RST) +// Adafruit_SSD1306(SCREEN_ADDRESS, I2C_SDA, I2C_SCL, DISPLAY_GEOMETRY) +// Adafruit_SSD1306(128, 64, &Wire, OLED_RST); // SH1106Wire display(0x3c, I2C_SDA, I2C_SCL, DISPLAY_GEOMETRY); #define BOTH_TYPE PrintSplitter diff --git a/lib/loraboards/LoRaBoards.cpp b/lib/loraboards/LoRaBoards.cpp index 7353c99..13f57e7 100644 --- a/lib/loraboards/LoRaBoards.cpp +++ b/lib/loraboards/LoRaBoards.cpp @@ -13,6 +13,7 @@ #include "LoRaBoards.h" #include "LiLyGo.h" +#include // Implement stubs for functions that exist on Heltec, but not on LilyGo void heltec_led(int led) {} @@ -22,7 +23,7 @@ void heltec_deep_sleep(int sleep_seconds) {} void heltec_delay(int millisec) { delay(millisec); } DISPLAY_TYPE display = DISPLAY_INIT(); -BOTH_TYPE both = BOTH_INIT(); +BOTH_TYPE splitBoth = BOTH_INIT(); HotButton button(BUTTON); @@ -35,14 +36,11 @@ void heltec_loop() void heltec_display_power(bool on) { -#ifndef HELTEC_NO_DISPLAY_INSTANCE + DISPLAY_TYPE display = DISPLAY_INIT(); + BOTH_TYPE splitBoth = BOTH_INIT(); 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); @@ -52,13 +50,8 @@ void heltec_display_power(bool on) } else { -#ifdef HELTEC_WIRELESS_STICK - heltec_ve(false); -#else - display.displayOff(); -#endif + display.ssd1306_command(SSD1306_DISPLAYOFF); } -#endif } void heltec_setup() @@ -76,15 +69,17 @@ void heltec_setup() #endif #ifdef HELTEC + heltec_display_power(true); + display.begin(DISPLAY_ADDR, SCREEN_ADDRESS); #ifndef ARDUINO_heltec_wifi_32_lora_V3 hspi->begin(SCK, MISO, MOSI, SS); #endif #endif #ifndef HELTEC_NO_DISPLAY_INSTANCE heltec_display_power(true); - display.init(); + display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS); // display.setContrast(200); - display.flipScreenVertically(); + // display.ssd1306_command(SSD1306_COMSCANINC); #endif } @@ -111,7 +106,7 @@ HardwareSerial SerialGPS(GPS_RX_PIN, GPS_TX_PIN); #include "driver/gpio.h" #endif // ARDUINO_ARCH_ESP32 -DISPLAY_MODEL *u8g2 = NULL; +// DISPLAY_MODEL *u8g2 = NULL; static DevInfo_t devInfo; #ifdef HAS_GPS @@ -530,29 +525,31 @@ void loopPMU() 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; - } + // ToDO: make it work with new Adafruit lib + /** 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; + Serial.printf("Warning: Failed to find Display at 0x%0X address\n", DISPLAY_ADDR); + return false; + */ } bool beginSDCard() @@ -847,7 +844,7 @@ void printResult(bool radio_online) Serial.println((psramFound()) ? "+" : "-"); Serial.print("Display : "); - Serial.println((u8g2) ? "+" : "-"); + // Serial.println((u8g2) ? "+" : "-"); #ifdef HAS_SDCARD Serial.print("Sd Card : "); @@ -866,34 +863,35 @@ void printResult(bool radio_online) #endif #endif - if (u8g2) + if (false /*&& 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->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) ? "+" : "-"); - 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 -#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) ? "+" : "-"); - 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 -#ifdef HAS_PMU - u8g2->drawStr(62, 54, "Power:"); - u8g2->drawStr(120, 54, (PMU) ? "+" : "-"); -#endif + u8g2->sendBuffer(); - u8g2->sendBuffer(); - - delay(2000); + delay(2000); + */ } #endif } diff --git a/lib/loraboards/LoRaBoards.h b/lib/loraboards/LoRaBoards.h index 811f209..35e07b1 100644 --- a/lib/loraboards/LoRaBoards.h +++ b/lib/loraboards/LoRaBoards.h @@ -23,12 +23,12 @@ #include #include -#include +// #include #include #include #ifndef DISPLAY_MODEL -#define DISPLAY_MODEL U8G2_SSD1306_128X64_NONAME_F_HW_I2C +// #define DISPLAY_MODEL SSD1306_128X64_NONAME_F_HW_I2C #endif #ifndef OLED_WIRE_PORT @@ -57,7 +57,7 @@ typedef struct uint8_t flashSpeed; } DevInfo_t; -void setupBoards(bool disable_u8g2 = false); +void setupBoards(bool disable_u8g2 = true); bool beginSDCard(); @@ -81,10 +81,10 @@ void loopPMU(); extern XPowersLibInterface *PMU; extern bool pmuInterrupt; #endif -extern DISPLAY_MODEL *u8g2; +// 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)) +// #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) diff --git a/platformio.ini b/platformio.ini index 6696f87..1d44e00 100644 --- a/platformio.ini +++ b/platformio.ini @@ -31,12 +31,13 @@ lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 bblanchon/ArduinoJson@^7.2.0 ESP Async WebServer + adafruit/Adafruit SSD1306@^2.5.13 build_flags = -DHELTEC_POWER_BUTTON -DHELTEC -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_USB_MODE=1 - + [env:heltec_wifi_lora_32_V3-OSD] platform = espressif32 board = heltec_wifi_lora_32_V3 @@ -49,6 +50,7 @@ lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 bblanchon/ArduinoJson@^7.2.0 ESP Async WebServer + adafruit/Adafruit SSD1306@^2.5.13 build_flags = -DHELTEC_POWER_BUTTON -DHELTEC @@ -67,6 +69,7 @@ lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 bblanchon/ArduinoJson@^7.2.0 ESP Async WebServer + adafruit/Adafruit SSD1306@^2.5.13 build_flags = -DHELTEC_POWER_BUTTON -DHELTEC @@ -86,9 +89,9 @@ lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 bblanchon/ArduinoJson@^7.2.0 RadioLib - U8g2 XPowersLib ESP Async WebServer + adafruit/Adafruit SSD1306@^2.5.13 build_flags = -DLILYGO -DT3_S3_V1_2_SX1262 @@ -116,22 +119,22 @@ lib_deps = XPowersLib bblanchon/ArduinoJson@^7.2.0 ESP Async WebServer + adafruit/Adafruit SSD1306@^2.5.13 build_flags = -DLILYGO -DT3_S3_V1_2_LR1121 -DT3_V1_3_SX1262 -DARDUINO_LILYGO_T3S3_LR1121 -DESP32 - -DSAMPLES_RSSI=5 + -DSAMPLES_RSSI=5 -DUSING_LR1121 - -DFREQ_BEGIN=2400 + -DFREQ_BEGIN=2400 -DFREQ_END=2500 -DARDUINO_ARCH_ESP32 -DARDUINO_USB_CDC_ON_BOOT=1 -DARDUINO_LILYGO_T3_S3_V1_X -DARDUINO_USB_MODE=1 - [env:lilygo-T3S3-v1-2-sx1280] platform = espressif32 board = t3_s3_v1_x @@ -147,6 +150,7 @@ lib_deps = U8g2 XPowersLib ESP Async WebServer + adafruit/Adafruit SSD1306@^2.5.13 build_flags = -DLILYGO -DT3_S3_V1_2_SX1280_PA @@ -174,20 +178,17 @@ lib_deps = U8g2 XPowersLib ESP Async WebServer -build_flags = + adafruit/Adafruit SSD1306@^2.5.13 +build_flags = -DLILYGO -DT3_V1_6_SX1276 -DUSING_SX1276 -DESP32 -DARDUINO_ARCH_ESP32 - -DARDUINO_USB_CDC_ON_BOOT=0 ;; if not 0 - Serial issue + -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_LILYGO_T3_V1_6 -DARDUINO_USB_MODE=1 -;; More old lylygo/titygo boeads defenitions you can find here: -;; https://github.com/PTR-projects/PTR_GroundStation_firmware/blob/main/platformio.ini -;; https://github.com/Xinyuan-LilyGO/LilyGo-LoRa-Series/blob/master/platformio.ini - [env:heltec_wifi_lora_32_V3-test-signal-generator] platform = espressif32 board = heltec_wifi_lora_32_V3 @@ -198,6 +199,7 @@ board_build.f_cpu = 240000000 board_build.flash_size = 80000000L lib_deps = ropg/Heltec_ESP32_LoRa_v3@^0.9.1 + adafruit/Adafruit SSD1306@^2.5.13 build_flags = -DHELTEC -DHELTEC_POWER_BUTTON @@ -209,7 +211,7 @@ framework = arduino monitor_speed = 115200 monitor_filters = esp32_exception_decoder board_upload.use_1200bps_touch = true -build_flags = +build_flags = -DHELTEC -DHELTEC_BOARD=37 -DSLOW_CLK_TPYE=1 @@ -273,3 +275,4 @@ lib_deps = [env:native] platform = native +lib_deps = adafruit/Adafruit SSD1306@^2.5.13 diff --git a/src/images.cpp b/src/images.cpp index d2ab5f7..64fd633 100644 --- a/src/images.cpp +++ b/src/images.cpp @@ -1,12 +1,13 @@ #include "images.h" +#include //'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 -const unsigned char epd_bitmap_ucog[] = { +const uint8_t 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, diff --git a/src/main.cpp b/src/main.cpp index 771d45d..0b39666 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -21,7 +21,9 @@ https://jgromes.github.io/RadioLib/ */ -// #define HELTEC_NO_DISPLAY +// We are not using default display library but Adafruit insread +#define HELTEC_NO_DISPLAY_INSTANCE +#define HELTEC_NO_DISPLAY #include "FS.h" #include @@ -32,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -63,6 +66,7 @@ #ifndef LILYGO #include + // This file contains a binary patch for the SX1262 #include "modules/SX126x/patches/SX126x_patch_scan.h" #endif // end ifndef LILYGO @@ -80,6 +84,48 @@ #include #endif // end LILYGO +#if defined(HELTEC) && defined(HELTEC_NO_DISPLAY) +#define DISPLAY_ADDR 0x3C +#include "Adafruit_GFX.h" +#include "Adafruit_SSD1306.h" +/** + * @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 PrintSplitter2 : public Print +{ + public: + PrintSplitter2(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; +}; + +#define DISPLAY_GEOMETRY GEOMETRY_128_64 + +#define SCREEN_ADDRESS 0x3C +// Wire.begin(SDA_OLED, SCL_OLED); +Adafruit_SSD1306 display(128, 64, &Wire, RST_OLED); +PrintSplitter2 splitBoth(Serial, display); + +#endif + #define BT_SCAN_DELAY 60 * 1 * 1000 #define WF_SCAN_DELAY 60 * 2 * 1000 long noDevicesMillis = 0, cycleCnt = 0; @@ -575,9 +621,9 @@ bool setFrequency(float curr_freq) #endif if (state != RADIOLIB_ERR_NONE) { - display.drawString(0, 64 - 10, - "E(" + String(state) + - "):setFrequency:" + String(r.current_frequency)); + display.setCursor(0, 64 - 10); + display.print("E(" + String(state) + + "):setFrequency:" + String(r.current_frequency)); Serial.println("E(" + String(state) + "):setFrequency:" + String(r.current_frequency)); display.display(); @@ -591,7 +637,7 @@ bool setFrequency(float curr_freq) void init_radio() { // initialize SX1262 FSK modem at the initial frequency - both.println("Init radio"); + splitBoth.println("Init radio"); state = initForScan(CONF_FREQ_BEGIN); if (state == RADIOLIB_ERR_NONE) @@ -614,7 +660,7 @@ void init_radio() // upload a patch to the SX1262 to enable spectral scan // NOTE: this patch is uploaded into volatile memory, // and must be re-uploaded on every power up - both.println("Upload SX1262 patch"); + splitBoth.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. @@ -622,7 +668,7 @@ void init_radio() // configure scan bandwidth and disable the data shaping #endif - both.println("Setting up radio"); + splitBoth.println("Setting up radio"); #ifdef USING_SX1280PA // RADIOLIB_OR_HALT(radio.setBandwidth(RADIOLIB_SX128X_LORA_BW_406_25)); #elif USING_SX1276 @@ -640,7 +686,7 @@ void init_radio() { Serial.println("Error:setDataShaping:" + String(state)); } - both.println("Starting scanning..."); + splitBoth.println("Starting scanning..."); // calibrate only once ,,, at startup // TODO: check documentation (9.2.1) if we must calibrate in certain ranges @@ -961,9 +1007,9 @@ void readConfigFile() config.configureDetectionStrategy(detection); configureDetection(); - both.println("C FREQ BEGIN:" + String(CONF_FREQ_BEGIN)); - both.println("C FREQ END:" + String(CONF_FREQ_END)); - both.println("C SAMPLES:" + String(CONF_SAMPLES)); + splitBoth.println("C FREQ BEGIN:" + String(CONF_FREQ_BEGIN)); + splitBoth.println("C FREQ END:" + String(CONF_FREQ_END)); + splitBoth.println("C SAMPLES:" + String(CONF_SAMPLES)); } void setup(void) @@ -1023,6 +1069,16 @@ void setup(void) pinMode(BUZZER_PIN, OUTPUT); pinMode(REB_PIN, OUTPUT); heltec_setup(); +#if defined(HELTEC) && defined(HELTEC_NO_DISPLAY) + pinMode(RST_OLED, OUTPUT); + digitalWrite(RST_OLED, HIGH); + delay(1); + digitalWrite(RST_OLED, LOW); + delay(20); + digitalWrite(RST_OLED, HIGH); + Wire.begin((int)SDA_OLED, (int)SCL_OLED); + display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS, false, false); +#endif #ifdef JOYSTICK_ENABLED calibrate_joy(); @@ -1043,21 +1099,21 @@ void setup(void) } } - display.clear(); + display.clearDisplay(); #ifdef WEB_SERVER - both.println("CLICK for WIFI settings."); + splitBoth.println("CLICK for WIFI settings."); for (int i = 0; i < 200; i++) { - both.print("."); + splitBoth.print("."); button.update(); delay(10); if (button.pressedNow()) { - both.println("-----------"); - both.println("Starting WIFI-SERVER..."); + splitBoth.println("-----------"); + splitBoth.println("Starting WIFI-SERVER..."); // Error here: E (15752) ledc: ledc_get_duty(745): LEDC is not initialized tone(BUZZER_PIN, 205, 100); delay(50); @@ -1066,14 +1122,14 @@ void setup(void) delay(50); serverStart(); - both.println("Ready to Connect: 192.168.4.1"); + splitBoth.println("Ready to Connect: 192.168.4.1"); delay(600); break; } } - both.print("\n"); + splitBoth.print("\n"); - both.println("Init File System"); + splitBoth.println("Init File System"); initLittleFS(); readConfigFile(); @@ -1087,15 +1143,15 @@ void setup(void) configureDetection(); - both.println("FREQ BEGIN:" + String(CONF_FREQ_BEGIN)); - both.println("FREQ END:" + String(CONF_FREQ_END)); - both.println("SAMPLES:" + String(CONF_SAMPLES)); + splitBoth.println("FREQ BEGIN:" + String(CONF_FREQ_BEGIN)); + splitBoth.println("FREQ END:" + String(CONF_FREQ_END)); + splitBoth.println("SAMPLES:" + String(CONF_SAMPLES)); #endif init_radio(); #ifndef LILYGO vbat = heltec_vbat(); - both.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); + splitBoth.printf("V battery: %.2fV (%d%%)\n", vbat, heltec_battery_percent(vbat)); delay(1000); #endif // end not LILYGO #ifdef WIFI_SCANNING_ENABLED @@ -1106,7 +1162,7 @@ void setup(void) #endif delay(400); - display.clear(); + display.clearDisplay(); resolution = (float)RANGE / (STEPS * SCAN_RBW_FACTOR); @@ -1122,17 +1178,17 @@ void setup(void) if (single_page_scan) { - both.println("Single Page Screen MODE"); - both.println("Multi Screen View Press P - button"); - both.println("Multi Screen Res: " + String(resolution) + "Mhz/tick"); - both.println( + splitBoth.println("Single Page Screen MODE"); + splitBoth.println("Multi Screen View Press P - button"); + splitBoth.println("Multi Screen Res: " + String(resolution) + "Mhz/tick"); + splitBoth.println( "Resolution: " + String((float)RANGE_PER_PAGE / (STEPS * SCAN_RBW_FACTOR)) + "MHz/tick"); for (int i = 0; i < 500; i++) { button.update(); delay(5); - both.print("."); + splitBoth.print("."); if (button.pressed()) { RANGE_PER_PAGE = DEFAULT_RANGE_PER_PAGE; @@ -1146,17 +1202,17 @@ void setup(void) } else { - both.println("Multi Page Screen MODE"); - both.println("Single screen View Press P - button"); - both.println("Single screen Resol: " + String(resolution) + "Mhz/tick"); - both.println( + splitBoth.println("Multi Page Screen MODE"); + splitBoth.println("Single screen View Press P - button"); + splitBoth.println("Single screen Resol: " + String(resolution) + "Mhz/tick"); + splitBoth.println( "Resolution: " + String((float)RANGE_PER_PAGE / (STEPS * SCAN_RBW_FACTOR)) + "Mhz/tick"); for (int i = 0; i < 500; i++) { button.update(); delay(10); - both.print("."); + splitBoth.print("."); if (button.pressed()) { RANGE_PER_PAGE = range; @@ -1168,7 +1224,7 @@ void setup(void) } configurePages(); - display.clear(); + display.clearDisplay(); Serial.println(); #ifdef METHOD_RSSI @@ -1182,7 +1238,8 @@ 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.setCursor(0, 64 - 10); + display.print("E:startReceive"); display.display(); delay(500); Serial.println(state); @@ -1374,24 +1431,29 @@ void joystickMoveCursor(int joy_x_pressed) if (joy_x_pressed > 0) { cursor_x_position--; - display.drawString(cursor_x_position, 0, String((int)r.current_frequency)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.setCursor(cursor_x_position, 0); + display.print(String((int)r.current_frequency)); + display.setCursor(cursor_x_position, 1); + display.drawFastHLine(cursor_x_position, 10, 1, WHITE); display.display(); delay(10); } else if (joy_x_pressed < 0) { cursor_x_position++; - display.drawString(cursor_x_position, 0, String((int)r.current_frequency)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.setCursor(cursor_x_position, 0); + display.print(String((int)r.current_frequency)); + display.setCursor(cursor_x_position, 1); + display.drawFastHLine(cursor_x_position, 10, 1, WHITE); 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)r.current_frequency)); - display.drawLine(cursor_x_position, 1, cursor_x_position, 10); + display.setCursor(cursor_x_position, 0); + display.print(String((int)r.current_frequency)); + display.drawLine(cursor_x_position, 1, cursor_x_position, 10, WHITE); display.display(); delay(10); } @@ -1577,7 +1639,7 @@ void doScan() #endif drone_detected_frequency_start = 0; - display.setTextAlignment(TEXT_ALIGN_RIGHT); + // display.setTextAlignment(TEXT_ALIGN_RIGHT); for (int i = 0; i < MAX_POWER_LEVELS; i++) { @@ -1788,8 +1850,14 @@ void doScan() if (buttonInputRequested()) { - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(display.width() / 2, 0, String(r.current_frequency)); + // display.setTextAlignment(TEXT_ALIGN_CENTER); + int16_t x1, y1; + uint16_t w, h0; + String s = String(r.current_frequency); + // Measure the text dimensions + display.getTextBounds(s.c_str(), 0, 0, &x1, &y1, &w, &h0); + display.setCursor((display.width() / 2) - w, 0); + display.print(s); display.display(); ButtonEvent e = buttonPressEvent(); @@ -1797,11 +1865,16 @@ void doScan() if (e == LONG_PRESS) { // Remove Curent Frequency Text - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.setColor(BLACK); - display.drawString(display.width() / 2, 0, - String(r.current_frequency)); - display.setColor(WHITE); + // display.setTextAlignment(TEXT_ALIGN_CENTER); + int16_t x1, y1; + uint16_t w, h0; + String s = String(r.current_frequency); + // Measure the text dimensions + display.getTextBounds(s.c_str(), 0, 0, &x1, &y1, &w, &h0); + display.setTextColor(BLACK); + display.setCursor((display.width() / 2) - w, 0); + display.print(s); + display.setTextColor(WHITE); display.display(); break; @@ -1810,7 +1883,7 @@ void doScan() if (e == SUSPEND) { // Visually confirm it's off so user releases button - display.displayOff(); + display.clearDisplay(); // Deep sleep (has wait for release so we don't wake up // immediately) heltec_deep_sleep(); @@ -1823,12 +1896,17 @@ void doScan() if (e == TOO_SHORT) { String v = String(r.trigger_level) + " dB"; - uint16_t w = display.getStringWidth(v); - display.setTextAlignment(TEXT_ALIGN_RIGHT); - // erase old drone detection level value - display.setColor(BLACK); - display.fillRect(display.width() - w, 0, 13, w); - display.setColor(WHITE); + int16_t x0, y0; + uint16_t w, h0; + + // Measure the text dimensions + display.getTextBounds(v.c_str(), 0, 0, &x0, &y0, &w, &h0); + + // display.setTextAlignment(TEXT_ALIGN_RIGHT); + // erase old drone detection level value + display.setTextColor(BLACK); + display.fillRect(display.width() - w, 0, 13, w, BLACK); + display.setTextColor(WHITE); // dt is roughly single-pixel increment float dt = @@ -1842,7 +1920,8 @@ void doScan() } // print new value - display.drawString(display.width(), 0, v); + display.setCursor(display.width(), 0); + display.print(v); tone(BUZZER_PIN, 104, 150); bar->bar.redraw_all = true; @@ -1977,6 +2056,18 @@ int16_t checkRadio(RadioComms &comms) if (msg->type == SCAN_RESULT) { + display.clearDisplay(); + // display.setDisplayRotation(1); + display.println("Host Mode ->"); + + size_t dump_sz = msg->payload.dump.sz; + + for (int i = 0; i < dump_sz; i++) + { + int16_t rssi = msg->payload.dump.rssis[i]; + int16_t fr = msg->payload.dump.freqs_khz[i]; + display.println(String(fr) + ":" + String(rssi)); + } HostComms->send(*msg); } else diff --git a/src/ui.cpp b/src/ui.cpp index 4349d85..3c76c3a 100644 --- a/src/ui.cpp +++ b/src/ui.cpp @@ -29,17 +29,17 @@ extern uint64_t loop_time; void UI_Init(Display_t *display_ptr) { // check for null ??? - display_ptr->clear(); + display_ptr->clearDisplay(); // draw the UCOG welcome logo - display_ptr->drawXbm(0, 2, 128, 64, epd_bitmap_ucog); + display_ptr->drawBitmap(0, 0, epd_bitmap_ucog, 128, 64, SSD1306_WHITE); display_ptr->display(); } void StatusBar::clearStatus(void) { // clear status line - display.setColor(BLACK); - display.fillRect(pos_x, pos_y, width, height); + // display.setColor(BLACK); + display.fillRect(pos_x, pos_y - 1, width, height, BLACK); } void UI_clearPlotter(void) @@ -73,13 +73,14 @@ void UI_drawCursor(int16_t possition) */ void StatusBar::draw() { - uint16_t text_y = pos_y + height - 10; + uint16_t text_y = pos_y + height - 8; if (!ui_initialized) { // Drone detection level - display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(width, 0, String(r.drone_detection_level)); + // display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.setCursor(120, 0); + display.print(String(r.drone_detection_level)); } if (!ui_initialized) { @@ -89,41 +90,52 @@ void StatusBar::draw() display_instance->setColor(WHITE); */ // Drone detection level - display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(pos_x + width, 0, String(r.drone_detection_level)); + // display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.setTextSize(1); + display.setCursor(pos_x + width, 0); + display.print(String(r.drone_detection_level)); // Frequency start - display.setTextAlignment(TEXT_ALIGN_LEFT); - display.drawString(pos_x, text_y, - (r.fr_begin == 0) ? String(CONF_FREQ_BEGIN) - : String(r.fr_begin)); + // display.setTextAlignment(TEXT_ALIGN_LEFT); + display.setCursor(pos_x, text_y); + display.print((r.fr_begin == 0) ? String(CONF_FREQ_BEGIN) : String(r.fr_begin)); - // Frequency detected - display.setTextAlignment(TEXT_ALIGN_CENTER); - display.drawString(pos_x + width / 2, text_y, - (r.fr_begin == 0) - ? String(median_frequency) - : String(r.fr_begin + ((r.fr_end - r.fr_begin) / 2))); + // Frequency median + // display.setTextAlignment(TEXT_ALIGN_CENTER); + display.setCursor(pos_x + width / 2, text_y); + display.print((r.fr_begin == 0) + ? String(median_frequency) + : String(r.fr_begin + ((r.fr_end - r.fr_begin) / 2))); // Frequency end - display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(pos_x + width, text_y, - (r.fr_end == 0) ? String(CONF_FREQ_END) : String(r.fr_end)); + // display.setTextAlignment(TEXT_ALIGN_RIGHT); + int16_t x0, y0; // Variables to store the top-left corner + uint16_t w, h0; // Variables to store width and height + String s = String(CONF_FREQ_END); + display.getTextBounds(s.c_str(), 0, 0, &x0, &y0, &w, &h0); + + display.setCursor(display.width() - w, text_y); + display.print((r.fr_end == 0) ? String(CONF_FREQ_END) : String(r.fr_end)); } // Status text block if (r.led_flag) // 'drone' detected { - display.setTextAlignment(TEXT_ALIGN_CENTER); - // clear status line + // display.setTextAlignment(TEXT_ALIGN_CENTER); + // clear status line clearStatus(); - display.setColor(WHITE); - display.drawString(pos_x + width / 2, text_y, - String(drone_detected_frequency_start) + ">RF<" + - String(drone_detected_frequency_end)); + display.setTextColor(WHITE); + String s = String(drone_detected_frequency_start) + ">RF<" + + String(drone_detected_frequency_end); + int16_t x0, y0; // Variables to store the top-left corner + uint16_t w, h0; // Variables to store width and height + display.getTextBounds(s.c_str(), 0, 0, &x0, &y0, &w, &h0); + + display.setCursor((display.width() - w) / 2, text_y); + display.print(s); } else { // "Scanning" - display.setTextAlignment(TEXT_ALIGN_CENTER); + /// display.setTextAlignment(TEXT_ALIGN_CENTER); // clear status line clearStatus(); String s = "Scan \\"; @@ -144,8 +156,16 @@ void StatusBar::draw() { scan_progress_count = 0; } - display.setColor(WHITE); - display.drawString(pos_x + width / 2 - 3, text_y, s); + display.setTextColor(WHITE); + int16_t x1, y1; + uint16_t w, h; + + // Measure the text dimensions + display.getTextBounds(s.c_str(), 0, text_y, &x1, &y1, &w, &h); + int x = (128 - w) / 2; + + display.setCursor(x, text_y); + display.print(s); } if (r.led_flag && r.detection_count >= 5) @@ -169,25 +189,34 @@ void StatusBar::draw() display.setTextAlignment(TEXT_ALIGN_LEFT); display.drawString(pos_x, text_y, String(loop_time)); #else - display.setTextAlignment(TEXT_ALIGN_LEFT); - display.drawString(pos_x, text_y, String(CONF_FREQ_BEGIN)); + // display.setTextAlignment(TEXT_ALIGN_LEFT); + display.setCursor(pos_x, text_y); + display.print(String(CONF_FREQ_BEGIN)); #endif - display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(pos_x + width, text_y, String(CONF_FREQ_END)); + // display.setTextAlignment(TEXT_ALIGN_RIGHT); + + int16_t x1, y1; + uint16_t w, h; + String end = String(CONF_FREQ_END); + // Measure the text dimensions + display.getTextBounds(end.c_str(), 0, text_y, &x1, &y1, &w, &h); + + display.setCursor(display.width() - w, text_y); + display.print(String(CONF_FREQ_END)); } else if (scan_pages_sz > 1) { - display.setTextAlignment(TEXT_ALIGN_LEFT); - display.drawString(pos_x, text_y, - String(scan_pages[scan_page].start_mhz) + "-" + - String(scan_pages[scan_page].end_mhz)); + // display.setTextAlignment(TEXT_ALIGN_LEFT); + display.setCursor(pos_x, text_y); + display.print(String(scan_pages[scan_page].start_mhz) + "-" + + String(scan_pages[scan_page].end_mhz)); if (scan_page + 1 < scan_pages_sz) { - display.setTextAlignment(TEXT_ALIGN_RIGHT); - display.drawString(pos_x + width, text_y, - String(scan_pages[scan_page + 1].start_mhz) + "-" + - String(scan_pages[scan_page + 1].end_mhz)); + // display.setTextAlignment(TEXT_ALIGN_RIGHT); + display.setCursor(pos_x + width, text_y); + display.print(String(scan_pages[scan_page + 1].start_mhz) + "-" + + String(scan_pages[scan_page + 1].end_mhz)); } } ui_initialized = true;