/* * Copyright (C) EdgeTX * * Based on code named * opentx - https://github.com/opentx/opentx * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include "hal/gpio.h" #include "stm32_gpio.h" #include "board.h" #include "fw_version.h" #include "lcd.h" #include "translations.h" #include "targets/common/arm/stm32/bootloader/boot.h" #include "bootloader/firmware_files.h" #include #define RADIO_MENU_LEN 2 #define SELECTED_COLOR (INVERS | COLOR_THEME_SECONDARY1) #define DEFAULT_PADDING 28 #define DOUBLE_PADDING 56 #define MESSAGE_TOP (LCD_H - (2*DOUBLE_PADDING)) const uint8_t __bmp_plug_usb[] { #include "bmp_plug_usb.lbm" }; LZ4BitmapBuffer BMP_PLUG_USB(BMP_ARGB4444, (LZ4Bitmap*)__bmp_plug_usb); const uint8_t __bmp_usb_plugged[] { #include "bmp_usb_plugged.lbm" }; LZ4BitmapBuffer BMP_USB_PLUGGED(BMP_ARGB4444, (LZ4Bitmap*)__bmp_usb_plugged); #define BL_GREEN COLOR2FLAGS(RGB(73, 219, 62)) #define BL_RED COLOR2FLAGS(RGB(229, 32, 30)) #define BL_BACKGROUND COLOR_BLACK #define BL_FOREGROUND COLOR_WHITE #define BL_SELECTED COLOR2FLAGS(RGB(11, 65, 244)) // deep blue extern BitmapBuffer * lcd; #if defined(USB_SW_GPIO) #define USB_SW_TO_INTERNAL_MODULE() gpio_set(USB_SW_GPIO); #define USB_SW_TO_MCU() gpio_clear(USB_SW_GPIO); static bool rfUsbAccess = false; #endif void bootloaderInitScreen() { lcdInitDisplayDriver(); #if defined(USE_HATS_AS_KEYS) setHatsAsKeys(true); #endif } static void bootloaderDrawTitle(const char* text) { lcd->drawText(LCD_W/2, DEFAULT_PADDING, text, CENTERED | BL_FOREGROUND); lcd->drawSolidFilledRect(DEFAULT_PADDING, DOUBLE_PADDING, LCD_W - DOUBLE_PADDING, 2, BL_FOREGROUND); } static void bootloaderDrawFooter() { if (LCD_W > LCD_H) lcd->drawSolidFilledRect(DEFAULT_PADDING, LCD_H - (DEFAULT_PADDING + 10), LCD_W - DOUBLE_PADDING, 2, BL_FOREGROUND); else lcd->drawSolidFilledRect(DEFAULT_PADDING, LCD_H - (DOUBLE_PADDING + 4), LCD_W - DOUBLE_PADDING, 2, BL_FOREGROUND); } static void bootloaderDrawBackground() { lcd->clear(BL_BACKGROUND); } void bootloaderDrawScreen(BootloaderState st, int opt, const char* str) { static bool _first_screen = true; lcdInitDirectDrawing(); bootloaderDrawBackground(); if (!_first_screen) { // ... and turn backlight ON backlightEnable(BACKLIGHT_LEVEL_MAX); } int center = LCD_W/2; int menuItemX = center - 120; if (st == ST_START) { int y = 75; bootloaderDrawTitle(BOOTLOADER_TITLE); lcd->drawText(menuItemX + 2, y, LV_SYMBOL_CHARGE, BL_FOREGROUND); coord_t pos = lcd->drawText(menuItemX + 24, y, TR_BL_WRITE_FW, BL_FOREGROUND); pos += 8; coord_t npos; y += 35; #if defined(SPI_FLASH) lcd->drawText(menuItemX + 2, y, LV_SYMBOL_SD_CARD, BL_FOREGROUND); npos = lcd->drawText(menuItemX + 24, y, TR_BL_ERASE_FLASH, BL_FOREGROUND); npos += 8; if (npos > pos) pos = npos; y += 35; #endif #if defined(USB_SW_GPIO) #if defined(RADIO_NV14_FAMILY) if(hardwareOptions.pcbrev == PCBREV_EL18) #endif { lcd->drawText(menuItemX, y, LV_SYMBOL_WIFI, BL_FOREGROUND); npos = lcd->drawText(menuItemX + 24, y, TR_BL_RF_USB_ACCESS, BL_FOREGROUND); npos += 8; if (npos > pos) pos = npos; y += 35; } #endif lcd->drawText(menuItemX, y, LV_SYMBOL_NEW_LINE, BL_FOREGROUND); lcd->drawText(menuItemX + 24, y, TR_BL_EXIT, BL_FOREGROUND); pos -= menuItemX - 8; lcd->drawSolidRect(menuItemX - 8, 72 + (opt * 35), pos, 26, 2, BL_SELECTED); if (LCD_W > LCD_H) { lcd->drawBitmap(menuItemX - 40, LCD_H - 106, (const BitmapBuffer*)&BMP_PLUG_USB); lcd->drawText(menuItemX + 95, LCD_H - 97, TR_BL_USB_PLUGIN, BL_FOREGROUND); lcd->drawText(menuItemX + 95, LCD_H - 72, TR_BL_USB_MASS_STORE, BL_FOREGROUND); } else { lcd->drawBitmap(center - 55, LCD_H - DEFAULT_PADDING - 157, (const BitmapBuffer*)&BMP_PLUG_USB); lcd->drawText(center, LCD_H - DEFAULT_PADDING - 97, TR_BL_USB_PLUGIN, CENTERED | BL_FOREGROUND); lcd->drawText(center, LCD_H - DEFAULT_PADDING - 72, TR_BL_USB_MASS_STORE, CENTERED | BL_FOREGROUND); } bootloaderDrawFooter(); if (LCD_W < LCD_H) lcd->drawText(center, LCD_H - DOUBLE_PADDING, TR_BL_CURRENT_FW, CENTERED | BL_FOREGROUND); lcd->drawText(center, LCD_H - DEFAULT_PADDING, getFirmwareVersion(), CENTERED | BL_FOREGROUND); } #if defined(SPI_FLASH) else if (st == ST_CLEAR_FLASH_CHECK) { bootloaderDrawTitle(TR_BL_ERASE_INT_FLASH); lcd->drawText(menuItemX + 2, 75, LV_SYMBOL_SD_CARD, BL_FOREGROUND); coord_t pos = lcd->drawText(menuItemX + 24, 75, TR_BL_ERASE_FLASH, BL_FOREGROUND); pos += 8; lcd->drawText(menuItemX, 110, LV_SYMBOL_NEW_LINE, BL_FOREGROUND); lcd->drawText(menuItemX + 24, 110, TR_BL_EXIT, BL_FOREGROUND); pos -= menuItemX - 8; lcd->drawSolidRect(menuItemX - 8, 72 + (opt * 35), pos, 26, 2, BL_SELECTED); bootloaderDrawFooter(); if (LCD_W > LCD_H) { lcd->drawText(DEFAULT_PADDING, LCD_H - DEFAULT_PADDING, LV_SYMBOL_SD_CARD " " TR_BL_ERASE_KEY, BL_FOREGROUND); lcd->drawText(LCD_W - 175, LCD_H - DEFAULT_PADDING, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, BL_FOREGROUND); } else { lcd->drawText(DOUBLE_PADDING, LCD_H - DOUBLE_PADDING, LV_SYMBOL_SD_CARD " " TR_BL_ERASE_KEY, BL_FOREGROUND); lcd->drawText(DOUBLE_PADDING, LCD_H - DEFAULT_PADDING, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, BL_FOREGROUND); } } else if (st == ST_CLEAR_FLASH) { bootloaderDrawTitle(TR_BL_ERASE_INT_FLASH); lcd->drawText(center, 75, TR_BL_ERASE_FLASH_MSG, CENTERED | BL_FOREGROUND); bootloaderDrawFooter(); } #endif #if defined(USB_SW_GPIO) else if (st == ST_RADIO_MENU) { bootloaderDrawTitle(TR_BL_RF_USB_ACCESS); lcd->drawText(menuItemX + 2, 75, LV_SYMBOL_USB, BL_FOREGROUND); coord_t pos = lcd->drawText(menuItemX + 24, 75, rfUsbAccess ? TR_BL_DISABLE : TR_BL_ENABLE, BL_FOREGROUND); pos += 8; lcd->drawText(menuItemX + 2, 110, LV_SYMBOL_NEW_LINE, BL_FOREGROUND); lcd->drawText(menuItemX + 24, 110, TR_BL_EXIT, BL_FOREGROUND); pos -= menuItemX - 8; lcd->drawSolidRect(menuItemX - 8, 72 + (opt * 35), pos, 26, 2, BL_SELECTED); } #endif else if (st == ST_USB) { lcd->drawBitmap(center - 26, 98, (const BitmapBuffer*)&BMP_USB_PLUGGED); lcd->drawText(center, 168, TR_BL_USB_CONNECTED, CENTERED | BL_FOREGROUND); } else if (st == ST_FILE_LIST || st == ST_DIR_CHECK || st == ST_FLASH_CHECK || st == ST_FLASHING || st == ST_FLASH_DONE) { bootloaderDrawTitle(LV_SYMBOL_SD_CARD " /FIRMWARE"); if (st == ST_FLASHING || st == ST_FLASH_DONE) { LcdFlags color = BL_RED; // red if (st == ST_FLASH_DONE) { color = BL_GREEN /* green */; opt = 100; // Completed > 100% } lcd->drawRect(DEFAULT_PADDING, 120, LCD_W - DOUBLE_PADDING, 31, 2, SOLID, BL_SELECTED); lcd->drawSolidFilledRect(DEFAULT_PADDING + 4, 124, ((LCD_W - DOUBLE_PADDING - 8) * opt) / 100, 23, color); } else if (st == ST_DIR_CHECK) { if (opt == FR_NO_PATH) { lcd->drawText(20, MESSAGE_TOP, LV_SYMBOL_CLOSE TR_BL_DIR_MISSING, BL_FOREGROUND); } else { lcd->drawText(20, MESSAGE_TOP, LV_SYMBOL_CLOSE TR_BL_DIR_EMPTY, BL_FOREGROUND); } } else if (st == ST_FLASH_CHECK) { bootloaderDrawFilename(str, 0, true); if (opt == FC_ERROR) { lcd->drawText(20, MESSAGE_TOP, LV_SYMBOL_CLOSE " " TR_BL_INVALID_FIRMWARE, BL_FOREGROUND); } else if (opt == FC_OK) { VersionTag tag; memset(&tag, 0, sizeof(tag)); getFileFirmwareVersion(&tag); if (strcmp(tag.flavour, FLAVOUR)) { lcd->drawText(20, MESSAGE_TOP, LV_SYMBOL_CLOSE " " TR_BL_INVALID_FIRMWARE, BL_FOREGROUND); } else { lcd->drawText(LCD_W / 4 + DEFAULT_PADDING, MESSAGE_TOP - DEFAULT_PADDING, TR_BL_FORK, RIGHT | BL_FOREGROUND); lcd->drawSizedText(LCD_W / 4 + 6 + DEFAULT_PADDING, MESSAGE_TOP - DEFAULT_PADDING, tag.fork, 6, BL_FOREGROUND); lcd->drawText(LCD_W / 4 + DEFAULT_PADDING, MESSAGE_TOP, TR_BL_VERSION, RIGHT | BL_FOREGROUND); lcd->drawText(LCD_W / 4 + 6 + DEFAULT_PADDING, MESSAGE_TOP, tag.version, BL_FOREGROUND); lcd->drawText(LCD_W / 4 + DEFAULT_PADDING, MESSAGE_TOP + DEFAULT_PADDING, TR_BL_RADIO, RIGHT | BL_FOREGROUND); lcd->drawText(LCD_W / 4 + 6 + DEFAULT_PADDING, MESSAGE_TOP + DEFAULT_PADDING, tag.flavour, BL_FOREGROUND); lcd->drawText(LCD_W > LCD_H ? DOUBLE_PADDING : DEFAULT_PADDING, MESSAGE_TOP, LV_SYMBOL_OK, BL_GREEN); } } } bootloaderDrawFooter(); if (st != ST_DIR_CHECK && (st != ST_FLASH_CHECK || opt == FC_OK)) { int padding = DOUBLE_PADDING; if (LCD_W > LCD_H) padding = DEFAULT_PADDING; if (st == ST_FILE_LIST) { lcd->drawText(padding, LCD_H - padding, LV_SYMBOL_CHARGE " " TR_BL_SELECT_KEY, BL_FOREGROUND); } else if (st == ST_FLASH_CHECK && opt == FC_OK) { lcd->drawText(padding, LCD_H - padding, LV_SYMBOL_CHARGE " " TR_BL_FLASH_KEY, BL_FOREGROUND); } else if (st == ST_FLASHING) { lcd->drawText(padding, LCD_H - padding, LV_SYMBOL_CHARGE " " TR_BL_WRITING_FW, BL_FOREGROUND); } else if (st == ST_FLASH_DONE) { lcd->drawText(padding, LCD_H - padding, LV_SYMBOL_CHARGE " " TR_BL_WRITING_COMPL, BL_FOREGROUND); } } if (st != ST_FLASHING) { if (LCD_W > LCD_H) { lcd->drawText(LCD_W - 175, LCD_H - DEFAULT_PADDING, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, BL_FOREGROUND); } else { lcd->drawText(DOUBLE_PADDING, LCD_H - DEFAULT_PADDING, LV_SYMBOL_NEW_LINE " " TR_BL_EXIT_KEY, BL_FOREGROUND); } } } _first_screen = false; } void bootloaderDrawFilename(const char* str, uint8_t line, bool selected) { lcd->drawText(DEFAULT_PADDING, 75 + (line * 25), LV_SYMBOL_FILE, BL_FOREGROUND); lcd->drawText(DEFAULT_PADDING + 30, 75 + (line * 25), str, BL_FOREGROUND); if (selected) { lcd->drawSolidRect(DEFAULT_PADDING + 25, 72 + (line * 25), LCD_W - (DEFAULT_PADDING + 25) - 28, 26, 2, BL_SELECTED); } } uint32_t bootloaderGetMenuItemCount(int baseCount) { uint8_t n = 0; #if defined(USB_SW_GPIO) #if defined(RADIO_NV14_FAMILY) if(hardwareOptions.pcbrev == PCBREV_EL18) #endif n = 1; #endif return baseCount + n; } bool bootloaderRadioMenu(uint32_t menuItem, event_t event) { #if defined(USB_SW_GPIO) static int pos = 0; if (event == EVT_KEY_FIRST(KEY_DOWN)) { if (pos < RADIO_MENU_LEN-1) pos++; } else if (event == EVT_KEY_FIRST(KEY_UP)) { if (pos > 0) pos--; } else if (event == EVT_KEY_BREAK(KEY_ENTER)) { switch (pos) { case 0: if (rfUsbAccess) { rfUsbAccess = false; INTERNAL_MODULE_OFF(); USB_SW_TO_MCU(); } else { rfUsbAccess = true; INTERNAL_MODULE_ON(); USB_SW_TO_INTERNAL_MODULE(); } break; case 1: // fall through default: USB_SW_TO_MCU(); pos = 0; return true; } } bootloaderDrawScreen(ST_RADIO_MENU, pos, nullptr); return false; #else return true; #endif } void blExit(void) { #if defined(USB_SW_GPIO) USB_SW_TO_MCU(); #endif lcdClear(); lcdRefresh(); lcdRefreshWait(); }