Allow choosing the RF Band on LR1121 modules (#3078)
[ExpressLRS.git] / src / lib / SCREEN / TFT / tftdisplay.cpp
bloba3f4d5d641d4acf3afb563d8021006a27568f061
1 #if defined(PLATFORM_ESP32)
3 #include <Arduino_GFX_Library.h>
4 #include "Pragma_Sans36pt7b.h"
5 #include "Pragma_Sans37pt7b.h"
6 #include "Pragma_Sans314pt7b.h"
8 #include "tftdisplay.h"
10 #include "logos.h"
11 #include "options.h"
12 #include "logging.h"
13 #include "common.h"
14 #include "CRSF.h"
16 #include "WiFi.h"
17 extern WiFiMode_t wifiMode;
19 const uint16_t *main_menu_icons[] = {
20 elrs_rate,
21 elrs_switch,
22 elrs_antenna,
23 elrs_power,
24 elrs_ratio,
25 elrs_motion,
26 elrs_fan,
27 elrs_joystick,
28 elrs_bind,
29 elrs_wifimode,
30 elrs_vtx,
32 elrs_power,
33 elrs_power,
35 elrs_vtx,
36 elrs_vtx,
37 elrs_vtx,
38 elrs_vtx,
39 elrs_vtx,
41 elrs_updatefw,
42 elrs_rxwifi,
43 elrs_backpack,
44 elrs_vrxwifi
47 // Hex color code to 16-bit rgb:
48 // color = 0x96c76f
49 // rgb_hex = ((((color&0xFF0000)>>16)&0xf8)<<8) + ((((color&0x00FF00)>>8)&0xfc)<<3) + ((color&0x0000FF)>>3)
50 constexpr uint16_t elrs_banner_bgColor[] = {
51 0x4315, // MSG_NONE => #4361AA (ELRS blue)
52 0x9E2D, // MSG_CONNECTED => #9FC76F (ELRS green)
53 0xAA08, // MSG_ARMED => #AA4343 (red)
54 0xF501, // MSG_MISMATCH => #F0A30A (amber)
55 0xF800 // MSG_ERROR => #F0A30A (very red)
58 #define SCREEN_X 160
59 #define SCREEN_Y 80
61 #define SCREEN_SMALL_FONT_SIZE 8
62 #define SCREEN_SMALL_FONT Pragma_Sans36pt7b
64 #define SCREEN_NORMAL_FONT_SIZE 16
65 #define SCREEN_NORMAL_FONT Pragma_Sans37pt7b
67 #define SCREEN_LARGE_FONT_SIZE 26
68 #define SCREEN_LARGE_FONT Pragma_Sans314pt7b
70 //ICON SIZE Definition
71 #define SCREEN_LARGE_ICON_SIZE 60
73 //GAP Definition
74 #define SCREEN_CONTENT_GAP 10
75 #define SCREEN_FONT_GAP 5
77 //INIT LOGO PAGE Definition
78 #define INIT_PAGE_LOGO_X SCREEN_X
79 #define INIT_PAGE_LOGO_Y 53
80 #define INIT_PAGE_FONT_PADDING 3
81 #define INIT_PAGE_FONT_START_X SCREEN_FONT_GAP
82 #define INIT_PAGE_FONT_START_Y INIT_PAGE_LOGO_Y + (SCREEN_Y - INIT_PAGE_LOGO_Y - SCREEN_NORMAL_FONT_SIZE)/2
84 //IDLE PAGE Definition
85 #define IDLE_PAGE_START_X SCREEN_CONTENT_GAP
86 #define IDLE_PAGE_START_Y 0
88 #define IDLE_PAGE_STAT_START_X SCREEN_X/2 // is centered, so no GAP
89 #define IDLE_PAGE_STAT_Y_GAP (SCREEN_Y - SCREEN_NORMAL_FONT_SIZE * 3)/4
91 #define IDLE_PAGE_RATE_START_Y IDLE_PAGE_STAT_Y_GAP
92 #define IDLE_PAGE_POWER_START_Y IDLE_PAGE_RATE_START_Y + SCREEN_NORMAL_FONT_SIZE + IDLE_PAGE_STAT_Y_GAP
93 #define IDLE_PAGE_RATIO_START_Y IDLE_PAGE_POWER_START_Y + SCREEN_NORMAL_FONT_SIZE + IDLE_PAGE_STAT_Y_GAP
95 //MAIN PAGE Definition
96 #define MAIN_PAGE_ICON_START_X SCREEN_CONTENT_GAP
97 #define MAIN_PAGE_ICON_START_Y (SCREEN_Y - SCREEN_LARGE_ICON_SIZE)/2
99 #define MAIN_PAGE_WORD_START_X MAIN_PAGE_ICON_START_X + SCREEN_LARGE_ICON_SIZE
100 #define MAIN_PAGE_WORD_START_Y1 (SCREEN_Y - SCREEN_NORMAL_FONT_SIZE*2 - SCREEN_FONT_GAP)/2
101 #define MAIN_PAGE_WORD_START_Y2 MAIN_PAGE_WORD_START_Y1 + SCREEN_NORMAL_FONT_SIZE + SCREEN_FONT_GAP
103 //Sub Function Definiton
104 #define SUB_PAGE_VALUE_START_X SCREEN_CONTENT_GAP
105 #define SUB_PAGE_VALUE_START_Y (SCREEN_Y - SCREEN_LARGE_FONT_SIZE - SCREEN_NORMAL_FONT_SIZE - SCREEN_CONTENT_GAP)/2
107 #define SUB_PAGE_TIPS_START_X SCREEN_CONTENT_GAP
108 #define SUB_PAGE_TIPS_START_Y SCREEN_Y - SCREEN_NORMAL_FONT_SIZE - SCREEN_CONTENT_GAP
110 //Sub WIFI Mode & Bind Confirm Definiton
111 #define SUB_PAGE_ICON_START_X 0
112 #define SUB_PAGE_ICON_START_Y (SCREEN_Y - SCREEN_LARGE_ICON_SIZE)/2
114 #define SUB_PAGE_WORD_START_X SUB_PAGE_ICON_START_X + SCREEN_LARGE_ICON_SIZE
115 #define SUB_PAGE_WORD_START_Y1 (SCREEN_Y - SCREEN_NORMAL_FONT_SIZE*3 - SCREEN_FONT_GAP*2)/2
116 #define SUB_PAGE_WORD_START_Y2 SUB_PAGE_WORD_START_Y1 + SCREEN_NORMAL_FONT_SIZE + SCREEN_FONT_GAP
117 #define SUB_PAGE_WORD_START_Y3 SUB_PAGE_WORD_START_Y2 + SCREEN_NORMAL_FONT_SIZE + SCREEN_FONT_GAP
119 //Sub Binding Definiton
120 #define SUB_PAGE_BINDING_WORD_START_X 0
121 #define SUB_PAGE_BINDING_WORD_START_Y (SCREEN_Y - SCREEN_LARGE_FONT_SIZE)/2
123 static Arduino_DataBus *bus;
124 static Arduino_GFX *gfx;
126 void TFTDisplay::init()
128 if (GPIO_PIN_SCREEN_BL != UNDEF_PIN)
130 pinMode(GPIO_PIN_SCREEN_BL, OUTPUT);
132 bus = new Arduino_ESP32SPI(GPIO_PIN_SCREEN_DC, GPIO_PIN_SCREEN_CS, GPIO_PIN_SCREEN_SCK, GPIO_PIN_SCREEN_MOSI, GFX_NOT_DEFINED, HSPI);
133 gfx = new Arduino_ST7735(bus, GPIO_PIN_SCREEN_RST, OPT_SCREEN_REVERSED ? 3 : 1 /* rotation */, true , 80, 160, 26, 1, 26, 1);
135 gfx->begin();
136 doScreenBackLight(SCREEN_BACKLIGHT_ON);
139 void TFTDisplay::doScreenBackLight(screen_backlight_t state)
141 if (GPIO_PIN_SCREEN_BL != UNDEF_PIN)
143 digitalWrite(GPIO_PIN_SCREEN_BL, state);
147 void TFTDisplay::printScreenshot()
149 DBGLN("Unimplemented");
152 static void displayFontCenter(uint32_t font_start_x, uint32_t font_end_x, uint32_t font_start_y,
153 int font_size, const GFXfont& font, String font_string,
154 uint16_t fgColor, uint16_t bgColor)
156 gfx->fillRect(font_start_x, font_start_y, font_end_x - font_start_x, font_size, bgColor);
157 gfx->setFont(&font);
159 int16_t x, y;
160 uint16_t w, h;
161 gfx->getTextBounds(font_string, font_start_x, font_start_y, &x, &y, &w, &h);
162 int start_pos = font_start_x + (font_end_x - font_start_x - w)/2;
164 gfx->setCursor(start_pos, font_start_y + h);
165 gfx->setTextColor(fgColor, bgColor);
166 gfx->print(font_string);
170 void TFTDisplay::displaySplashScreen()
172 gfx->fillScreen(WHITE);
174 size_t sz = INIT_PAGE_LOGO_X * INIT_PAGE_LOGO_Y;
175 uint16_t image[sz];
176 if (spi_flash_read(logo_image, image, sz * 2) == ESP_OK)
178 gfx->draw16bitRGBBitmap(0, 0, image, INIT_PAGE_LOGO_X, INIT_PAGE_LOGO_Y);
181 gfx->fillRect(SCREEN_FONT_GAP, INIT_PAGE_FONT_START_Y - INIT_PAGE_FONT_PADDING,
182 SCREEN_X - SCREEN_FONT_GAP*2, SCREEN_NORMAL_FONT_SIZE + INIT_PAGE_FONT_PADDING*2, BLACK);
184 char buffer[50];
185 snprintf(buffer, sizeof(buffer), "ELRS-%.6s", version);
186 displayFontCenter(INIT_PAGE_FONT_START_X, SCREEN_X - INIT_PAGE_FONT_START_X, INIT_PAGE_FONT_START_Y,
187 SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
188 String(buffer), WHITE, BLACK);
191 void TFTDisplay::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)
193 if (changed == CHANGED_ALL)
195 // Everything has changed! So clear the right side
196 gfx->fillRect(SCREEN_X/2, 0, SCREEN_X/2, SCREEN_Y, WHITE);
199 if (changed & CHANGED_TEMP)
201 // Left side logo, version, and temp
202 gfx->fillRect(0, 0, SCREEN_X/2, SCREEN_Y, elrs_banner_bgColor[message_index]);
203 gfx->drawBitmap(IDLE_PAGE_START_X, IDLE_PAGE_START_Y, elrs_banner_bmp, SCREEN_LARGE_ICON_SIZE, SCREEN_LARGE_ICON_SIZE,
204 WHITE);
206 // Update the temperature
207 char buffer[20];
208 // \367 = (char)247 = degree symbol
209 snprintf(buffer, sizeof(buffer), "%.6s %02d\367C", version, temperature);
210 displayFontCenter(0, SCREEN_X/2, SCREEN_LARGE_ICON_SIZE + (SCREEN_Y - SCREEN_LARGE_ICON_SIZE - SCREEN_SMALL_FONT_SIZE)/2,
211 SCREEN_SMALL_FONT_SIZE, SCREEN_SMALL_FONT,
212 String(buffer), WHITE, elrs_banner_bgColor[message_index]);
215 // The Radio Params right half of the screen
216 uint16_t text_color = (message_index == MSG_ARMED) ? DARKGREY : BLACK;
218 if (connectionState == radioFailed)
220 displayFontCenter(IDLE_PAGE_STAT_START_X, SCREEN_X, MAIN_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
221 "BAD", BLACK, WHITE);
222 displayFontCenter(IDLE_PAGE_STAT_START_X, SCREEN_X, MAIN_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
223 "RADIO", BLACK, WHITE);
225 else if (connectionState == noCrossfire)
227 displayFontCenter(IDLE_PAGE_STAT_START_X, SCREEN_X, MAIN_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
228 "NO", BLACK, WHITE);
229 displayFontCenter(IDLE_PAGE_STAT_START_X, SCREEN_X, MAIN_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
230 "HANDSET", BLACK, WHITE);
232 else
234 if (changed & CHANGED_RATE)
236 displayFontCenter(IDLE_PAGE_STAT_START_X, SCREEN_X, IDLE_PAGE_RATE_START_Y, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
237 getValue(STATE_PACKET, rate_index), text_color, WHITE);
240 if (changed & CHANGED_POWER)
242 String power = getValue(STATE_POWER, running_power_index);
243 if (dynamic || power_index != running_power_index)
245 power += " *";
247 displayFontCenter(IDLE_PAGE_STAT_START_X, SCREEN_X, IDLE_PAGE_POWER_START_Y, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
248 power, text_color, WHITE);
251 if (changed & CHANGED_TELEMETRY)
253 displayFontCenter(IDLE_PAGE_STAT_START_X, SCREEN_X, IDLE_PAGE_RATIO_START_Y, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
254 getValue(STATE_TELEMETRY_CURR, ratio_index), text_color, WHITE);
260 void TFTDisplay::displayMainMenu(menu_item_t menu)
262 gfx->fillScreen(WHITE);
264 gfx->draw16bitRGBBitmap(MAIN_PAGE_ICON_START_X, MAIN_PAGE_ICON_START_Y, main_menu_icons[menu], SCREEN_LARGE_ICON_SIZE, SCREEN_LARGE_ICON_SIZE);
265 displayFontCenter(MAIN_PAGE_WORD_START_X, SCREEN_X, MAIN_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
266 main_menu_strings[menu][0], BLACK, WHITE);
267 displayFontCenter(MAIN_PAGE_WORD_START_X, SCREEN_X, MAIN_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
268 main_menu_strings[menu][1], BLACK, WHITE);
271 void TFTDisplay::displayValue(menu_item_t menu, uint8_t value_index)
273 gfx->fillScreen(WHITE);
275 String val = String(getValue(menu, value_index));
276 val.replace("!+", "\xA0");
277 val.replace("!-", "\xA1");
279 displayFontCenter(SUB_PAGE_VALUE_START_X, SCREEN_X, SUB_PAGE_VALUE_START_Y, SCREEN_LARGE_FONT_SIZE, SCREEN_LARGE_FONT,
280 val.c_str(), BLACK, WHITE);
281 displayFontCenter(SUB_PAGE_TIPS_START_X, SCREEN_X, SUB_PAGE_TIPS_START_Y, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
282 "PRESS TO CONFIRM", BLACK, WHITE);
285 void TFTDisplay::displayBLEConfirm()
287 gfx->fillScreen(WHITE);
289 gfx->draw16bitRGBBitmap(SUB_PAGE_ICON_START_X, SUB_PAGE_ICON_START_Y, elrs_joystick, SCREEN_LARGE_ICON_SIZE, SCREEN_LARGE_ICON_SIZE);
290 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
291 "PRESS TO", BLACK, WHITE);
292 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
293 "START BLE", BLACK, WHITE);
294 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y3, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
295 "GAMEPAD", BLACK, WHITE);
298 void TFTDisplay::displayBLEStatus()
300 gfx->fillScreen(WHITE);
302 gfx->draw16bitRGBBitmap(SUB_PAGE_ICON_START_X, SUB_PAGE_ICON_START_Y, elrs_joystick, SCREEN_LARGE_ICON_SIZE, SCREEN_LARGE_ICON_SIZE);
303 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
304 "BLE", BLACK, WHITE);
305 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
306 "GAMEPAD", BLACK, WHITE);
307 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y3, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
308 "RUNNING", BLACK, WHITE);
311 void TFTDisplay::displayWiFiConfirm()
313 gfx->fillScreen(WHITE);
315 gfx->draw16bitRGBBitmap(SUB_PAGE_ICON_START_X, SUB_PAGE_ICON_START_Y, elrs_wifimode, SCREEN_LARGE_ICON_SIZE, SCREEN_LARGE_ICON_SIZE);
316 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
317 "PRESS TO", BLACK, WHITE);
318 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
319 "ENTER WIFI", BLACK, WHITE);
320 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y3, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
321 "UPDATE MODE", BLACK, WHITE);
324 void TFTDisplay::displayWiFiStatus()
326 gfx->fillScreen(WHITE);
328 gfx->draw16bitRGBBitmap(SUB_PAGE_ICON_START_X, SUB_PAGE_ICON_START_Y, elrs_wifimode, SCREEN_LARGE_ICON_SIZE, SCREEN_LARGE_ICON_SIZE);
329 if (wifiMode == WIFI_STA) {
330 String host_msg = String(wifi_hostname) + ".local";
331 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
332 "open http://", BLACK, WHITE);
333 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
334 host_msg, BLACK, WHITE);
335 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y3, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
336 "by browser", BLACK, WHITE);
338 else
340 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
341 wifi_ap_ssid, BLACK, WHITE);
342 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
343 wifi_ap_password, BLACK, WHITE);
344 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y3, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
345 wifi_ap_address, BLACK, WHITE);
349 void TFTDisplay::displayBindConfirm()
351 gfx->fillScreen(WHITE);
353 gfx->draw16bitRGBBitmap(SUB_PAGE_ICON_START_X, SUB_PAGE_ICON_START_Y, elrs_bind, SCREEN_LARGE_ICON_SIZE, SCREEN_LARGE_ICON_SIZE);
354 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y1, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
355 "PRESS TO", BLACK, WHITE);
356 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y2, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
357 "SEND BIND", BLACK, WHITE);
358 displayFontCenter(SUB_PAGE_WORD_START_X, SCREEN_X, SUB_PAGE_WORD_START_Y3, SCREEN_NORMAL_FONT_SIZE, SCREEN_NORMAL_FONT,
359 "REQUEST", BLACK, WHITE);
362 void TFTDisplay::displayBindStatus()
364 gfx->fillScreen(WHITE);
366 displayFontCenter(SUB_PAGE_BINDING_WORD_START_X, SCREEN_X, SUB_PAGE_BINDING_WORD_START_Y, SCREEN_LARGE_FONT_SIZE, SCREEN_LARGE_FONT,
367 "BINDING...", BLACK, WHITE);
370 void TFTDisplay::displayRunning()
372 gfx->fillScreen(WHITE);
374 displayFontCenter(SUB_PAGE_BINDING_WORD_START_X, SCREEN_X, SUB_PAGE_BINDING_WORD_START_Y, SCREEN_LARGE_FONT_SIZE, SCREEN_LARGE_FONT,
375 "RUNNING...", BLACK, WHITE);
378 void TFTDisplay::displaySending()
380 gfx->fillScreen(WHITE);
382 displayFontCenter(SUB_PAGE_BINDING_WORD_START_X, SCREEN_X, SUB_PAGE_BINDING_WORD_START_Y, SCREEN_LARGE_FONT_SIZE, SCREEN_LARGE_FONT,
383 "SENDING...", BLACK, WHITE);
386 void TFTDisplay::displayLinkstats()
388 constexpr int16_t LINKSTATS_COL_FIRST = 0;
389 constexpr int16_t LINKSTATS_COL_SECOND = 30;
390 constexpr int16_t LINKSTATS_COL_THIRD = 100;
392 constexpr int16_t LINKSTATS_ROW_FIRST = 10;
393 constexpr int16_t LINKSTATS_ROW_SECOND = 25;
394 constexpr int16_t LINKSTATS_ROW_THIRD = 40;
395 constexpr int16_t LINKSTATS_ROW_FOURTH = 55;
396 constexpr int16_t LINKSTATS_ROW_FIFTH = 70;
398 gfx->fillScreen(WHITE);
399 gfx->setFont(&SCREEN_SMALL_FONT);
400 gfx->setTextColor(BLACK, WHITE);
402 gfx->setCursor(LINKSTATS_COL_FIRST, LINKSTATS_ROW_SECOND);
403 gfx->print("LQ");
404 gfx->setCursor(LINKSTATS_COL_FIRST, LINKSTATS_ROW_THIRD);
405 gfx->print("RSSI");
406 gfx->setCursor(LINKSTATS_COL_FIRST, LINKSTATS_ROW_FOURTH);
407 gfx->print("SNR");
408 gfx->setCursor(LINKSTATS_COL_FIRST, LINKSTATS_ROW_FIFTH);
409 gfx->print("Ant");
411 // Uplink Linkstats
412 gfx->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_FIRST);
413 gfx->print("Uplink");
414 gfx->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_SECOND);
415 gfx->print(CRSF::LinkStatistics.uplink_Link_quality);
416 gfx->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_THIRD);
417 gfx->print((int8_t)CRSF::LinkStatistics.uplink_RSSI_1);
418 if (CRSF::LinkStatistics.uplink_RSSI_2 != 0)
420 gfx->print('/');
421 gfx->print((int8_t)CRSF::LinkStatistics.uplink_RSSI_2);
424 gfx->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_FOURTH);
425 gfx->print(CRSF::LinkStatistics.uplink_SNR);
426 gfx->setCursor(LINKSTATS_COL_SECOND, LINKSTATS_ROW_FIFTH);
427 gfx->print(CRSF::LinkStatistics.active_antenna);
429 // Downlink Linkstats
430 gfx->setCursor(LINKSTATS_COL_THIRD, LINKSTATS_ROW_FIRST);
431 gfx->print("Downlink");
432 gfx->setCursor(LINKSTATS_COL_THIRD, LINKSTATS_ROW_SECOND);
433 gfx->print(CRSF::LinkStatistics.downlink_Link_quality);
434 gfx->setCursor(LINKSTATS_COL_THIRD, LINKSTATS_ROW_THIRD);
435 gfx->print((int8_t)CRSF::LinkStatistics.downlink_RSSI_1);
436 if (isDualRadio())
438 gfx->print('/');
439 gfx->print((int8_t)CRSF::LinkStatistics.downlink_RSSI_2);
442 gfx->setCursor(LINKSTATS_COL_THIRD, LINKSTATS_ROW_FOURTH);
443 gfx->print(CRSF::LinkStatistics.downlink_SNR);
446 #endif