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"
17 extern WiFiMode_t wifiMode
;
19 const uint16_t *main_menu_icons
[] = {
47 // Hex color code to 16-bit rgb:
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)
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
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);
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
);
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
;
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
);
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
,
206 // Update the temperature
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
,
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
);
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
)
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
);
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
);
404 gfx
->setCursor(LINKSTATS_COL_FIRST
, LINKSTATS_ROW_THIRD
);
406 gfx
->setCursor(LINKSTATS_COL_FIRST
, LINKSTATS_ROW_FOURTH
);
408 gfx
->setCursor(LINKSTATS_COL_FIRST
, LINKSTATS_ROW_FIFTH
);
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)
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
);
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
);