mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-15 06:17:47 +00:00
383 lines
15 KiB
C++
383 lines
15 KiB
C++
|
|
#include "DebugRenderer.h"
|
||
|
|
#include "../Screen.h"
|
||
|
|
#include "Throttle.h"
|
||
|
|
#include "UIRenderer.h"
|
||
|
|
#include "airtime.h"
|
||
|
|
#include "configuration.h"
|
||
|
|
#include "gps/RTC.h"
|
||
|
|
#include "graphics/ScreenFonts.h"
|
||
|
|
#include "graphics/SharedUIDisplay.h"
|
||
|
|
#include "graphics/images.h"
|
||
|
|
#include "main.h"
|
||
|
|
#include "mesh/Channels.h"
|
||
|
|
#include "mesh/generated/meshtastic/deviceonly.pb.h"
|
||
|
|
#include "sleep.h"
|
||
|
|
|
||
|
|
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||
|
|
#include "mesh/wifi/WiFiAPClient.h"
|
||
|
|
#include <WiFi.h>
|
||
|
|
#ifdef ARCH_ESP32
|
||
|
|
#include "mesh/wifi/WiFiAPClient.h"
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#ifdef ARCH_ESP32
|
||
|
|
#include "modules/StoreForwardModule.h"
|
||
|
|
#endif
|
||
|
|
|
||
|
|
using namespace meshtastic;
|
||
|
|
|
||
|
|
// Battery icon array
|
||
|
|
static uint8_t imgBattery[16] = {0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xE7, 0x3C};
|
||
|
|
|
||
|
|
// External variables
|
||
|
|
extern graphics::Screen *screen;
|
||
|
|
extern PowerStatus *powerStatus;
|
||
|
|
extern NodeStatus *nodeStatus;
|
||
|
|
extern GPSStatus *gpsStatus;
|
||
|
|
extern Channels channels;
|
||
|
|
extern const char *ourId;
|
||
|
|
extern AirTime *airTime;
|
||
|
|
|
||
|
|
// External functions from Screen.cpp
|
||
|
|
extern bool heartbeat;
|
||
|
|
|
||
|
|
#ifdef ARCH_ESP32
|
||
|
|
extern StoreForwardModule *storeForwardModule;
|
||
|
|
#endif
|
||
|
|
|
||
|
|
namespace graphics
|
||
|
|
{
|
||
|
|
namespace DebugRenderer
|
||
|
|
{
|
||
|
|
|
||
|
|
void drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||
|
|
{
|
||
|
|
display->setFont(FONT_SMALL);
|
||
|
|
|
||
|
|
// The coordinates define the left starting point of the text
|
||
|
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||
|
|
|
||
|
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
|
||
|
|
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||
|
|
display->setColor(BLACK);
|
||
|
|
}
|
||
|
|
|
||
|
|
char channelStr[20];
|
||
|
|
snprintf(channelStr, sizeof(channelStr), "#%s", channels.getName(channels.getPrimaryIndex()));
|
||
|
|
|
||
|
|
// Display power status
|
||
|
|
if (powerStatus->getHasBattery()) {
|
||
|
|
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||
|
|
UIRenderer::drawBattery(display, x, y + 2, imgBattery, powerStatus);
|
||
|
|
} else {
|
||
|
|
UIRenderer::drawBattery(display, x + 1, y + 3, imgBattery, powerStatus);
|
||
|
|
}
|
||
|
|
} else if (powerStatus->knowsUSB()) {
|
||
|
|
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||
|
|
display->drawFastImage(x, y + 2, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
|
||
|
|
} else {
|
||
|
|
display->drawFastImage(x + 1, y + 3, 16, 8, powerStatus->getHasUSB() ? imgUSB : imgPower);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Display nodes status
|
||
|
|
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||
|
|
UIRenderer::drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 2, nodeStatus);
|
||
|
|
} else {
|
||
|
|
UIRenderer::drawNodes(display, x + (SCREEN_WIDTH * 0.25), y + 3, nodeStatus);
|
||
|
|
}
|
||
|
|
#if HAS_GPS
|
||
|
|
// Display GPS status
|
||
|
|
if (config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||
|
|
UIRenderer::drawGPSpowerstat(display, x, y + 2, gpsStatus);
|
||
|
|
} else {
|
||
|
|
if (config.display.displaymode == meshtastic_Config_DisplayConfig_DisplayMode_DEFAULT) {
|
||
|
|
UIRenderer::drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 2, gpsStatus);
|
||
|
|
} else {
|
||
|
|
UIRenderer::drawGPS(display, x + (SCREEN_WIDTH * 0.63), y + 3, gpsStatus);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
display->setColor(WHITE);
|
||
|
|
// Draw the channel name
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL, channelStr);
|
||
|
|
// Draw our hardware ID to assist with bluetooth pairing. Either prefix with Info or S&F Logo
|
||
|
|
if (moduleConfig.store_forward.enabled) {
|
||
|
|
#ifdef ARCH_ESP32
|
||
|
|
if (!Throttle::isWithinTimespanMs(storeForwardModule->lastHeartbeat,
|
||
|
|
(storeForwardModule->heartbeatInterval * 1200))) { // no heartbeat, overlap a bit
|
||
|
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||
|
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
|
||
|
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||
|
|
imgQuestionL1);
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||
|
|
imgQuestionL2);
|
||
|
|
#else
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8,
|
||
|
|
imgQuestion);
|
||
|
|
#endif
|
||
|
|
} else {
|
||
|
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||
|
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS)) && \
|
||
|
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 16, 8,
|
||
|
|
imgSFL1);
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 18 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 16, 8,
|
||
|
|
imgSFL2);
|
||
|
|
#else
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 13 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 11, 8,
|
||
|
|
imgSF);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
} else {
|
||
|
|
// TODO: Raspberry Pi supports more than just the one screen size
|
||
|
|
#if (defined(USE_EINK) || defined(ILI9341_DRIVER) || defined(ILI9342_DRIVER) || defined(ST7701_CS) || defined(ST7735_CS) || \
|
||
|
|
defined(ST7789_CS) || defined(USE_ST7789) || defined(ILI9488_CS) || defined(HX8357_CS) || ARCH_PORTDUINO) && \
|
||
|
|
!defined(DISPLAY_FORCE_SMALL_FONTS)
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 3 + FONT_HEIGHT_SMALL, 12, 8,
|
||
|
|
imgInfoL1);
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 14 - display->getStringWidth(ourId), y + 11 + FONT_HEIGHT_SMALL, 12, 8,
|
||
|
|
imgInfoL2);
|
||
|
|
#else
|
||
|
|
display->drawFastImage(x + SCREEN_WIDTH - 10 - display->getStringWidth(ourId), y + 2 + FONT_HEIGHT_SMALL, 8, 8, imgInfo);
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(ourId), y + FONT_HEIGHT_SMALL, ourId);
|
||
|
|
|
||
|
|
// Draw any log messages
|
||
|
|
display->drawLogBuffer(x, y + (FONT_HEIGHT_SMALL * 2));
|
||
|
|
|
||
|
|
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
||
|
|
#ifdef SHOW_REDRAWS
|
||
|
|
if (heartbeat)
|
||
|
|
display->setPixel(0, 0);
|
||
|
|
heartbeat = !heartbeat;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
void drawFrameWiFi(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||
|
|
{
|
||
|
|
#if HAS_WIFI && !defined(ARCH_PORTDUINO)
|
||
|
|
const char *wifiName = config.network.wifi_ssid;
|
||
|
|
|
||
|
|
display->setFont(FONT_SMALL);
|
||
|
|
|
||
|
|
// The coordinates define the left starting point of the text
|
||
|
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||
|
|
|
||
|
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
|
||
|
|
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||
|
|
display->setColor(BLACK);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (WiFi.status() != WL_CONNECTED) {
|
||
|
|
display->drawString(x, y, String("WiFi: Not Connected"));
|
||
|
|
if (config.display.heading_bold)
|
||
|
|
display->drawString(x + 1, y, String("WiFi: Not Connected"));
|
||
|
|
} else {
|
||
|
|
display->drawString(x, y, String("WiFi: Connected"));
|
||
|
|
if (config.display.heading_bold)
|
||
|
|
display->drawString(x + 1, y, String("WiFi: Connected"));
|
||
|
|
|
||
|
|
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())), y,
|
||
|
|
"RSSI " + String(WiFi.RSSI()));
|
||
|
|
if (config.display.heading_bold) {
|
||
|
|
display->drawString(x + SCREEN_WIDTH - display->getStringWidth("RSSI " + String(WiFi.RSSI())) - 1, y,
|
||
|
|
"RSSI " + String(WiFi.RSSI()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
display->setColor(WHITE);
|
||
|
|
|
||
|
|
/*
|
||
|
|
- WL_CONNECTED: assigned when connected to a WiFi network;
|
||
|
|
- WL_NO_SSID_AVAIL: assigned when no SSID are available;
|
||
|
|
- WL_CONNECT_FAILED: assigned when the connection fails for all the attempts;
|
||
|
|
- WL_CONNECTION_LOST: assigned when the connection is lost;
|
||
|
|
- WL_DISCONNECTED: assigned when disconnected from a network;
|
||
|
|
- WL_IDLE_STATUS: it is a temporary status assigned when WiFi.begin() is called and remains active until the number of
|
||
|
|
attempts expires (resulting in WL_CONNECT_FAILED) or a connection is established (resulting in WL_CONNECTED);
|
||
|
|
- WL_SCAN_COMPLETED: assigned when the scan networks is completed;
|
||
|
|
- WL_NO_SHIELD: assigned when no WiFi shield is present;
|
||
|
|
|
||
|
|
*/
|
||
|
|
if (WiFi.status() == WL_CONNECTED) {
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "IP: " + String(WiFi.localIP().toString().c_str()));
|
||
|
|
} else if (WiFi.status() == WL_NO_SSID_AVAIL) {
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "SSID Not Found");
|
||
|
|
} else if (WiFi.status() == WL_CONNECTION_LOST) {
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Lost");
|
||
|
|
} else if (WiFi.status() == WL_IDLE_STATUS) {
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Idle ... Reconnecting");
|
||
|
|
} else if (WiFi.status() == WL_CONNECT_FAILED) {
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Connection Failed");
|
||
|
|
}
|
||
|
|
#ifdef ARCH_ESP32
|
||
|
|
else {
|
||
|
|
// Codes:
|
||
|
|
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-guides/wifi.html#wi-fi-reason-code
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1,
|
||
|
|
WiFi.disconnectReasonName(static_cast<wifi_err_reason_t>(getWifiDisconnectReason())));
|
||
|
|
}
|
||
|
|
#else
|
||
|
|
else {
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, "Unkown status: " + String(WiFi.status()));
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 2, "SSID: " + String(wifiName));
|
||
|
|
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 3, "http://meshtastic.local");
|
||
|
|
|
||
|
|
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
||
|
|
#ifdef SHOW_REDRAWS
|
||
|
|
if (heartbeat)
|
||
|
|
display->setPixel(0, 0);
|
||
|
|
heartbeat = !heartbeat;
|
||
|
|
#endif
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
void drawFrameSettings(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||
|
|
{
|
||
|
|
display->setFont(FONT_SMALL);
|
||
|
|
|
||
|
|
// The coordinates define the left starting point of the text
|
||
|
|
display->setTextAlignment(TEXT_ALIGN_LEFT);
|
||
|
|
|
||
|
|
if (config.display.displaymode != meshtastic_Config_DisplayConfig_DisplayMode_INVERTED) {
|
||
|
|
display->fillRect(0 + x, 0 + y, x + display->getWidth(), y + FONT_HEIGHT_SMALL);
|
||
|
|
display->setColor(BLACK);
|
||
|
|
}
|
||
|
|
|
||
|
|
char batStr[20];
|
||
|
|
if (powerStatus->getHasBattery()) {
|
||
|
|
int batV = powerStatus->getBatteryVoltageMv() / 1000;
|
||
|
|
int batCv = (powerStatus->getBatteryVoltageMv() % 1000) / 10;
|
||
|
|
|
||
|
|
snprintf(batStr, sizeof(batStr), "B %01d.%02dV %3d%% %c%c", batV, batCv, powerStatus->getBatteryChargePercent(),
|
||
|
|
powerStatus->getIsCharging() ? '+' : ' ', powerStatus->getHasUSB() ? 'U' : ' ');
|
||
|
|
|
||
|
|
// Line 1
|
||
|
|
display->drawString(x, y, batStr);
|
||
|
|
if (config.display.heading_bold)
|
||
|
|
display->drawString(x + 1, y, batStr);
|
||
|
|
} else {
|
||
|
|
// Line 1
|
||
|
|
display->drawString(x, y, String("USB"));
|
||
|
|
if (config.display.heading_bold)
|
||
|
|
display->drawString(x + 1, y, String("USB"));
|
||
|
|
}
|
||
|
|
|
||
|
|
// auto mode = DisplayFormatters::getModemPresetDisplayName(config.lora.modem_preset, true);
|
||
|
|
|
||
|
|
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode), y, mode);
|
||
|
|
// if (config.display.heading_bold)
|
||
|
|
// display->drawString(x + SCREEN_WIDTH - display->getStringWidth(mode) - 1, y, mode);
|
||
|
|
|
||
|
|
uint32_t currentMillis = millis();
|
||
|
|
uint32_t seconds = currentMillis / 1000;
|
||
|
|
uint32_t minutes = seconds / 60;
|
||
|
|
uint32_t hours = minutes / 60;
|
||
|
|
uint32_t days = hours / 24;
|
||
|
|
// currentMillis %= 1000;
|
||
|
|
// seconds %= 60;
|
||
|
|
// minutes %= 60;
|
||
|
|
// hours %= 24;
|
||
|
|
|
||
|
|
// Show uptime as days, hours, minutes OR seconds
|
||
|
|
std::string uptime = screen->drawTimeDelta(days, hours, minutes, seconds);
|
||
|
|
|
||
|
|
// Line 1 (Still)
|
||
|
|
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||
|
|
if (config.display.heading_bold)
|
||
|
|
display->drawString(x - 1 + SCREEN_WIDTH - display->getStringWidth(uptime.c_str()), y, uptime.c_str());
|
||
|
|
|
||
|
|
display->setColor(WHITE);
|
||
|
|
|
||
|
|
// Setup string to assemble analogClock string
|
||
|
|
std::string analogClock = "";
|
||
|
|
|
||
|
|
uint32_t rtc_sec = getValidTime(RTCQuality::RTCQualityDevice, true); // Display local timezone
|
||
|
|
if (rtc_sec > 0) {
|
||
|
|
long hms = rtc_sec % SEC_PER_DAY;
|
||
|
|
// hms += tz.tz_dsttime * SEC_PER_HOUR;
|
||
|
|
// hms -= tz.tz_minuteswest * SEC_PER_MIN;
|
||
|
|
// mod `hms` to ensure in positive range of [0...SEC_PER_DAY)
|
||
|
|
hms = (hms + SEC_PER_DAY) % SEC_PER_DAY;
|
||
|
|
|
||
|
|
// Tear apart hms into h:m:s
|
||
|
|
int hour = hms / SEC_PER_HOUR;
|
||
|
|
int min = (hms % SEC_PER_HOUR) / SEC_PER_MIN;
|
||
|
|
int sec = (hms % SEC_PER_HOUR) % SEC_PER_MIN; // or hms % SEC_PER_MIN
|
||
|
|
|
||
|
|
char timebuf[12];
|
||
|
|
|
||
|
|
if (config.display.use_12h_clock) {
|
||
|
|
std::string meridiem = "am";
|
||
|
|
if (hour >= 12) {
|
||
|
|
if (hour > 12)
|
||
|
|
hour -= 12;
|
||
|
|
meridiem = "pm";
|
||
|
|
}
|
||
|
|
if (hour == 00) {
|
||
|
|
hour = 12;
|
||
|
|
}
|
||
|
|
snprintf(timebuf, sizeof(timebuf), "%d:%02d:%02d%s", hour, min, sec, meridiem.c_str());
|
||
|
|
} else {
|
||
|
|
snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d", hour, min, sec);
|
||
|
|
}
|
||
|
|
analogClock += timebuf;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Line 2
|
||
|
|
display->drawString(x, y + FONT_HEIGHT_SMALL * 1, analogClock.c_str());
|
||
|
|
|
||
|
|
// Display Channel Utilization
|
||
|
|
char chUtil[13];
|
||
|
|
snprintf(chUtil, sizeof(chUtil), "ChUtil %2.0f%%", airTime->channelUtilizationPercent());
|
||
|
|
display->drawString(x + SCREEN_WIDTH - display->getStringWidth(chUtil), y + FONT_HEIGHT_SMALL * 1, chUtil);
|
||
|
|
|
||
|
|
#if HAS_GPS
|
||
|
|
if (config.position.gps_mode == meshtastic_Config_PositionConfig_GpsMode_ENABLED) {
|
||
|
|
// Line 3
|
||
|
|
if (config.display.gps_format !=
|
||
|
|
meshtastic_Config_DisplayConfig_GpsCoordinateFormat_DMS) // if DMS then don't draw altitude
|
||
|
|
UIRenderer::drawGPSAltitude(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
||
|
|
|
||
|
|
// Line 4
|
||
|
|
UIRenderer::drawGPScoordinates(display, x, y + FONT_HEIGHT_SMALL * 3, gpsStatus);
|
||
|
|
} else {
|
||
|
|
UIRenderer::drawGPSpowerstat(display, x, y + FONT_HEIGHT_SMALL * 2, gpsStatus);
|
||
|
|
}
|
||
|
|
#endif
|
||
|
|
/* Display a heartbeat pixel that blinks every time the frame is redrawn */
|
||
|
|
#ifdef SHOW_REDRAWS
|
||
|
|
if (heartbeat)
|
||
|
|
display->setPixel(0, 0);
|
||
|
|
heartbeat = !heartbeat;
|
||
|
|
#endif
|
||
|
|
}
|
||
|
|
|
||
|
|
// Trampoline functions for DebugInfo class access
|
||
|
|
void drawDebugInfoTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||
|
|
{
|
||
|
|
drawFrame(display, state, x, y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void drawDebugInfoSettingsTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||
|
|
{
|
||
|
|
drawFrameSettings(display, state, x, y);
|
||
|
|
}
|
||
|
|
|
||
|
|
void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y)
|
||
|
|
{
|
||
|
|
drawFrameWiFi(display, state, x, y);
|
||
|
|
}
|
||
|
|
|
||
|
|
} // namespace DebugRenderer
|
||
|
|
} // namespace graphics
|