Phase 4: Expunge STM32: TX device cleanup (#3024)
[ExpressLRS.git] / src / lib / SCREEN / OLED / oleddisplay.cpp
blob6a0ba7573e3c3999c34c1927cbafb220c836d559
1 #if defined(PLATFORM_ESP32)
3 #include <U8g2lib.h> // Needed for the OLED drivers, this is a arduino package. It is maintained by platformIO
5 #include "oleddisplay.h"
7 #include "XBMStrings.h" // Contains all the ELRS logos and animations for the UI
8 #include "options.h"
9 #include "logging.h"
10 #include "common.h"
11 #include "CRSF.h"
13 #include "WiFi.h"
14 extern WiFiMode_t wifiMode;
16 // OLED specific header files.
17 U8G2 *u8g2;
19 static void helperDrawImage(menu_item_t menu);
20 static void drawCentered(u8g2_int_t y, const char *str)
22 u8g2_int_t x = (u8g2->getDisplayWidth() - u8g2->getStrWidth(str)) / 2;
23 u8g2->drawStr(x, y, str);
26 void OLEDDisplay::init()
28 if (OPT_HAS_OLED_SPI_SMALL)
29 u8g2 = new U8G2_SSD1306_128X32_UNIVISION_F_4W_SW_SPI(OPT_SCREEN_REVERSED ? U8G2_R2 : U8G2_R0, GPIO_PIN_SCREEN_SCK, GPIO_PIN_SCREEN_MOSI, GPIO_PIN_SCREEN_CS, GPIO_PIN_SCREEN_DC, GPIO_PIN_SCREEN_RST);
30 else if (OPT_HAS_OLED_SPI)
31 u8g2 = new U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI(OPT_SCREEN_REVERSED ? U8G2_R2 : U8G2_R0, GPIO_PIN_SCREEN_SCK, GPIO_PIN_SCREEN_MOSI, GPIO_PIN_SCREEN_CS, GPIO_PIN_SCREEN_DC, GPIO_PIN_SCREEN_RST);
32 else if (OPT_HAS_OLED_I2C)
33 u8g2 = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(OPT_SCREEN_REVERSED ? U8G2_R2 : U8G2_R0, GPIO_PIN_SCREEN_RST, GPIO_PIN_SCREEN_SCK, GPIO_PIN_SCREEN_SDA);
35 u8g2->begin();
36 u8g2->clearBuffer();
39 void OLEDDisplay::doScreenBackLight(screen_backlight_t state)
41 if (GPIO_PIN_SCREEN_BL != UNDEF_PIN)
43 digitalWrite(GPIO_PIN_SCREEN_BL, state);
45 if (state == SCREEN_BACKLIGHT_OFF)
47 u8g2->clearDisplay();
48 u8g2->setPowerSave(true);
50 else
52 u8g2->setPowerSave(false);
56 void OLEDDisplay::printScreenshot()
58 u8g2->writeBufferXBM(*TxBackpack);
61 void OLEDDisplay::displaySplashScreen()
63 u8g2->clearBuffer();
64 if (OPT_HAS_OLED_SPI_SMALL)
66 auto constexpr sz = 128 * 32 / 8;
67 uint8_t image[sz];
68 if (spi_flash_read(logo_image, image, sz) == ESP_OK)
70 u8g2->drawXBM(0, 0, 128, 32, image);
73 else
75 auto constexpr sz = 128 * 64 / 8;
76 uint8_t image[sz];
77 if (spi_flash_read(logo_image, image, sz) == ESP_OK)
79 u8g2->drawXBM(0, 0, 128, 64, image);
82 char buffer[50];
83 snprintf(buffer, sizeof(buffer), "ELRS-%.6s", version);
84 u8g2->setFont(u8g2_font_profont10_mr);
85 drawCentered(60, buffer);
87 u8g2->sendBuffer();
90 void OLEDDisplay::displayIdleScreen(uint8_t changed, uint8_t rate_index, uint8_t power_index, uint8_t ratio_index, uint8_t motion_index, uint8_t fan_index, bool dynamic, uint8_t running_power_index, uint8_t temperature, message_index_t message_index)
92 u8g2->clearBuffer();
93 String power = getValue(STATE_POWER, running_power_index);
94 if (dynamic || power_index != running_power_index)
96 power += " *";
99 u8g2->setFont(u8g2_font_t0_15_mr);
100 if (connectionState == radioFailed)
102 drawCentered(15, "BAD");
103 drawCentered(32, "RADIO");
105 else if (connectionState == noCrossfire)
107 drawCentered(15, "NO");
108 drawCentered(32, "HANDSET");
110 else if (OPT_HAS_OLED_SPI_SMALL)
112 u8g2->drawStr(0, 15, getValue(STATE_PACKET, rate_index));
113 u8g2->drawStr(70, 15, getValue(STATE_TELEMETRY_CURR, ratio_index));
114 u8g2->drawStr(0, 32, power.c_str());
115 u8g2->drawStr(70, 32, version);
117 else
119 u8g2->drawStr(0, 13, message_string[message_index]);
120 u8g2->drawStr(0, 45, getValue(STATE_PACKET, rate_index));
121 u8g2->drawStr(70, 45, getValue(STATE_TELEMETRY_CURR, ratio_index));
122 u8g2->drawStr(0, 60, power.c_str());
123 u8g2->setFont(u8g2_font_profont10_mr);
124 u8g2->drawStr(70, 56, "TLM");
125 u8g2->drawStr(0, 27, "Ver: ");
126 u8g2->drawStr(38, 27, version);
128 u8g2->sendBuffer();
131 void OLEDDisplay::displayMainMenu(menu_item_t menu)
133 u8g2->clearBuffer();
134 u8g2->setFont(u8g2_font_t0_17_mr);
135 if (OPT_HAS_OLED_SPI_SMALL)
137 u8g2->drawStr(0,15, main_menu_strings[menu][0]);
138 u8g2->drawStr(0,32, main_menu_strings[menu][1]);
140 else
142 u8g2->drawStr(0,20, main_menu_strings[menu][0]);
143 u8g2->drawStr(0,50, main_menu_strings[menu][1]);
145 helperDrawImage(menu);
146 u8g2->sendBuffer();
149 void OLEDDisplay::displayValue(menu_item_t menu, uint8_t value_index)
151 u8g2->clearBuffer();
152 u8g2->setFont(u8g2_font_9x15_t_symbols);
153 String val = String(getValue(menu, value_index));
154 val.replace("!+", "\u2191");
155 val.replace("!-", "\u2193");
156 if (OPT_HAS_OLED_SPI_SMALL)
158 u8g2->drawStr(0,15, val.c_str());
159 u8g2->setFont(u8g2_font_profont10_mr);
160 u8g2->drawStr(0,60, "PRESS TO CONFIRM");
162 else
164 u8g2->drawUTF8(0,20, val.c_str());
165 u8g2->setFont(u8g2_font_profont10_mr);
166 u8g2->drawStr(0,44, "PRESS TO");
167 u8g2->drawStr(0,56, "CONFIRM");
169 helperDrawImage(menu);
170 u8g2->sendBuffer();
173 void OLEDDisplay::displayBLEConfirm()
175 // TODO: Put wifi image?
176 u8g2->clearBuffer();
178 u8g2->setFont(u8g2_font_t0_17_mr);
179 if (OPT_HAS_OLED_SPI_SMALL)
181 u8g2->drawStr(0,15, "PRESS TO");
182 u8g2->drawStr(70,15, "START BLUETOOTH");
183 u8g2->drawStr(0,32, "JOYSTICK");
185 else
187 u8g2->drawStr(0,29, "PRESS TO START");
188 u8g2->drawStr(0,59, "BLE JOYSTICK");
190 u8g2->sendBuffer();
193 void OLEDDisplay::displayBLEStatus()
195 u8g2->clearBuffer();
197 // TODO: Add a fancy joystick symbol like the cool TFT peeps
199 u8g2->setFont(u8g2_font_t0_17_mr);
200 if (OPT_HAS_OLED_SPI_SMALL)
202 u8g2->drawStr(0,15, "BLUETOOTH");
203 u8g2->drawStr(70,15, "GAMEPAD");
204 u8g2->drawStr(0,32, "RUNNING");
206 else
208 u8g2->drawStr(0,13, "BLUETOOTH");
209 u8g2->drawStr(0,33, "GAMEPAD");
210 u8g2->drawStr(0,63, "RUNNING");
212 u8g2->sendBuffer();
215 void OLEDDisplay::displayWiFiConfirm()
217 // TODO: Put wifi image?
218 u8g2->clearBuffer();
220 u8g2->setFont(u8g2_font_t0_17_mr);
221 if (OPT_HAS_OLED_SPI_SMALL)
223 u8g2->drawStr(0,15, "PRESS TO");
224 u8g2->drawStr(70,15, "ENTER WIFI");
225 u8g2->drawStr(0,32, "UPDATE");
227 else
229 u8g2->drawStr(0,29, "PRESS TO ENTER");
230 u8g2->drawStr(0,59, "WIFI UPDATE");
232 u8g2->sendBuffer();
235 void OLEDDisplay::displayWiFiStatus()
237 u8g2->clearBuffer();
238 // TODO: Add a fancy wifi symbol like the cool TFT peeps
240 u8g2->setFont(u8g2_font_t0_17_mr);
241 if (wifiMode == WIFI_STA) {
242 if (OPT_HAS_OLED_SPI_SMALL)
244 u8g2->drawStr(0,15, "open http://");
245 u8g2->drawStr(70,15, (String(wifi_hostname)+".local").c_str());
246 u8g2->drawStr(0,32, "by browser");
248 else
250 u8g2->drawStr(0,13, "open http://");
251 u8g2->drawStr(0,33, (String(wifi_hostname)+".local").c_str());
252 u8g2->drawStr(0,63, "by browser");
255 else
257 if (OPT_HAS_OLED_SPI_SMALL)
259 u8g2->drawStr(0,15, wifi_ap_ssid);
260 u8g2->drawStr(70,15, wifi_ap_password);
261 u8g2->drawStr(0,32, wifi_ap_address);
263 else
265 u8g2->drawStr(0,13, wifi_ap_ssid);
266 u8g2->drawStr(0,33, wifi_ap_password);
267 u8g2->drawStr(0,63, wifi_ap_address);
270 u8g2->sendBuffer();
273 void OLEDDisplay::displayBindConfirm()
275 // TODO: Put bind image?
276 u8g2->clearBuffer();
277 u8g2->setFont(u8g2_font_t0_17_mr);
278 if (OPT_HAS_OLED_SPI_SMALL)
280 u8g2->drawStr(0,15, "PRESS TO");
281 u8g2->drawStr(70,15 , "SEND BIND");
282 u8g2->drawStr(0,32, "REQUEST");
284 else
286 u8g2->drawStr(0,29, "PRESS TO SEND");
287 u8g2->drawStr(0,59, "BIND REQUEST");
289 u8g2->sendBuffer();
292 void OLEDDisplay::displayBindStatus()
294 // TODO: Put bind image?
295 u8g2->clearBuffer();
296 u8g2->setFont(u8g2_font_t0_17_mr);
297 if (OPT_HAS_OLED_SPI_SMALL)
299 drawCentered(15, "BINDING...");
301 else
303 drawCentered(29, "BINDING...");
305 u8g2->sendBuffer();
308 void OLEDDisplay::displayRunning()
310 // TODO: Put wifi image?
311 u8g2->clearBuffer();
312 u8g2->setFont(u8g2_font_t0_17_mr);
313 if (OPT_HAS_OLED_SPI_SMALL)
315 drawCentered(15, "RUNNING...");
317 else
319 drawCentered(29, "RUNNING...");
321 u8g2->sendBuffer();
324 void OLEDDisplay::displaySending()
326 // TODO: Put wifi image?
327 u8g2->clearBuffer();
328 u8g2->setFont(u8g2_font_t0_17_mr);
329 if (OPT_HAS_OLED_SPI_SMALL)
331 drawCentered(15, "SENDING...");
333 else
335 drawCentered(29, "SENDING...");
337 u8g2->sendBuffer();
340 void OLEDDisplay::displayLinkstats()
342 constexpr int16_t LINKSTATS_COL_FIRST = 0;
343 constexpr int16_t LINKSTATS_COL_SECOND = 32;
344 constexpr int16_t LINKSTATS_COL_THIRD = 85;
346 constexpr int16_t LINKSTATS_ROW_FIRST = 10;
347 constexpr int16_t LINKSTATS_ROW_SECOND = 20;
348 constexpr int16_t LINKSTATS_ROW_THIRD = 30;
349 constexpr int16_t LINKSTATS_ROW_FOURTH = 40;
350 constexpr int16_t LINKSTATS_ROW_FIFTH = 50;
352 u8g2->clearBuffer();
353 u8g2->setFont(u8g2_font_profont10_mr);
355 u8g2->drawStr(LINKSTATS_COL_FIRST, LINKSTATS_ROW_SECOND, "LQ");
356 u8g2->drawStr(LINKSTATS_COL_FIRST, LINKSTATS_ROW_THIRD, "RSSI");
357 u8g2->drawStr(LINKSTATS_COL_FIRST, LINKSTATS_ROW_FOURTH, "SNR");
358 u8g2->drawStr(LINKSTATS_COL_FIRST, LINKSTATS_ROW_FIFTH, "Ant");
360 u8g2->drawStr(LINKSTATS_COL_SECOND, LINKSTATS_ROW_FIRST, "Uplink");
361 u8g2->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_SECOND);
362 u8g2->print(CRSF::LinkStatistics.uplink_Link_quality);
363 u8g2->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_THIRD);
364 u8g2->print((int8_t)CRSF::LinkStatistics.uplink_RSSI_1);
365 if (CRSF::LinkStatistics.uplink_RSSI_2 != 0)
367 u8g2->print('/');
368 u8g2->print((int8_t)CRSF::LinkStatistics.uplink_RSSI_2);
371 u8g2->drawStr(LINKSTATS_COL_THIRD, LINKSTATS_ROW_FIRST, "Downlink");
372 u8g2->setCursor(LINKSTATS_COL_THIRD, LINKSTATS_ROW_SECOND);
373 u8g2->print(CRSF::LinkStatistics.downlink_Link_quality);
374 u8g2->setCursor(LINKSTATS_COL_THIRD, LINKSTATS_ROW_THIRD);
375 u8g2->print((int8_t)CRSF::LinkStatistics.downlink_RSSI_1);
376 if (isDualRadio())
378 u8g2->print('/');
379 u8g2->print((int8_t)CRSF::LinkStatistics.downlink_RSSI_2);
382 if (!OPT_HAS_OLED_SPI_SMALL)
384 u8g2->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_FOURTH);
385 u8g2->print((int8_t)CRSF::LinkStatistics.uplink_SNR);
386 u8g2->setCursor(LINKSTATS_COL_THIRD, LINKSTATS_ROW_FOURTH);
387 u8g2->print((int8_t)CRSF::LinkStatistics.downlink_SNR);
388 u8g2->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_FIFTH);
389 u8g2->print(CRSF::LinkStatistics.active_antenna);
392 u8g2->sendBuffer();
395 // helpers
396 static void helperDrawImage(menu_item_t menu)
398 if (OPT_HAS_OLED_SPI_SMALL)
401 // Adjust these to move them around on the screen
402 int x_pos = 65;
403 int y_pos = 5;
405 switch(menu){
406 case STATE_PACKET:
407 u8g2->drawXBM(x_pos, y_pos, 32, 22, rate_img32);
408 break;
409 case STATE_SWITCH:
410 u8g2->drawXBM(x_pos, y_pos, 32, 32, switch_img32);
411 break;
412 case STATE_ANTENNA:
413 u8g2->drawXBM(x_pos, y_pos, 32, 32, antenna_img32);
414 break;
415 case STATE_POWER:
416 case STATE_POWER_MAX:
417 case STATE_POWER_DYNAMIC:
418 u8g2->drawXBM(x_pos, y_pos, 25, 25, power_img32);
419 break;
420 case STATE_TELEMETRY:
421 u8g2->drawXBM(x_pos, y_pos, 32, 32, ratio_img32);
422 break;
423 case STATE_POWERSAVE:
424 u8g2->drawXBM(x_pos, y_pos, 32, 32, powersaving_img32);
425 break;
426 case STATE_SMARTFAN:
427 u8g2->drawXBM(x_pos, y_pos, 32, 32, fan_img32);
428 break;
429 case STATE_JOYSTICK:
430 u8g2->drawXBM(x_pos, y_pos-5, 32, 32, joystick_img32);
431 break;
432 case STATE_VTX:
433 case STATE_VTX_BAND:
434 case STATE_VTX_CHANNEL:
435 case STATE_VTX_POWER:
436 case STATE_VTX_PITMODE:
437 case STATE_VTX_SEND:
438 u8g2->drawXBM(x_pos, y_pos, 32, 32, vtx_img32);
439 break;
440 case STATE_WIFI:
441 u8g2->drawXBM(x_pos, y_pos, 24, 22, wifi_img32);
442 break;
443 case STATE_BIND:
444 u8g2->drawXBM(x_pos, y_pos, 32, 32, bind_img32);
445 break;
447 case STATE_WIFI_TX:
448 u8g2->drawXBM(x_pos, y_pos, 24, 22, wifi_img32);
449 break;
450 case STATE_WIFI_RX:
451 u8g2->drawXBM(x_pos, y_pos-5, 32, 32, rxwifi_img32);
452 break;
453 case STATE_WIFI_BACKPACK:
454 u8g2->drawXBM(x_pos, y_pos-5, 32, 32, backpack_img32);
455 break;
456 case STATE_WIFI_VRX:
457 u8g2->drawXBM(x_pos, y_pos-5, 32, 32, vrxwifi_img32);
458 break;
460 default:
461 break;
464 else
466 // Adjust these to move them around on the screen
467 int x_pos = 65;
468 int y_pos = 5;
470 switch(menu){
471 case STATE_PACKET:
472 u8g2->drawXBM(x_pos, y_pos, 64, 44, rate_img64);
473 break;
474 case STATE_SWITCH:
475 u8g2->drawXBM(x_pos, y_pos, 64, 64, switch_img64);
476 break;
477 case STATE_ANTENNA:
478 u8g2->drawXBM(x_pos, y_pos, 64, 64, antenna_img64);
479 break;
480 case STATE_POWER:
481 case STATE_POWER_MAX:
482 case STATE_POWER_DYNAMIC:
483 u8g2->drawXBM(x_pos, y_pos, 50, 50, power_img64);
484 break;
485 case STATE_TELEMETRY:
486 u8g2->drawXBM(x_pos, y_pos, 64, 64, ratio_img64);
487 break;
488 case STATE_POWERSAVE:
489 u8g2->drawXBM(x_pos, y_pos, 64, 64, powersaving_img64);
490 break;
491 case STATE_SMARTFAN:
492 u8g2->drawXBM(x_pos, y_pos, 64, 64, fan_img64);
493 break;
494 case STATE_JOYSTICK:
495 u8g2->drawXBM(x_pos, y_pos, 64, 64-5, joystick_img64);
496 break;
497 case STATE_VTX:
498 case STATE_VTX_BAND:
499 case STATE_VTX_CHANNEL:
500 case STATE_VTX_POWER:
501 case STATE_VTX_PITMODE:
502 case STATE_VTX_SEND:
503 u8g2->drawXBM(x_pos, y_pos, 64, 64, vtx_img64);
504 break;
505 case STATE_WIFI:
506 u8g2->drawXBM(x_pos, y_pos, 48, 44, wifi_img64);
507 break;
508 case STATE_BIND:
509 u8g2->drawXBM(x_pos, y_pos, 64, 64, bind_img64);
510 break;
512 case STATE_WIFI_TX:
513 u8g2->drawXBM(x_pos, y_pos, 48, 44, wifi_img64);
514 break;
515 case STATE_WIFI_RX:
516 u8g2->drawXBM(x_pos, y_pos-5, 64, 64, rxwifi_img64);
517 break;
518 case STATE_WIFI_BACKPACK:
519 u8g2->drawXBM(x_pos, y_pos-5, 64, 64, backpack_img64);
520 break;
521 case STATE_WIFI_VRX:
522 u8g2->drawXBM(x_pos, y_pos-5, 64, 64, vrxwifi_img64);
523 break;
525 default:
526 break;
531 #endif