2 * This file is part of the ExpressLRS distribution (https://github.com/ExpressLRS/ExpressLRS).
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3.
8 * This program is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #if defined(USE_OLED_SPI) || defined(USE_OLED_SPI_SMALL) || defined(USE_OLED_I2C) // This code will not be used if the hardware does not have a OLED display. Maybe a better way to blacklist it in platformio.ini?
18 // Default header files for Express LRS
22 // OLED specific header files.
23 #include "oledscreen.h"
24 #include <U8g2lib.h> // Needed for the OLED drivers, this is a arduino package. It is maintained by platformIO
25 #include "XBMStrings.h" // Contains all the ELRS logos and animations for the UI
27 // Used for the the max power settings
28 #include "POWERMGNT.h"
31 #define OLED_ROTATION U8G2_R2
33 #define OLED_ROTATION U8G2_R0
36 #ifdef USE_OLED_SPI_SMALL
37 U8G2_SSD1306_128X32_UNIVISION_F_4W_SW_SPI
u8g2(OLED_ROTATION
, GPIO_PIN_OLED_SCK
, GPIO_PIN_OLED_MOSI
, GPIO_PIN_OLED_CS
, GPIO_PIN_OLED_DC
, GPIO_PIN_OLED_RST
);
41 U8G2_SSD1306_128X64_NONAME_F_4W_SW_SPI
u8g2(OLED_ROTATION
, GPIO_PIN_OLED_SCK
, GPIO_PIN_OLED_MOSI
, GPIO_PIN_OLED_CS
, GPIO_PIN_OLED_DC
, GPIO_PIN_OLED_RST
);
45 U8G2_SSD1306_128X64_NONAME_F_HW_I2C
u8g2(OLED_ROTATION
, GPIO_PIN_OLED_RST
, GPIO_PIN_OLED_SCK
, GPIO_PIN_OLED_SDA
);
48 #ifdef TARGET_TX_GHOST
50 * helper function is used to draw xbmp on the OLED.
51 * x = x position of the image
52 * y = y position of the image
53 * size = demensions of the box size x size, this only works for square images 1:1
54 * image = XBM character string
56 #ifndef TARGET_TX_GHOST_LITE
57 static void helper(int x
, int y
, int size
, const unsigned char * image
){
59 u8g2
.drawXBMP(x
, y
, size
, size
, image
);
65 * ghostChase will only be called for ghost TX hardware.
67 static void ghostChase(){
68 // Using i < 16 and (i*4) to get 64 total pixels. Change to i < 32 (i*2) to slow animation.
69 for(int i
= 0; i
< 20; i
++){
71 #ifndef TARGET_TX_GHOST_LITE
72 u8g2
.drawXBMP((26 + i
), 16, 32, 32, ghost
);
73 u8g2
.drawXBMP((-31 + (i
*4)), 16, 32, 32, elrs32
);
75 u8g2
.drawXBMP((26 + i
), 0, 32, 32, ghost
);
76 u8g2
.drawXBMP((-31 + (i
*4)), 0, 32, 32, elrs32
);
81 * Animation for the ghost logo expanding in the center of the screen.
82 * helper function just draw's the XBM strings.
84 #ifndef TARGET_TX_GHOST_LITE
85 helper(38,12,40,elrs40
);
86 helper(36,8,48,elrs48
);
87 helper(34,4,56,elrs56
);
88 helper(32,0,64,elrs64
);
94 * Displays the ExpressLRS logo
99 static void displayLogo()
104 #ifdef TARGET_TX_GHOST
107 #ifdef USE_OLED_SPI_SMALL
108 u8g2
.drawXBM(48, 0, 32, 32, elrs32
);
110 u8g2
.drawXBM(32, 0, 64, 64, elrs64
);
117 static void displayFontCenter(const char * info
)
120 u8g2
.setFont(u8g2_font_profont10_mr
);
121 #ifdef USE_OLED_SPI_SMALL
122 u8g2
.drawStr(32, 32, info
);
124 u8g2
.drawStr(64, 64, info
);
129 void OLEDScreen::init(bool reboot
)
136 current_screen_status
= SCREEN_STATUS_INIT
;
138 current_rate_index
= 0;
139 current_power_index
= 0;
140 current_ratio_index
= 0;
142 current_page_index
= PAGE_MAIN_MENU_INDEX
;
144 main_menu_page_index
= MAIN_MENU_RATE_INDEX
;
149 void helperDrawImage64(int menu
)
151 // Adjust these to move them around on the screen
157 u8g2
.drawXBM(x_pos
, y_pos
, 64, 44, rate_img64
);
160 u8g2
.drawXBM(x_pos
, y_pos
, 50, 50, power_img64
);
163 u8g2
.drawXBM(x_pos
, y_pos
, 64, 64, ratio_img64
);
166 u8g2
.drawXBM(x_pos
, y_pos
, 64, 64, powersaving_img64
);
169 u8g2
.drawXBM(x_pos
, y_pos
, 64, 64, fan_img64
);
172 u8g2
.drawXBM(x_pos
, y_pos
, 64, 64, bind_img64
);
175 u8g2
.drawXBM(x_pos
, y_pos
, 48, 44, wifi_img64
);
180 void helperDrawImage32(int menu
)
182 // Adjust these to move them around on the screen
188 u8g2
.drawXBM(x_pos
, y_pos
, 32, 22, rate_img32
);
191 u8g2
.drawXBM(x_pos
, y_pos
, 25, 25, power_img32
);
194 u8g2
.drawXBM(x_pos
, y_pos
, 32, 32, ratio_img32
);
197 u8g2
.drawXBM(x_pos
, y_pos
, 32, 32, powersaving_img32
);
200 u8g2
.drawXBM(x_pos
, y_pos
, 32, 32, fan_img32
);
203 u8g2
.drawXBM(x_pos
, y_pos
, 32, 32, bind_img32
);
206 u8g2
.drawXBM(x_pos
, y_pos
, 24, 22, wifi_img32
);
212 void OLEDScreen::displayMainScreen(){
215 #ifdef USE_OLED_SPI_SMALL
216 u8g2
.setFont(u8g2_font_t0_15_mr
);
217 u8g2
.drawStr(0,15, &(rate_string
[current_rate_index
])[0]);
218 u8g2
.drawStr(70,15 ,&(ratio_string
[current_ratio_index
])[0]);
219 u8g2
.drawStr(0,32, &(power_string
[current_power_index
])[0]);
220 u8g2
.drawStr(70,32, "Test");
222 u8g2
.setFont(u8g2_font_t0_15_mr
);
223 u8g2
.drawStr(0,13, "ExpressLRS");
224 u8g2
.drawStr(0,45, &(rate_string
[current_rate_index
])[0]);
225 u8g2
.drawStr(70,45 , &(ratio_string
[current_ratio_index
])[0]);
226 u8g2
.drawStr(0,60, &(power_string
[current_power_index
])[0]);
227 u8g2
.setFont(u8g2_font_profont10_mr
);
228 u8g2
.drawStr(70,56, "TLM");
229 u8g2
.drawStr(0,27, "Ver: ");
231 strncpy(buffer
, version
, 6);
233 u8g2
.drawStr(38,27, buffer
);
238 void OLEDScreen::idleScreen()
242 current_screen_status
= SCREEN_STATUS_IDLE
;
245 void OLEDScreen::updateMainMenuPage()
248 #ifdef USE_OLED_SPI_SMALL
249 u8g2
.setFont(u8g2_font_t0_17_mr
);
250 u8g2
.drawStr(0,15, &(main_menu_line_1
[main_menu_page_index
- 1])[0]);
251 u8g2
.drawStr(0,32, &(main_menu_line_2
[main_menu_page_index
- 1])[0]);
252 helperDrawImage32(main_menu_page_index
- 1 );
254 u8g2
.setFont(u8g2_font_t0_17_mr
);
255 u8g2
.drawStr(0,20, &(main_menu_line_1
[main_menu_page_index
- 1])[0]);
256 u8g2
.drawStr(0,50, &(main_menu_line_2
[main_menu_page_index
- 1])[0]);
257 helperDrawImage64(main_menu_page_index
- 1);
262 void OLEDScreen::updateSubFunctionPage()
264 doValueSelection(USER_ACTION_NONE
);
267 void OLEDScreen::updateSubWIFIModePage()
271 // TODO: Add a fancy wifi symbol like the cool TFT peeps
273 #if defined(HOME_WIFI_SSID) && defined(HOME_WIFI_PASSWORD)
274 #ifdef USE_OLED_SPI_SMALL
275 u8g2
.setFont(u8g2_font_t0_17_mr
);
276 u8g2
.drawStr(0,15, "open http://");
277 u8g2
.drawStr(70,15, (String(wifi_hostname
)+".local").c_str());
278 u8g2
.drawStr(0,32, "by browser");
280 u8g2
.setFont(u8g2_font_t0_17_mr
);
281 u8g2
.drawStr(0,13, "open http://");
282 u8g2
.drawStr(0,33, (String(wifi_hostname
)+".local").c_str());
283 u8g2
.drawStr(0,63, "by browser");
286 #ifdef USE_OLED_SPI_SMALL
287 u8g2
.setFont(u8g2_font_t0_17_mr
);
288 u8g2
.drawStr(0,15, wifi_ap_ssid
);
289 u8g2
.drawStr(70,15, wifi_ap_password
);
290 u8g2
.drawStr(0,32, wifi_ap_address
);
292 u8g2
.setFont(u8g2_font_t0_17_mr
);
293 u8g2
.drawStr(0,13, wifi_ap_ssid
);
294 u8g2
.drawStr(0,33, wifi_ap_password
);
295 u8g2
.drawStr(0,63, wifi_ap_address
);
299 updatecallback(USER_UPDATE_TYPE_WIFI
);
302 void OLEDScreen::updateSubBindConfirmPage()
304 // TODO: Put bind image?
307 #ifdef USE_OLED_SPI_SMALL
308 u8g2
.setFont(u8g2_font_t0_17_mr
);
309 u8g2
.drawStr(0,15, "PRESS TO");
310 u8g2
.drawStr(70,15 , "SEND BIND");
311 u8g2
.drawStr(0,32, "REQUEST");
313 u8g2
.setFont(u8g2_font_t0_17_mr
);
314 u8g2
.drawStr(0,29, "PRESS TO SEND");
315 u8g2
.drawStr(0,59, "BIND REQUEST");
321 void OLEDScreen::updateSubBindingPage()
323 // TODO: Put bind image?
326 #ifdef USE_OLED_SPI_SMALL
327 u8g2
.setFont(u8g2_font_t0_17_mr
);
328 u8g2
.drawStr(0,15, "BINDING");
330 u8g2
.setFont(u8g2_font_t0_17_mr
);
331 u8g2
.drawStr(0,29, "BINDING");
336 updatecallback(USER_UPDATE_TYPE_BINDING
);
338 current_screen_status
= SCREEN_STATUS_BINDING
;
341 void OLEDScreen::doRateValueSelect(int action
)
343 nextIndex(current_rate_index
, action
, RATE_MAX_NUMBER
);
345 // TODO: Put bind image?
347 #ifdef USE_OLED_SPI_SMALL
348 u8g2
.setFont(u8g2_font_t0_16_mr
);
349 u8g2
.drawStr(0,15, &(rate_string
[current_rate_index
])[0]);
350 u8g2
.setFont(u8g2_font_profont10_mr
);
351 u8g2
.drawStr(0,60, "PRESS TO CONFIRM");
352 helperDrawImage32(IMAGE_RATE
);
354 u8g2
.setFont(u8g2_font_t0_16_mr
);
355 u8g2
.drawStr(0,20, &(rate_string
[current_rate_index
])[0]);
356 u8g2
.setFont(u8g2_font_profont10_mr
);
357 u8g2
.drawStr(0,44, "PRESS TO");
358 u8g2
.drawStr(0,56, "CONFIRM");
359 helperDrawImage64(IMAGE_RATE
);
364 void OLEDScreen::doPowerValueSelect(int action
)
366 nextIndex(current_power_index
, action
, MinPower
, MaxPower
+1);
369 #ifdef USE_OLED_SPI_SMALL
370 u8g2
.setFont(u8g2_font_t0_16_mr
);
371 u8g2
.drawStr(0,15, &(power_string
[current_power_index
])[0]);
372 u8g2
.setFont(u8g2_font_courR08_tr
);
373 u8g2
.drawStr(0,60, "PRESS TO CONFIRM");
374 helperDrawImage32(IMAGE_POWER
);
376 u8g2
.setFont(u8g2_font_t0_16_mr
);
377 u8g2
.drawStr(0,20, &(power_string
[current_power_index
])[0]);
378 u8g2
.setFont(u8g2_font_profont10_mr
);
379 u8g2
.drawStr(0,44, "PRESS TO");
380 u8g2
.drawStr(0,56, "CONFIRM");
381 helperDrawImage64(IMAGE_POWER
);
386 void OLEDScreen::doRatioValueSelect(int action
)
389 nextIndex(current_ratio_index
, action
, RATIO_MAX_NUMBER
);
392 #ifdef USE_OLED_SPI_SMALL
393 u8g2
.setFont(u8g2_font_t0_16_mr
);
394 u8g2
.drawStr(0,15, &(ratio_string
[current_ratio_index
])[0]);
395 u8g2
.setFont(u8g2_font_profont10_mr
);
396 u8g2
.drawStr(0,60, "PRESS TO CONFIRM");
397 helperDrawImage32(IMAGE_RATIO
);
399 u8g2
.setFont(u8g2_font_t0_16_mr
);
400 u8g2
.drawStr(0,20, &(ratio_string
[current_ratio_index
])[0]);
401 u8g2
.setFont(u8g2_font_profont10_mr
);
402 u8g2
.drawStr(0,44, "PRESS TO");
403 u8g2
.drawStr(0,56, "CONFIRM");
404 helperDrawImage64(IMAGE_RATIO
);
409 void OLEDScreen::doPowerSavingValueSelect(int action
)
411 nextIndex(current_smartfan_index
, action
, SMARTFAN_MAX_NUMBER
);
412 // TODO display the value
415 void OLEDScreen::doSmartFanValueSelect(int action
)
417 nextIndex(current_powersaving_index
, action
, POWERSAVING_MAX_NUMBER
);
418 // TODO display the value
421 void OLEDScreen::doParamUpdate(uint8_t rate_index
, uint8_t power_index
, uint8_t ratio_index
, uint8_t motion_index
, uint8_t fan_index
)
423 if(current_screen_status
== SCREEN_STATUS_IDLE
)
425 if(rate_index
!= current_rate_index
)
427 current_rate_index
= rate_index
;
431 if(power_index
!= current_power_index
)
433 current_power_index
= power_index
;
437 if(ratio_index
!= current_ratio_index
)
439 current_ratio_index
= ratio_index
;
445 current_rate_index
= rate_index
;
446 current_power_index
= power_index
;
447 current_ratio_index
= ratio_index
;
450 current_powersaving_index
= motion_index
;
451 current_smartfan_index
= fan_index
;
454 void OLEDScreen::doTemperatureUpdate(uint8_t temperature
)
456 system_temperature
= temperature
;
457 if(current_screen_status
== SCREEN_STATUS_IDLE
)
460 strncpy(buffer
, version
, 6);
461 sprintf(buffer
+6, " %02d", system_temperature
);
463 // displayFontCenterWithCelsius(0, SCREEN_X/2, SCREEN_LARGE_ICON_SIZE + (SCREEN_Y - SCREEN_LARGE_ICON_SIZE - SCREEN_SMALL_FONT_SIZE)/2,
464 // SCREEN_SMALL_FONT_SIZE, SCREEN_SMALL_FONT,
465 // String(buffer), TFT_WHITE, COLOR_ELRS_BANNER_BACKGROUND);
469 void OLEDScreen::doScreenBackLight(int state
)
471 #ifdef GPIO_PIN_OLED_BL
472 digitalWrite(GPIO_PIN_OLED_BL
, state
);