diff --git a/radio/src/bmp.cpp b/radio/src/bmp.cpp index 313396f49..8e0671d33 100644 --- a/radio/src/bmp.cpp +++ b/radio/src/bmp.cpp @@ -21,37 +21,37 @@ #include "opentx.h" #if defined(PCBTARANIS) -const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint16_t height) +uint8_t * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint16_t height) { FIL bmpFile; UINT read; uint8_t palette[16]; uint8_t bmpBuf[LCD_W]; /* maximum with LCD_W */ - uint8_t *buf = &bmpBuf[0]; + uint8_t * buf = &bmpBuf[0]; if (width > LCD_W) { - return STR_INCOMPATIBLE; + return NULL; } FRESULT result = f_open(&bmpFile, filename, FA_OPEN_EXISTING | FA_READ); if (result != FR_OK) { - return SDCARD_ERROR(result); + return NULL; } if (f_size(&bmpFile) < 14) { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } result = f_read(&bmpFile, buf, 14, &read); if (result != FR_OK || read != 14) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } if (buf[0] != 'B' || buf[1] != 'M') { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } uint32_t fsize = *((uint32_t *)&buf[2]); @@ -61,7 +61,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 result = f_read(&bmpFile, buf, len, &read); if (result != FR_OK || read != len) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } uint32_t ihsize = *((uint32_t *)&buf[0]); /* more header size */ @@ -69,7 +69,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 /* invalid header size */ if (ihsize + 14 > hsize) { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } /* sometimes file size is set to some headers size, set a real size in that case */ @@ -79,7 +79,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 /* declared file size less than header size */ if (fsize <= hsize) { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } uint32_t w, h; @@ -101,17 +101,17 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 break; default: f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } if (*((uint16_t *)&buf[0]) != 1) { /* planes */ f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } if (w > width || h > height) { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } uint16_t depth = *((uint16_t *)&buf[2]); @@ -121,7 +121,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 if (depth == 4) { if (f_lseek(&bmpFile, hsize-64) != FR_OK || f_read(&bmpFile, buf, 64, &read) != FR_OK || read != 64) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } for (uint8_t i=0; i<16; i++) { palette[i] = buf[4*i] >> 4; @@ -130,11 +130,11 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 else { if (f_lseek(&bmpFile, hsize) != FR_OK) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } } - uint8_t *dest = bmp; + uint8_t * dest = bmp; *dest++ = w; *dest++ = h; @@ -150,7 +150,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 result = f_read(&bmpFile, buf, rowSize*2, &read); if (result != FR_OK || read != rowSize*2) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } for (uint32_t j=0; j LCD_W) { - return STR_INCOMPATIBLE; - } + uint8_t * buf = &bmpBuf[0]; FRESULT result = f_open(&bmpFile, filename, FA_OPEN_EXISTING | FA_READ); if (result != FR_OK) { - return SDCARD_ERROR(result); + return NULL; } if (f_size(&bmpFile) < 14) { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } result = f_read(&bmpFile, buf, 14, &read); if (result != FR_OK || read != 14) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } if (buf[0] != 'B' || buf[1] != 'M') { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } uint32_t fsize = *((uint32_t *)&buf[2]); @@ -233,7 +225,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 result = f_read(&bmpFile, buf, len, &read); if (result != FR_OK || read != len) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } uint32_t ihsize = *((uint32_t *)&buf[0]); /* more header size */ @@ -241,7 +233,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 /* invalid header size */ if (ihsize + 14 > hsize) { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } /* sometimes file size is set to some headers size, set a real size in that case */ @@ -251,7 +243,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 /* declared file size less than header size */ if (fsize <= hsize) { f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } uint32_t w, h; @@ -273,17 +265,12 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 break; default: f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } if (*((uint16_t *)&buf[0]) != 1) { /* planes */ f_close(&bmpFile); - return STR_INCOMPATIBLE; - } - - if (w > width || h > height) { - f_close(&bmpFile); - return STR_INCOMPATIBLE; + return NULL; } uint16_t depth = *((uint16_t *)&buf[2]); @@ -293,7 +280,7 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 if (depth == 4) { if (f_lseek(&bmpFile, hsize-64) != FR_OK || f_read(&bmpFile, buf, 64, &read) != FR_OK || read != 64) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } for (uint8_t i=0; i<16; i++) { palette[i] = buf[4*i]; @@ -302,13 +289,19 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 else { if (f_lseek(&bmpFile, hsize) != FR_OK) { f_close(&bmpFile); - return SDCARD_ERROR(result); + return NULL; } } + uint8_t * bmp = (uint8_t *)malloc(BITMAP_BUFFER_SIZE(w, h)); + uint16_t * dest = (uint16_t *)bmp; + if (bmp == NULL) { + f_close(&bmpFile); + return NULL; + } + *dest++ = w; *dest++ = h; - memset(dest, 0, BITMAP_BUFFER_SIZE(w, h) - 4); uint32_t rowSize; @@ -322,7 +315,8 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 result = f_read(&bmpFile, (uint8_t *)&pixel, 4, &read); if (result != FR_OK || read != 4) { f_close(&bmpFile); - return SDCARD_ERROR(result); + free(bmp); + return NULL; } *((uint16_t *)dst) = RGB((pixel>>24) & 0xff, (pixel>>16) & 0xff, (pixel>>8) & 0xff); dst += 2; @@ -339,7 +333,8 @@ const char * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint1 result = f_read(&bmpFile, buf, rowSize, &read); if (result != FR_OK || read != rowSize) { f_close(&bmpFile); - return SDCARD_ERROR(result); + free(bmp); + return NULL; } uint8_t * dst = ((uint8_t *)dest) + i*w*2; for (uint32_t j=0; j #include "../../opentx.h" -#define REFRESH_FILES() do { reusableBuffer.sdmanager.offset = 65535; lastBitmap = -1; } while (0) +#define REFRESH_FILES() do { reusableBuffer.sdmanager.offset = 65535; currentBitmapIndex = -1; } while (0) #define NODE_TYPE(fname) fname[SD_SCREEN_FILE_LENGTH+1] #define IS_DIRECTORY(fname) ((bool)(!NODE_TYPE(fname))) #define IS_FILE(fname) ((bool)(NODE_TYPE(fname))) -int lastBitmap; +int currentBitmapIndex = 0; +uint8_t * currentBitmap = NULL; bool menuGeneralSdManagerInfo(evt_t event) { @@ -362,13 +363,15 @@ bool menuGeneralSdManager(evt_t _event) char * ext = getFileExtension(reusableBuffer.sdmanager.lines[index], SD_SCREEN_FILE_LENGTH+1); if (ext && (!strcasecmp(ext, BITMAPS_EXT) || !strcasecmp(ext, PNG_EXT) || !strcasecmp(ext, JPG_EXT))) { - if (lastBitmap != menuVerticalPosition) { - lastBitmap = menuVerticalPosition; - if (bmpLoad(modelBitmap, reusableBuffer.sdmanager.lines[index], MODEL_BITMAP_WIDTH, MODEL_BITMAP_HEIGHT)) { - ((uint32_t *)modelBitmap)[0] = 0; - } + if (currentBitmapIndex != menuVerticalPosition) { + currentBitmapIndex = menuVerticalPosition; + free(currentBitmap); + currentBitmap = bmpLoad(reusableBuffer.sdmanager.lines[index]); + } + if (currentBitmap) { + // TODO scale in case of a too large bitmap + lcdDrawBitmap(LCD_W / 2, LCD_H / 2, currentBitmap); } - lcdDrawBitmap(LCD_W/2, (LCD_H-MODEL_BITMAP_HEIGHT)/2, modelBitmap); } return true; diff --git a/radio/src/gui/horus/menu_model_select.cpp b/radio/src/gui/horus/menu_model_select.cpp index 25ecc8dd4..21f8ed660 100644 --- a/radio/src/gui/horus/menu_model_select.cpp +++ b/radio/src/gui/horus/menu_model_select.cpp @@ -61,8 +61,10 @@ void drawModel(coord_t x, coord_t y, const char * name, bool selected) for (int i=0; i<4; i++) { lcdDrawBitmapPattern(x+104+i*11, y+25, LBM_SCORE0, TITLE_BGCOLOR); } - if (loadModelBitmap(header.bitmap, modelBitmap)) { - lcdDrawBitmap(x+5, y+24, modelBitmap, 0, 0, getBitmapScale(modelBitmap, 64, 32)); + uint8_t * bitmap = bmpLoad(header.bitmap); + if (bitmap) { + lcdDrawBitmap(x+5, y+24, bitmap, 0, 0, getBitmapScale(bitmap, 64, 32)); + free(bitmap); } else { lcdDrawBitmapPattern(x+5, y+23, LBM_LIBRARY_SLOT, TEXT_COLOR); diff --git a/radio/src/gui/horus/menu_model_setup.cpp b/radio/src/gui/horus/menu_model_setup.cpp index 5b895d1e5..916df74af 100644 --- a/radio/src/gui/horus/menu_model_setup.cpp +++ b/radio/src/gui/horus/menu_model_setup.cpp @@ -77,8 +77,6 @@ enum menuModelSetupItems { ITEM_MODEL_SETUP_MAX }; -#define FIELD_PROTOCOL_MAX 1 - #define MODEL_SETUP_2ND_COLUMN 200 #define MODEL_SETUP_BIND_OFS 40 #define MODEL_SETUP_RANGE_OFS 80 @@ -94,7 +92,6 @@ void onModelSetupBitmapMenu(const char *result) else { // The user choosed a bmp file in the list copySelection(g_model.header.bitmap, result, sizeof(g_model.header.bitmap)); - loadModelBitmap(g_model.header.bitmap, modelBitmap); storageDirty(EE_MODEL); } } diff --git a/radio/src/gui/horus/popups.cpp b/radio/src/gui/horus/popups.cpp index ca7fd331b..07f5dfebc 100644 --- a/radio/src/gui/horus/popups.cpp +++ b/radio/src/gui/horus/popups.cpp @@ -173,7 +173,7 @@ const char * displayPopupMenu(evt_t event) } if (popupMenuNoItems > display_count) { - drawVerticalScrollbar(MENU_X+MENU_W-1, y+1, POPUP_MENU_MAX_LINES * (FH+1), popupMenuOffset, popupMenuNoItems, POPUP_MENU_MAX_LINES); + drawVerticalScrollbar(MENU_X+MENU_W-1, y+1, MENU_MAX_DISPLAY_LINES * (FH+1), popupMenuOffset, popupMenuNoItems, MENU_MAX_DISPLAY_LINES); } return result; diff --git a/radio/src/gui/horus/widgets/modelbmp.cpp b/radio/src/gui/horus/widgets/modelbmp.cpp index 18bb47084..cc8226058 100644 --- a/radio/src/gui/horus/widgets/modelbmp.cpp +++ b/radio/src/gui/horus/widgets/modelbmp.cpp @@ -24,30 +24,57 @@ class ModelBitmapWidget: public Widget { public: ModelBitmapWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData): - Widget(factory, zone, persistentData) + Widget(factory, zone, persistentData), + bitmap(NULL) { + memset(bitmapFilename, 0, sizeof(bitmapFilename)); + } + + void loadBitmap() + { + char filename[] = BITMAPS_PATH "/xxxxxxxxxx.bmp"; + strncpy(filename+sizeof(BITMAPS_PATH), g_model.header.bitmap, sizeof(g_model.header.bitmap)); + strcat(filename+sizeof(BITMAPS_PATH), BITMAPS_EXT); + bitmap = bmpLoad(filename); + memcpy(bitmapFilename, g_model.header.bitmap, sizeof(g_model.header.bitmap)); + // TODO rescale the bitmap here instead of every refresh! + } + + virtual ~ModelBitmapWidget() + { + free(bitmap); } virtual void refresh(); + + protected: + char bitmapFilename[sizeof(g_model.header.bitmap)]; + uint8_t * bitmap; }; void ModelBitmapWidget::refresh() { - if (zone.h >= MODEL_BITMAP_HEIGHT) { + if (memcmp(bitmapFilename, g_model.header.bitmap, sizeof(g_model.header.bitmap)) != 0) { + loadBitmap(); + } + + if (zone.h >= 96) { lcdDrawFilledRect(zone.x, zone.y, zone.w, zone.h, SOLID, MAINVIEW_PANES_COLOR | OPACITY(5)); lcdDrawBitmapPattern(zone.x + 6, zone.y + 4, LBM_MODEL_ICON, MAINVIEW_GRAPHICS_COLOR); lcdDrawSizedText(zone.x + 45, zone.y + 10, g_model.header.name, LEN_MODEL_NAME, ZCHAR | SMLSIZE); lcdDrawSolidFilledRect(zone.x + 39, zone.y + 27, zone.w - 48, 2, MAINVIEW_GRAPHICS_COLOR); - float scale = getBitmapScale(modelBitmap, zone.w, zone.h - 25); - int width = getBitmapScaledSize(getBitmapWidth(modelBitmap), scale); - int height = getBitmapScaledSize(getBitmapHeight(modelBitmap), scale); - lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + zone.h - height / 2 - height / 2, modelBitmap, 0, 0, scale); + if (bitmap) { + float scale = getBitmapScale(bitmap, zone.w, zone.h - 25); + int width = getBitmapScaledSize(getBitmapWidth(bitmap), scale); + int height = getBitmapScaledSize(getBitmapHeight(bitmap), scale); + lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + zone.h - height / 2 - height / 2, bitmap, 0, 0, scale); + } } - else { - float scale = getBitmapScale(modelBitmap, 1000, zone.h); - int width = getBitmapScaledSize(getBitmapWidth(modelBitmap), scale); - int height = getBitmapScaledSize(getBitmapHeight(modelBitmap), scale); - lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + (zone.h - height) / 2, modelBitmap, 0, 0, scale); + else if (bitmap) { + float scale = getBitmapScale(bitmap, 1000, zone.h); + int width = getBitmapScaledSize(getBitmapWidth(bitmap), scale); + int height = getBitmapScaledSize(getBitmapHeight(bitmap), scale); + lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + (zone.h - height) / 2, bitmap, 0, 0, scale); } } diff --git a/radio/src/lua/api_lcd.cpp b/radio/src/lua/api_lcd.cpp index b48d68a4f..7c6a03b9e 100644 --- a/radio/src/lua/api_lcd.cpp +++ b/radio/src/lua/api_lcd.cpp @@ -352,11 +352,20 @@ static int luaLcdDrawPixmap(lua_State *L) int x = luaL_checkinteger(L, 1); int y = luaL_checkinteger(L, 2); const char * filename = luaL_checkstring(L, 3); + +#if defined(PCBTARANIS) uint8_t bitmap[BITMAP_BUFFER_SIZE(LCD_W/2, LCD_H)]; // width max is LCD_W/2 pixels for saving stack and avoid a malloc here - const pm_char * error = bmpLoad(bitmap, filename, LCD_W/2, LCD_H); - if (!error) { + if (bmpLoad(bitmap, filename, LCD_W/2, LCD_H)) { lcdDrawBitmap(x, y, bitmap); } +#else + uint8_t * bitmap = bmpLoad(filename); + if (bitmap) { + lcdDrawBitmap(x, y, bitmap); + free(bitmap); + } +#endif + return 0; } #endif diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index 15c3c9a1f..a026ee881 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -905,10 +905,8 @@ void luaLoadThemeCallback() char path[LUA_FULLPATH_MAXLEN+1]; strcpy(path, THEMES_PATH "/"); strcpy(path+sizeof(THEMES_PATH), bitmap); - uint8_t * bitmapData = (uint8_t *)malloc(BITMAP_BUFFER_SIZE(51, 31)); - TRACE("path=%s bitmapData=%p %d %p", path, bitmapData, BITMAP_BUFFER_SIZE(51, 31), path); - bmpLoad(bitmapData, path, 51, 31); - LuaTheme * theme = new LuaTheme(name, bitmapData, themeOptions); + uint8_t * bitmap = bmpLoad(path/*, 51, 31*/); // TODO rescale + LuaTheme * theme = new LuaTheme(name, bitmap, themeOptions); theme->loadFunction = loadFunction; theme->drawBackgroundFunction = drawBackgroundFunction; theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index e2c89925a..464e68b20 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -30,9 +30,7 @@ Clipboard clipboard; #if defined(PCBTARANIS) uint8_t modelBitmap[MODEL_BITMAP_SIZE] __DMA; -#endif -#if defined(PCBTARANIS) || defined(PCBHORUS) bool loadModelBitmap(char * name, uint8_t * bitmap) { uint8_t len = zlen(name, LEN_BITMAP_NAME); @@ -45,13 +43,8 @@ bool loadModelBitmap(char * name, uint8_t * bitmap) } } -#if defined(COLORLCD) - // TODO only the first bytes can be set to 0 - memset(bitmap, 0, MODEL_BITMAP_SIZE); -#else // In all error cases, we set the default logo memcpy(bitmap, logo_taranis, MODEL_BITMAP_SIZE); -#endif return false; } diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp index 8ab931a3a..38280a756 100644 --- a/radio/src/targets/horus/lcd_driver.cpp +++ b/radio/src/targets/horus/lcd_driver.cpp @@ -47,8 +47,6 @@ uint32_t CurrentLayer = LCD_FIRST_LAYER; #define NRST_LOW() do { LCD_GPIO_NRST->BSRRH = LCD_GPIO_PIN_NRST; } while(0) #define NRST_HIGH() do { LCD_GPIO_NRST->BSRRL = LCD_GPIO_PIN_NRST; } while(0) -uint8_t modelBitmap[MODEL_BITMAP_SIZE] __SDRAM; - static void LCD_AF_GPIOConfig(void) { GPIO_InitTypeDef GPIO_InitStructure;