From 531cad5e8873639d8fe147d2f58f3dbf554d9610 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 7 Nov 2025 15:03:56 -0600 Subject: [PATCH] Add API types, state, and log message in Debug screen. Added persistent "Connected" icon (#8576) * Add API types, state, and log message in Debug screen * un-goober the API state tracking * Set the SerialConsole api_type * Add api_type for Ethernet * Remove API state debugging code * Update wording for client connection states * Improve string width for smaller screen devices * Reserve space on navigation bar to fit link indicator * Add persistent Connected icon to screen * Connect System frame to ensure text doesn't overflow --------- Co-authored-by: Ben Meadors Co-authored-by: Jason P Co-authored-by: HarukiToreda <116696711+HarukiToreda@users.noreply.github.com> --- src/SerialConsole.cpp | 1 + src/graphics/SharedUIDisplay.cpp | 39 ++++++++++++++ src/graphics/SharedUIDisplay.h | 3 ++ src/graphics/draw/ClockRenderer.cpp | 3 ++ src/graphics/draw/DebugRenderer.cpp | 47 ++++++++++++++--- src/graphics/draw/MessageRenderer.cpp | 2 + src/graphics/draw/NodeListRenderer.cpp | 1 + src/graphics/draw/UIRenderer.cpp | 52 ++++++++++++++++++- src/graphics/images.h | 4 ++ src/mesh/MeshService.h | 12 +++++ src/mesh/PhoneAPI.cpp | 25 +++++++++ src/mesh/PhoneAPI.h | 12 +++++ src/mesh/api/PacketAPI.cpp | 1 + src/mesh/api/WiFiServerAPI.cpp | 1 + src/mesh/api/ethServerAPI.cpp | 1 + src/mesh/http/ContentHandler.h | 2 +- src/mesh/raspihttp/PiWebServer.h | 2 +- src/modules/SerialModule.cpp | 15 ++++-- .../Telemetry/EnvironmentTelemetry.cpp | 1 + src/modules/Telemetry/PowerTelemetry.cpp | 1 + src/modules/esp32/PaxcounterModule.cpp | 1 + src/nimble/NimbleBluetooth.cpp | 2 +- src/platform/nrf52/NRF52Bluetooth.cpp | 3 ++ 23 files changed, 218 insertions(+), 13 deletions(-) diff --git a/src/SerialConsole.cpp b/src/SerialConsole.cpp index fad0fb92f..dd2acb599 100644 --- a/src/SerialConsole.cpp +++ b/src/SerialConsole.cpp @@ -50,6 +50,7 @@ void consolePrintf(const char *format, ...) SerialConsole::SerialConsole() : StreamAPI(&Port), RedirectablePrint(&Port), concurrency::OSThread("SerialConsole") { + api_type = TYPE_SERIAL; assert(!console); console = this; canWrite = false; // We don't send packets to our port until it has talked to us first diff --git a/src/graphics/SharedUIDisplay.cpp b/src/graphics/SharedUIDisplay.cpp index 8e1299f51..1645789a7 100644 --- a/src/graphics/SharedUIDisplay.cpp +++ b/src/graphics/SharedUIDisplay.cpp @@ -1,6 +1,8 @@ #include "configuration.h" #if HAS_SCREEN +#include "MeshService.h" #include "RTC.h" +#include "draw/NodeListRenderer.h" #include "graphics/ScreenFonts.h" #include "graphics/SharedUIDisplay.h" #include "graphics/draw/UIRenderer.h" @@ -398,6 +400,43 @@ const int *getTextPositions(OLEDDisplay *display) return textPositions; } +// ************************* +// * Common Footer Drawing * +// ************************* +void drawCommonFooter(OLEDDisplay *display, int16_t x, int16_t y) +{ + bool drawConnectionState = false; + if (service->api_state == service->STATE_BLE || service->api_state == service->STATE_WIFI || + service->api_state == service->STATE_SERIAL || service->api_state == service->STATE_PACKET || + service->api_state == service->STATE_HTTP || service->api_state == service->STATE_ETH) { + drawConnectionState = true; + } + + if (drawConnectionState) { + if (isHighResolution) { + const int scale = 2; + const int bytesPerRow = (connection_icon_width + 7) / 8; + int iconX = 0; + int iconY = SCREEN_HEIGHT - (connection_icon_height * 2); + + for (int yy = 0; yy < connection_icon_height; ++yy) { + const uint8_t *rowPtr = connection_icon + yy * bytesPerRow; + for (int xx = 0; xx < connection_icon_width; ++xx) { + const uint8_t byteVal = pgm_read_byte(rowPtr + (xx >> 3)); + const uint8_t bitMask = 1U << (xx & 7); // XBM is LSB-first + if (byteVal & bitMask) { + display->fillRect(iconX + xx * scale, iconY + yy * scale, scale, scale); + } + } + } + + } else { + display->drawXbm(0, SCREEN_HEIGHT - connection_icon_height, connection_icon_width, connection_icon_height, + connection_icon); + } + } +} + bool isAllowedPunctuation(char c) { const std::string allowed = ".,!?;:-_()[]{}'\"@#$/\\&+=%~^ "; diff --git a/src/graphics/SharedUIDisplay.h b/src/graphics/SharedUIDisplay.h index e1a7c6383..b51dfea36 100644 --- a/src/graphics/SharedUIDisplay.h +++ b/src/graphics/SharedUIDisplay.h @@ -52,6 +52,9 @@ void drawRoundedHighlight(OLEDDisplay *display, int16_t x, int16_t y, int16_t w, void drawCommonHeader(OLEDDisplay *display, int16_t x, int16_t y, const char *titleStr = "", bool force_no_invert = false, bool show_date = false); +// Shared battery/time/mail header +void drawCommonFooter(OLEDDisplay *display, int16_t x, int16_t y); + const int *getTextPositions(OLEDDisplay *display); bool isAllowedPunctuation(char c); diff --git a/src/graphics/draw/ClockRenderer.cpp b/src/graphics/draw/ClockRenderer.cpp index 751db8d88..97417571b 100644 --- a/src/graphics/draw/ClockRenderer.cpp +++ b/src/graphics/draw/ClockRenderer.cpp @@ -302,6 +302,8 @@ void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int1 display->drawString(startingHourMinuteTextX + timeStringWidth - xOffset, (display->getHeight() - hourMinuteTextY) - yOffset, secondString); #endif + + graphics::drawCommonFooter(display, x, y); } void drawBluetoothConnectedIcon(OLEDDisplay *display, int16_t x, int16_t y) @@ -516,6 +518,7 @@ void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 display->drawLine(centerX, centerY, secondX, secondY); #endif } + graphics::drawCommonFooter(display, x, y); } } // namespace ClockRenderer diff --git a/src/graphics/draw/DebugRenderer.cpp b/src/graphics/draw/DebugRenderer.cpp index 60abd661e..d098fa304 100644 --- a/src/graphics/draw/DebugRenderer.cpp +++ b/src/graphics/draw/DebugRenderer.cpp @@ -3,6 +3,7 @@ #include "../Screen.h" #include "DebugRenderer.h" #include "FSCommon.h" +#include "MeshService.h" #include "NodeDB.h" #include "Throttle.h" #include "UIRenderer.h" @@ -223,6 +224,8 @@ void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, i display->drawString(x, getTextPositions(display)[line++], "URL: http://meshtastic.local"); + graphics::drawCommonFooter(display, x, y); + /* Display a heartbeat pixel that blinks every time the frame is redrawn */ #ifdef SHOW_REDRAWS if (heartbeat) @@ -503,6 +506,7 @@ void drawLoRaFocused(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, display->drawString(starting_position + chUtil_x + chutil_bar_width + extraoffset, getTextPositions(display)[line++], chUtilPercentage); #endif + graphics::drawCommonFooter(display, x, y); } // **************************** @@ -642,10 +646,9 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x int textWidth = display->getStringWidth(appversionstr); int nameX = (SCREEN_WIDTH - textWidth) / 2; - display->drawString(nameX, getTextPositions(display)[line], appversionstr); -#if !defined(M5STACK_UNITC6L) - if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line < 4)) { // Only show uptime if the screen can show it - line += 1; + display->drawString(nameX, getTextPositions(display)[line++], appversionstr); + + if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line <= 5)) { // Only show uptime if the screen can show it char uptimeStr[32] = ""; uint32_t uptime = millis() / 1000; uint32_t days = uptime / 86400; @@ -660,9 +663,41 @@ void drawSystemScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x snprintf(uptimeStr, sizeof(uptimeStr), " Uptime: %um", mins); textWidth = display->getStringWidth(uptimeStr); nameX = (SCREEN_WIDTH - textWidth) / 2; - display->drawString(nameX, getTextPositions(display)[line], uptimeStr); + display->drawString(nameX, getTextPositions(display)[line++], uptimeStr); } -#endif + + if (SCREEN_HEIGHT > 64 || (SCREEN_HEIGHT <= 64 && line <= 5)) { // Only show API state if the screen can show it + char api_state[32] = ""; + const char *clientWord = nullptr; + + // Determine if narrow or wide screen + if (isHighResolution) { + clientWord = "Client"; + } else { + clientWord = "App"; + } + snprintf(api_state, sizeof(api_state), "No %ss Connected", clientWord); + + if (service->api_state == service->STATE_BLE) { + snprintf(api_state, sizeof(api_state), "%s Connected (BLE)", clientWord); + } else if (service->api_state == service->STATE_WIFI) { + snprintf(api_state, sizeof(api_state), "%s Connected (WiFi)", clientWord); + } else if (service->api_state == service->STATE_SERIAL) { + snprintf(api_state, sizeof(api_state), "%s Connected (Serial)", clientWord); + } else if (service->api_state == service->STATE_PACKET) { + snprintf(api_state, sizeof(api_state), "%s Connected (Internal)", clientWord); + } else if (service->api_state == service->STATE_HTTP) { + snprintf(api_state, sizeof(api_state), "%s Connected (HTTP)", clientWord); + } else if (service->api_state == service->STATE_ETH) { + snprintf(api_state, sizeof(api_state), "%s Connected (Ethernet)", clientWord); + } + if (api_state[0] != '\0') { + display->drawString((SCREEN_WIDTH - display->getStringWidth(api_state)) / 2, getTextPositions(display)[line++], + api_state); + } + } + + graphics::drawCommonFooter(display, x, y); } // **************************** diff --git a/src/graphics/draw/MessageRenderer.cpp b/src/graphics/draw/MessageRenderer.cpp index 6971826de..da6ec7abc 100644 --- a/src/graphics/draw/MessageRenderer.cpp +++ b/src/graphics/draw/MessageRenderer.cpp @@ -213,6 +213,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 #else display->drawString(center_text, getTextPositions(display)[2], messageString); #endif + graphics::drawCommonFooter(display, x, y); return; } @@ -423,6 +424,7 @@ void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16 // Draw header at the end to sort out overlapping elements graphics::drawCommonHeader(display, x, y, titleStr); #endif + graphics::drawCommonFooter(display, x, y); } std::vector generateLines(OLEDDisplay *display, const char *headerStr, const char *messageBuf, int textWidth) diff --git a/src/graphics/draw/NodeListRenderer.cpp b/src/graphics/draw/NodeListRenderer.cpp index 2a2f71dba..1a36a6188 100644 --- a/src/graphics/draw/NodeListRenderer.cpp +++ b/src/graphics/draw/NodeListRenderer.cpp @@ -505,6 +505,7 @@ void drawNodeListScreen(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t #endif const int scrollStartY = y + 3; drawScrollbar(display, visibleNodeRows, totalEntries, scrollIndex, 2, scrollStartY); + graphics::drawCommonFooter(display, x, y); } // ============================= diff --git a/src/graphics/draw/UIRenderer.cpp b/src/graphics/draw/UIRenderer.cpp index 1ff183779..538c32842 100644 --- a/src/graphics/draw/UIRenderer.cpp +++ b/src/graphics/draw/UIRenderer.cpp @@ -552,6 +552,7 @@ void UIRenderer::drawNodeInfo(OLEDDisplay *display, const OLEDDisplayUiState *st // else show nothing } #endif + graphics::drawCommonFooter(display, x, y); } // **************************** @@ -771,6 +772,7 @@ void UIRenderer::drawDeviceFocused(OLEDDisplay *display, OLEDDisplayUiState *sta display->drawString(nameX, getTextPositions(display)[line++], shortnameble); } #endif + graphics::drawCommonFooter(display, x, y); } // Start Functions to write date/time to the screen @@ -1183,6 +1185,7 @@ void UIRenderer::drawCompassAndLocationScreen(OLEDDisplay *display, OLEDDisplayU } #endif #endif // HAS_GPS + graphics::drawCommonFooter(display, x, y); } #ifdef USERPREFS_OEM_TEXT @@ -1267,7 +1270,13 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta if (totalIcons == 0) return; - const size_t iconsPerPage = (SCREEN_WIDTH + spacing) / (iconSize + spacing); + const int navPadding = isHighResolution ? 24 : 12; // padding per side + + int usableWidth = SCREEN_WIDTH - (navPadding * 2); + if (usableWidth < iconSize) + usableWidth = iconSize; + + const size_t iconsPerPage = usableWidth / (iconSize + spacing); const size_t currentPage = currentFrame / iconsPerPage; const size_t pageStart = currentPage * iconsPerPage; const size_t pageEnd = min(pageStart + iconsPerPage, totalIcons); @@ -1338,6 +1347,47 @@ void UIRenderer::drawNavigationBar(OLEDDisplay *display, OLEDDisplayUiState *sta display->setColor(WHITE); } } + + // Compact arrow drawer + auto drawArrow = [&](bool rightSide) { + display->setColor(WHITE); + + const int offset = isHighResolution ? 3 : 1; + const int halfH = rectHeight / 2; + + const int top = (y - 2) + (rectHeight - halfH) / 2; + const int bottom = top + halfH - 1; + const int midY = top + (halfH / 2); + + const int maxW = 4; + + // Determine left X coordinate + int baseX = rightSide ? (rectX + rectWidth + offset) : // right arrow + (rectX - offset - 1); // left arrow + + for (int yy = top; yy <= bottom; yy++) { + int dist = abs(yy - midY); + int lineW = maxW - (dist * maxW / (halfH / 2)); + if (lineW < 1) + lineW = 1; + + if (rightSide) { + display->drawHorizontalLine(baseX, yy, lineW); + } else { + display->drawHorizontalLine(baseX - lineW + 1, yy, lineW); + } + } + }; + // Right arrow + if (pageEnd < totalIcons) { + drawArrow(true); + } + + // Left arrow + if (pageStart > 0) { + drawArrow(false); + } + // Knock the corners off the square display->setColor(BLACK); display->drawRect(rectX, y - 2, 1, 1); diff --git a/src/graphics/images.h b/src/graphics/images.h index b5010b116..8670d78d9 100644 --- a/src/graphics/images.h +++ b/src/graphics/images.h @@ -360,6 +360,10 @@ const uint8_t chirpy_hirez[] = { #define chirpy_small_image_height 8 const uint8_t chirpy_small[] = {0x7f, 0x41, 0x55, 0x55, 0x55, 0x55, 0x41, 0x7f}; +#define connection_icon_width 7 +#define connection_icon_height 5 +const uint8_t connection_icon[] = {0x36, 0x41, 0x5D, 0x41, 0x36}; + #ifdef M5STACK_UNITC6L #include "img/icon_small.xbm" #else diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 66d9d9679..71fb544a0 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -79,6 +79,18 @@ class MeshService uint32_t oldFromNum = 0; public: + enum APIState { + STATE_DISCONNECTED, // Initial state, no API is connected + STATE_BLE, + STATE_WIFI, + STATE_SERIAL, + STATE_PACKET, + STATE_HTTP, + STATE_ETH + }; + + APIState api_state = STATE_DISCONNECTED; + static bool isTextPayload(const meshtastic_MeshPacket *p) { if (moduleConfig.range_test.enabled && p->decoded.portnum == meshtastic_PortNum_RANGE_TEST_APP) { diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index d1e342c80..9050ee89d 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -87,6 +87,18 @@ void PhoneAPI::handleStartConfig() void PhoneAPI::close() { LOG_DEBUG("PhoneAPI::close()"); + if (service->api_state == service->STATE_BLE && api_type == TYPE_BLE) + service->api_state = service->STATE_DISCONNECTED; + else if (service->api_state == service->STATE_WIFI && api_type == TYPE_WIFI) + service->api_state = service->STATE_DISCONNECTED; + else if (service->api_state == service->STATE_SERIAL && api_type == TYPE_SERIAL) + service->api_state = service->STATE_DISCONNECTED; + else if (service->api_state == service->STATE_PACKET && api_type == TYPE_PACKET) + service->api_state = service->STATE_DISCONNECTED; + else if (service->api_state == service->STATE_HTTP && api_type == TYPE_HTTP) + service->api_state = service->STATE_DISCONNECTED; + else if (service->api_state == service->STATE_ETH && api_type == TYPE_ETH) + service->api_state = service->STATE_DISCONNECTED; if (state != STATE_SEND_NOTHING) { state = STATE_SEND_NOTHING; @@ -578,6 +590,19 @@ void PhoneAPI::sendConfigComplete() fromRadioScratch.config_complete_id = config_nonce; config_nonce = 0; state = STATE_SEND_PACKETS; + if (api_type == TYPE_BLE) { + service->api_state = service->STATE_BLE; + } else if (api_type == TYPE_WIFI) { + service->api_state = service->STATE_WIFI; + } else if (api_type == TYPE_SERIAL) { + service->api_state = service->STATE_SERIAL; + } else if (api_type == TYPE_PACKET) { + service->api_state = service->STATE_PACKET; + } else if (api_type == TYPE_HTTP) { + service->api_state = service->STATE_HTTP; + } else if (api_type == TYPE_ETH) { + service->api_state = service->STATE_ETH; + } // Allow subclasses to know we've entered steady-state so they can lower power consumption onConfigComplete(); diff --git a/src/mesh/PhoneAPI.h b/src/mesh/PhoneAPI.h index d6682684f..7f79b5792 100644 --- a/src/mesh/PhoneAPI.h +++ b/src/mesh/PhoneAPI.h @@ -167,6 +167,18 @@ class PhoneAPI /// begin a new connection void handleStartConfig(); + enum APIType { + TYPE_NONE, // Initial state, don't send anything until the client starts asking for config + TYPE_BLE, + TYPE_WIFI, + TYPE_SERIAL, + TYPE_PACKET, + TYPE_HTTP, + TYPE_ETH + }; + + APIType api_type = TYPE_NONE; + private: void releasePhonePacket(); diff --git a/src/mesh/api/PacketAPI.cpp b/src/mesh/api/PacketAPI.cpp index ab380d696..f4d5de540 100644 --- a/src/mesh/api/PacketAPI.cpp +++ b/src/mesh/api/PacketAPI.cpp @@ -19,6 +19,7 @@ PacketAPI *PacketAPI::create(PacketServer *_server) PacketAPI::PacketAPI(PacketServer *_server) : concurrency::OSThread("PacketAPI"), isConnected(false), programmingMode(false), server(_server) { + api_type = TYPE_PACKET; } int32_t PacketAPI::runOnce() diff --git a/src/mesh/api/WiFiServerAPI.cpp b/src/mesh/api/WiFiServerAPI.cpp index b19194f78..4d729f5c7 100644 --- a/src/mesh/api/WiFiServerAPI.cpp +++ b/src/mesh/api/WiFiServerAPI.cpp @@ -25,6 +25,7 @@ void deInitApiServer() WiFiServerAPI::WiFiServerAPI(WiFiClient &_client) : ServerAPI(_client) { + api_type = TYPE_WIFI; LOG_INFO("Incoming wifi connection"); } diff --git a/src/mesh/api/ethServerAPI.cpp b/src/mesh/api/ethServerAPI.cpp index 0ccf92df7..10ff06df2 100644 --- a/src/mesh/api/ethServerAPI.cpp +++ b/src/mesh/api/ethServerAPI.cpp @@ -20,6 +20,7 @@ void initApiServer(int port) ethServerAPI::ethServerAPI(EthernetClient &_client) : ServerAPI(_client) { LOG_INFO("Incoming ethernet connection"); + api_type = TYPE_ETH; } ethServerPort::ethServerPort(int port) : APIServerPort(port) {} diff --git a/src/mesh/http/ContentHandler.h b/src/mesh/http/ContentHandler.h index 2066a6d57..91cad3359 100644 --- a/src/mesh/http/ContentHandler.h +++ b/src/mesh/http/ContentHandler.h @@ -26,7 +26,7 @@ class HttpAPI : public PhoneAPI { public: - // Nothing here yet + HttpAPI() { api_type = TYPE_HTTP; } private: // Nothing here yet diff --git a/src/mesh/raspihttp/PiWebServer.h b/src/mesh/raspihttp/PiWebServer.h index b45348cf3..5a4adedaa 100644 --- a/src/mesh/raspihttp/PiWebServer.h +++ b/src/mesh/raspihttp/PiWebServer.h @@ -27,7 +27,7 @@ class HttpAPI : public PhoneAPI { public: - // Nothing here yet + HttpAPI() { api_type = TYPE_HTTP; } private: // Nothing here yet diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index a9ec8f6a8..575e9fa96 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -65,13 +65,22 @@ SerialModuleRadio *serialModuleRadio; #if defined(TTGO_T_ECHO) || defined(CANARYONE) || defined(MESHLINK) || defined(ELECROW_ThinkNode_M1) || \ defined(ELECROW_ThinkNode_M5) || defined(HELTEC_MESH_SOLAR) || defined(T_ECHO_LITE) -SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") {} +SerialModule::SerialModule() : StreamAPI(&Serial), concurrency::OSThread("Serial") +{ + api_type = TYPE_SERIAL; +} static Print *serialPrint = &Serial; #elif defined(CONFIG_IDF_TARGET_ESP32C6) || defined(RAK3172) || defined(EBYTE_E77_MBL) -SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") {} +SerialModule::SerialModule() : StreamAPI(&Serial1), concurrency::OSThread("Serial") +{ + api_type = TYPE_SERIAL; +} static Print *serialPrint = &Serial1; #else -SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("Serial") {} +SerialModule::SerialModule() : StreamAPI(&Serial2), concurrency::OSThread("Serial") +{ + api_type = TYPE_SERIAL; +} static Print *serialPrint = &Serial2; #endif diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index a923ab457..29e815092 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -517,6 +517,7 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt currentY += rowHeight; } + graphics::drawCommonFooter(display, x, y); } #endif diff --git a/src/modules/Telemetry/PowerTelemetry.cpp b/src/modules/Telemetry/PowerTelemetry.cpp index e69ee3931..29dd1def8 100644 --- a/src/modules/Telemetry/PowerTelemetry.cpp +++ b/src/modules/Telemetry/PowerTelemetry.cpp @@ -165,6 +165,7 @@ void PowerTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *s if (m.has_ch3_voltage || m.has_ch3_current) { drawLine("Ch3", m.ch3_voltage, m.ch3_current); } + graphics::drawCommonFooter(display, x, y); } #endif diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 8b1fc5302..9c25177bc 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -141,6 +141,7 @@ void PaxcounterModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state display->drawStringf(display->getWidth() / 2 + x, graphics::getTextPositions(display)[line++], buffer, "WiFi: %d\nBLE: %d\nUptime: %ds", count_from_libpax.wifi_count, count_from_libpax.ble_count, millis() / 1000); + graphics::drawCommonFooter(display, x, y); } #endif // HAS_SCREEN diff --git a/src/nimble/NimbleBluetooth.cpp b/src/nimble/NimbleBluetooth.cpp index 6238031f6..76cde3cae 100644 --- a/src/nimble/NimbleBluetooth.cpp +++ b/src/nimble/NimbleBluetooth.cpp @@ -118,7 +118,7 @@ class BluetoothPhoneAPI : public PhoneAPI, public concurrency::OSThread */ public: - BluetoothPhoneAPI() : concurrency::OSThread("NimbleBluetooth") {} + BluetoothPhoneAPI() : concurrency::OSThread("NimbleBluetooth") { api_type = TYPE_BLE; } /* Packets from phone (BLE onWrite callback) */ std::mutex fromPhoneMutex; diff --git a/src/platform/nrf52/NRF52Bluetooth.cpp b/src/platform/nrf52/NRF52Bluetooth.cpp index 79eef8f76..4f7fb4776 100644 --- a/src/platform/nrf52/NRF52Bluetooth.cpp +++ b/src/platform/nrf52/NRF52Bluetooth.cpp @@ -48,6 +48,9 @@ class BluetoothPhoneAPI : public PhoneAPI /// Check the current underlying physical link to see if the client is currently connected virtual bool checkIsConnected() override { return Bluefruit.connected(connectionHandle); } + + public: + BluetoothPhoneAPI() { api_type = TYPE_BLE; } }; static BluetoothPhoneAPI *bluetoothPhoneAPI;