From afcac1557b9dfc64220ea48a0a97333b2e8f428b Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sat, 14 May 2022 19:32:14 +0200 Subject: [PATCH 1/2] Remove framebuffer pointer from function calls, implement file browser that can install binaries and an uninstaller --- main/graphics_wrapper.c | 48 ++--- main/include/graphics_wrapper.h | 4 +- main/include/rp2040_updater.h | 2 +- main/main.c | 348 +++++++++++++++++++++++++++++--- main/rp2040_updater.c | 42 ++-- 5 files changed, 369 insertions(+), 75 deletions(-) diff --git a/main/graphics_wrapper.c b/main/graphics_wrapper.c index 77561ae..96e0331 100644 --- a/main/graphics_wrapper.c +++ b/main/graphics_wrapper.c @@ -4,18 +4,18 @@ #include "pax_keyboard.h" #include "rp2040.h" -void render_message(pax_buf_t *aBuffer, char* message, float aPosX, float aPosY, float aWidth, float aHeight) { +void render_message(pax_buf_t *pax_buffer, char* message, float aPosX, float aPosY, float aWidth, float aHeight) { pax_col_t fgColor = 0xFFFF0000; pax_col_t bgColor = 0xFFFFD4D4; - pax_clip(aBuffer, aPosX, aPosY, aWidth, aHeight); - pax_simple_rect(aBuffer, bgColor, aPosX, aPosY, aWidth, aHeight); - pax_outline_rect(aBuffer, fgColor, aPosX, aPosY, aWidth, aHeight); - pax_clip(aBuffer, aPosX + 1, aPosY + 1, aWidth - 2, aHeight - 2); - pax_draw_text(aBuffer, fgColor, NULL, 18, aPosX + 1, aPosY + 1, message); - pax_noclip(aBuffer); + pax_clip(pax_buffer, aPosX, aPosY, aWidth, aHeight); + pax_simple_rect(pax_buffer, bgColor, aPosX, aPosY, aWidth, aHeight); + pax_outline_rect(pax_buffer, fgColor, aPosX, aPosY, aWidth, aHeight); + pax_clip(pax_buffer, aPosX + 1, aPosY + 1, aWidth - 2, aHeight - 2); + pax_draw_text(pax_buffer, fgColor, NULL, 18, aPosX + 1, aPosY + 1, message); + pax_noclip(pax_buffer); } -esp_err_t graphics_task(pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuffer, menu_t* menu, char* message) { +esp_err_t graphics_task(pax_buf_t* pax_buffer, ILI9341* ili9341, menu_t* menu, char* message) { pax_background(pax_buffer, 0xCCCCCC); if (menu != NULL) { menu_render(pax_buffer, menu, 10, 10, 320-20, 240-20); @@ -25,13 +25,13 @@ esp_err_t graphics_task(pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* frameb render_message(pax_buffer, message, 20, 110, 320-40, 20); } - return ili9341_write(ili9341, framebuffer); + return ili9341_write(ili9341, pax_buffer->buf); } -bool keyboard(xQueueHandle buttonQueue, pax_buf_t* aBuffer, ILI9341* ili9341, uint8_t* framebuffer, float aPosX, float aPosY, float aWidth, float aHeight, const char* aTitle, const char* aHint, char* aOutput, size_t aOutputSize) { +bool keyboard(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, float aPosX, float aPosY, float aWidth, float aHeight, const char* aTitle, const char* aHint, char* aOutput, size_t aOutputSize) { bool accepted = false; pkb_ctx_t kb_ctx; - pkb_init(aBuffer, &kb_ctx, aOutput); + pkb_init(pax_buffer, &kb_ctx, aOutput); pax_col_t fgColor = 0xFF000000; pax_col_t bgColor = 0xFFFFFFFF; @@ -51,17 +51,17 @@ bool keyboard(xQueueHandle buttonQueue, pax_buf_t* aBuffer, ILI9341* ili9341, ui float titleHeight = 20; float hintHeight = 14; - pax_noclip(aBuffer); - pax_simple_rect(aBuffer, shadowColor, aPosX+5, aPosY+5, aWidth, aHeight); - pax_simple_rect(aBuffer, bgColor, aPosX, aPosY, aWidth, aHeight); - pax_outline_rect(aBuffer, borderColor, aPosX, aPosY, aWidth, aHeight); - pax_simple_rect(aBuffer, titleBgColor, aPosX, aPosY, aWidth, titleHeight); - pax_simple_line(aBuffer, titleColor, aPosX + 1, aPosY + titleHeight, aPosX + aWidth - 2, aPosY + titleHeight - 1); - pax_clip(aBuffer, aPosX + 1, aPosY + 1, aWidth - 2, titleHeight - 2); - pax_draw_text(aBuffer, titleColor, NULL, titleHeight - 2, aPosX + 1, aPosY + 1, aTitle); - pax_clip(aBuffer, aPosX + 1, aPosY + aHeight - hintHeight, aWidth - 2, hintHeight); - pax_draw_text(aBuffer, borderColor, NULL, hintHeight - 2, aPosX + 1, aPosY + aHeight - hintHeight, aHint); - pax_noclip(aBuffer); + pax_noclip(pax_buffer); + pax_simple_rect(pax_buffer, shadowColor, aPosX+5, aPosY+5, aWidth, aHeight); + pax_simple_rect(pax_buffer, bgColor, aPosX, aPosY, aWidth, aHeight); + pax_outline_rect(pax_buffer, borderColor, aPosX, aPosY, aWidth, aHeight); + pax_simple_rect(pax_buffer, titleBgColor, aPosX, aPosY, aWidth, titleHeight); + pax_simple_line(pax_buffer, titleColor, aPosX + 1, aPosY + titleHeight, aPosX + aWidth - 2, aPosY + titleHeight - 1); + pax_clip(pax_buffer, aPosX + 1, aPosY + 1, aWidth - 2, titleHeight - 2); + pax_draw_text(pax_buffer, titleColor, NULL, titleHeight - 2, aPosX + 1, aPosY + 1, aTitle); + pax_clip(pax_buffer, aPosX + 1, aPosY + aHeight - hintHeight, aWidth - 2, hintHeight); + pax_draw_text(pax_buffer, borderColor, NULL, hintHeight - 2, aPosX + 1, aPosY + aHeight - hintHeight, aHint); + pax_noclip(pax_buffer); kb_ctx.x = aPosX + 1; kb_ctx.y = aPosY + titleHeight + 1 ; @@ -142,8 +142,8 @@ bool keyboard(xQueueHandle buttonQueue, pax_buf_t* aBuffer, ILI9341* ili9341, ui } pkb_loop(&kb_ctx); if (kb_ctx.dirty) { - pkb_redraw(aBuffer, &kb_ctx); - ili9341_write(ili9341, framebuffer); + pkb_redraw(pax_buffer, &kb_ctx); + ili9341_write(ili9341, pax_buffer->buf); } if (kb_ctx.input_accepted) { memset(aOutput, 0, aOutputSize); diff --git a/main/include/graphics_wrapper.h b/main/include/graphics_wrapper.h index b3dd791..e34d852 100644 --- a/main/include/graphics_wrapper.h +++ b/main/include/graphics_wrapper.h @@ -12,5 +12,5 @@ #include "menu.h" -esp_err_t graphics_task(pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuffer, menu_t* menu, char* message); -bool keyboard(xQueueHandle buttonQueue, pax_buf_t* aBuffer, ILI9341* ili9341, uint8_t* framebuffer, float aPosX, float aPosY, float aWidth, float aHeight, const char* aTitle, const char* aHint, char* aOutput, size_t aOutputSize); +esp_err_t graphics_task(pax_buf_t* pax_buffer, ILI9341* ili9341, menu_t* menu, char* message); +bool keyboard(xQueueHandle buttonQueue, pax_buf_t* aBuffer, ILI9341* ili9341, float aPosX, float aPosY, float aWidth, float aHeight, const char* aTitle, const char* aHint, char* aOutput, size_t aOutputSize); diff --git a/main/include/rp2040_updater.h b/main/include/rp2040_updater.h index bdff60e..bc16ffe 100644 --- a/main/include/rp2040_updater.h +++ b/main/include/rp2040_updater.h @@ -10,4 +10,4 @@ #include "ili9341.h" -void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuffer); +void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341); diff --git a/main/main.c b/main/main.c index 4a271cd..366d5b2 100644 --- a/main/main.c +++ b/main/main.c @@ -37,6 +37,8 @@ #include "wifi_ota.h" +#include "esp_vfs.h" + static const char *TAG = "main"; typedef enum action { @@ -51,7 +53,9 @@ typedef enum action { ACTION_WIFI_SCAN, ACTION_WIFI_MANUAL, ACTION_WIFI_LIST, - ACTION_BACK + ACTION_BACK, + ACTION_FILE_BROWSER, + ACTION_UNINSTALL } menu_action_t; typedef struct _menu_args { @@ -59,21 +63,21 @@ typedef struct _menu_args { menu_action_t action; } menu_args_t; -void appfs_store_app(pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuffer) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Installing app..."); +void appfs_store_app(pax_buf_t* pax_buffer, ILI9341* ili9341, char* path, char* label) { + graphics_task(pax_buffer, ili9341, NULL, "Installing app..."); esp_err_t res; appfs_handle_t handle; - FILE* app_fd = fopen("/sd/gnuboy.bin", "rb"); + FILE* app_fd = fopen(path, "rb"); if (app_fd == NULL) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Failed to open gnuboy.bin"); - ESP_LOGE(TAG, "Failed to open gnuboy.bin"); + graphics_task(pax_buffer, ili9341, NULL, "Failed to open file"); + ESP_LOGE(TAG, "Failed to open file"); vTaskDelay(100 / portTICK_PERIOD_MS); return; } size_t app_size; uint8_t* app = load_file_to_ram(app_fd, &app_size); if (app == NULL) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Failed to load app to RAM"); + graphics_task(pax_buffer, ili9341, NULL, "Failed to load app to RAM"); ESP_LOGE(TAG, "Failed to load application into RAM"); vTaskDelay(100 / portTICK_PERIOD_MS); return; @@ -81,9 +85,9 @@ void appfs_store_app(pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuff ESP_LOGI(TAG, "Application size %d", app_size); - res = appfsCreateFile("gnuboy", app_size, &handle); + res = appfsCreateFile(label, app_size, &handle); if (res != ESP_OK) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Failed to create on AppFS"); + graphics_task(pax_buffer, ili9341, NULL, "Failed to create on AppFS"); ESP_LOGE(TAG, "Failed to create file on AppFS (%d)", res); vTaskDelay(100 / portTICK_PERIOD_MS); free(app); @@ -91,7 +95,7 @@ void appfs_store_app(pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuff } res = appfsWrite(handle, 0, app, app_size); if (res != ESP_OK) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Failed to write to AppFS"); + graphics_task(pax_buffer, ili9341, NULL, "Failed to write to AppFS"); ESP_LOGE(TAG, "Failed to write to file on AppFS (%d)", res); vTaskDelay(100 / portTICK_PERIOD_MS); free(app); @@ -99,12 +103,12 @@ void appfs_store_app(pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuff } free(app); ESP_LOGI(TAG, "Application is now stored in AppFS"); - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "App installed!"); + graphics_task(pax_buffer, ili9341, NULL, "App installed!"); vTaskDelay(100 / portTICK_PERIOD_MS); return; } -void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuffer, menu_action_t* menu_action, appfs_handle_t* appfs_fd) { +void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, menu_action_t* menu_action, appfs_handle_t* appfs_fd) { menu_t* menu = menu_alloc("Main menu"); *appfs_fd = APPFS_INVALID_FD; *menu_action = ACTION_NONE; @@ -144,6 +148,14 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili menu_args_t* wifi_connect_args = malloc(sizeof(menu_args_t)); wifi_connect_args->action = ACTION_WIFI_CONNECT; menu_insert_item(menu, "WiFi connect", NULL, wifi_connect_args, -1); + + menu_args_t* file_browser_args = malloc(sizeof(menu_args_t)); + file_browser_args->action = ACTION_FILE_BROWSER; + menu_insert_item(menu, "File browser", NULL, file_browser_args, -1); + + menu_args_t* uninstall_args = malloc(sizeof(menu_args_t)); + uninstall_args->action = ACTION_UNINSTALL; + menu_insert_item(menu, "Uninstall app", NULL, uninstall_args, -1); bool render = true; menu_args_t* menuArgs = NULL; @@ -177,7 +189,7 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili } if (render) { - graphics_task(pax_buffer, ili9341, framebuffer, menu, NULL); + graphics_task(pax_buffer, ili9341, menu, NULL); render = false; } @@ -195,7 +207,7 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili menu_free(menu); } -void menu_wifi_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuffer, menu_action_t* menu_action) { +void menu_wifi_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, menu_action_t* menu_action) { menu_t* menu = menu_alloc("WiFi settings"); *menu_action = ACTION_NONE; @@ -247,7 +259,7 @@ void menu_wifi_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341 } if (render) { - graphics_task(pax_buffer, ili9341, framebuffer, menu, NULL); + graphics_task(pax_buffer, ili9341, menu, NULL); render = false; } @@ -305,6 +317,276 @@ void wifi_connect_to_stored() { wifi_connect(ssid, password, WIFI_AUTH_WPA2_PSK, 3); } +void list_files_in_folder(const char* path) { + DIR* dir = opendir(path); + if (dir == NULL) { + ESP_LOGE(TAG, "Failed to open directory %s", path); + return; + } + + struct dirent *ent; + char type; + char size[12]; + char tpath[255]; + char tbuffer[80]; + struct stat sb; + struct tm *tm_info; + char *lpath = NULL; + int statok; + + uint64_t total = 0; + int nfiles = 0; + printf("T Size Date/Time Name\n"); + printf("-----------------------------------\n"); + while ((ent = readdir(dir)) != NULL) { + sprintf(tpath, path); + if (path[strlen(path)-1] != '/') { + strcat(tpath,"/"); + } + strcat(tpath,ent->d_name); + tbuffer[0] = '\0'; + + // Get file stat + statok = stat(tpath, &sb); + + if (statok == 0) { + tm_info = localtime(&sb.st_mtime); + strftime(tbuffer, 80, "%d/%m/%Y %R", tm_info); + } else { + sprintf(tbuffer, " "); + } + + if (ent->d_type == DT_REG) { + type = 'f'; + nfiles++; + if (statok) { + strcpy(size, " ?"); + } else { + total += sb.st_size; + if (sb.st_size < (1024*1024)) sprintf(size,"%8d", (int)sb.st_size); + else if ((sb.st_size/1024) < (1024*1024)) sprintf(size,"%6dKB", (int)(sb.st_size / 1024)); + else sprintf(size,"%6dMB", (int)(sb.st_size / (1024 * 1024))); + } + } else { + type = 'd'; + strcpy(size, " -"); + } + + printf("%c %s %s %s\r\n", type, size, tbuffer, ent->d_name); + } + + printf("-----------------------------------\n"); + if (total < (1024*1024)) printf(" %8d", (int)total); + else if ((total/1024) < (1024*1024)) printf(" %6dKB", (int)(total / 1024)); + else printf(" %6dMB", (int)(total / (1024 * 1024))); + printf(" in %d file(s)\n", nfiles); + printf("-----------------------------------\n"); + + closedir(dir); + free(lpath); +} + +typedef struct _uninstall_menu_args { + appfs_handle_t fd; + char name[512]; +} uninstall_menu_args_t; + +void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { + appfs_handle_t appfs_fd = APPFS_INVALID_FD; + menu_t* menu = menu_alloc("Uninstall application"); + while (1) { + appfs_fd = appfsNextEntry(appfs_fd); + if (appfs_fd == APPFS_INVALID_FD) break; + const char* name = NULL; + appfsEntryInfo(appfs_fd, &name, NULL); + uninstall_menu_args_t* args = malloc(sizeof(uninstall_menu_args_t)); + if (args == NULL) { + ESP_LOGE(TAG, "Failed to malloc() menu args"); + return; + } + args->fd = appfs_fd; + sprintf(args->name, name); + menu_insert_item(menu, name, NULL, (void*) args, -1); + } + uninstall_menu_args_t* menuArgs = NULL; + bool render = true; + bool exit = false; + while (1) { + rp2040_input_message_t buttonMessage = {0}; + if (xQueueReceive(buttonQueue, &buttonMessage, 16 / portTICK_PERIOD_MS) == pdTRUE) { + uint8_t pin = buttonMessage.input; + bool value = buttonMessage.state; + switch(pin) { + case RP2040_INPUT_JOYSTICK_DOWN: + if (value) { + menu_navigate_next(menu); + render = true; + } + break; + case RP2040_INPUT_JOYSTICK_UP: + if (value) { + menu_navigate_previous(menu); + render = true; + } + break; + case RP2040_INPUT_BUTTON_ACCEPT: + if (value) { + menuArgs = menu_get_callback_args(menu, menu_get_position(menu)); + } + break; + case RP2040_INPUT_BUTTON_HOME: + if (value) exit = true; + break; + default: + break; + } + } + + if (render) { + graphics_task(pax_buffer, ili9341, menu, NULL); + render = false; + } + + if (menuArgs != NULL) { + char message[1024]; + sprintf(message, "Uninstalling %s...", menuArgs->name); + printf("%s\n", message); + graphics_task(pax_buffer, ili9341, menu, message); + appfsDeleteFile(menuArgs->name); + menuArgs = NULL; + break; + } + + if (exit) { + break; + } + } + + for (size_t index = 0; index < menu_get_length(menu); index++) { + free(menu_get_callback_args(menu, index)); + } + + menu_free(menu); +} + +typedef struct _file_browser_menu_args { + char type; + char path[512]; + char label[512]; +} file_browser_menu_args_t; + +void find_parent_dir(char* path, char* parent) { + size_t last_separator = 0; + for (size_t index = 0; index < strlen(path); index++) { + if (path[index] == '/') last_separator = index; + } + + strcpy(parent, path); + parent[last_separator] = '\0'; +} + +void file_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { + char path[512] = "/sd"; + while (true) { + menu_t* menu = menu_alloc(path); + DIR* dir = opendir(path); + if (dir == NULL) { + ESP_LOGE(TAG, "Failed to open directory %s", path); + return; + } + struct dirent *ent; + file_browser_menu_args_t* pd_args = malloc(sizeof(file_browser_menu_args_t)); + pd_args->type = 'd'; + find_parent_dir(path, pd_args->path); + printf("Parent dir: %s\n", pd_args->path); + menu_insert_item(menu, "../", NULL, pd_args, -1); + + while ((ent = readdir(dir)) != NULL) { + file_browser_menu_args_t* args = malloc(sizeof(file_browser_menu_args_t)); + sprintf(args->path, path); + if (path[strlen(path)-1] != '/') { + strcat(args->path,"/"); + } + strcat(args->path,ent->d_name); + + if (ent->d_type == DT_REG) { + args->type = 'f'; + } else { + args->type = 'd'; + } + + printf("%c %s %s\r\n", args->type, ent->d_name, args->path); + + snprintf(args->label, sizeof(args->label), "%s%s", ent->d_name, (args->type == 'd') ? "/" : ""); + menu_insert_item(menu, args->label, NULL, args, -1); + } + closedir(dir); + + bool render = true; + bool exit = false; + file_browser_menu_args_t* menuArgs = NULL; + + while (1) { + rp2040_input_message_t buttonMessage = {0}; + if (xQueueReceive(buttonQueue, &buttonMessage, 16 / portTICK_PERIOD_MS) == pdTRUE) { + uint8_t pin = buttonMessage.input; + bool value = buttonMessage.state; + switch(pin) { + case RP2040_INPUT_JOYSTICK_DOWN: + if (value) { + menu_navigate_next(menu); + render = true; + } + break; + case RP2040_INPUT_JOYSTICK_UP: + if (value) { + menu_navigate_previous(menu); + render = true; + } + break; + case RP2040_INPUT_BUTTON_ACCEPT: + if (value) { + menuArgs = menu_get_callback_args(menu, menu_get_position(menu)); + } + break; + case RP2040_INPUT_BUTTON_HOME: + if (value) exit = true; + break; + default: + break; + } + } + + if (render) { + graphics_task(pax_buffer, ili9341, menu, NULL); + render = false; + } + + if (menuArgs != NULL) { + if (menuArgs->type == 'd') { + strcpy(path, menuArgs->path); + break; + } else { + printf("File selected: %s\n", menuArgs->path); + appfs_store_app(pax_buffer, ili9341, menuArgs->path, menuArgs->label); + } + menuArgs = NULL; + render = true; + } + + if (exit) { + break; + } + } + + for (size_t index = 0; index < menu_get_length(menu); index++) { + free(menu_get_callback_args(menu, index)); + } + + menu_free(menu); + } +} + void app_main(void) { esp_err_t res; @@ -355,7 +637,7 @@ void app_main(void) { esp_restart(); } - rp2040_updater(rp2040, pax_buffer, ili9341, framebuffer); // Handle RP2040 firmware update & bootloader mode + rp2040_updater(rp2040, pax_buffer, ili9341); // Handle RP2040 firmware update & bootloader mode if (bsp_ice40_init() != ESP_OK) { ESP_LOGE(TAG, "Failed to initialize the ICE40 FPGA"); @@ -400,6 +682,9 @@ void app_main(void) { /* Start SD card */ res = mount_sd(SD_CMD, SD_CLK, SD_D0, SD_PWR, "/sd", false, 5); bool sdcard_ready = (res == ESP_OK); + if (sdcard_ready) { + list_files_in_folder("/sd"); + } /* Start LEDs */ ws2812_init(GPIO_LED_DATA); @@ -413,30 +698,33 @@ void app_main(void) { while (true) { menu_action_t menu_action; appfs_handle_t appfs_fd; - menu_launcher(rp2040->queue, pax_buffer, ili9341, framebuffer, &menu_action, &appfs_fd); + menu_launcher(rp2040->queue, pax_buffer, ili9341, &menu_action, &appfs_fd); if (menu_action == ACTION_APPFS) { appfs_boot_app(appfs_fd); } else if (menu_action == ACTION_FPGA) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Loading..."); + graphics_task(pax_buffer, ili9341, NULL, "Loading..."); fpga_test(ili9341, ice40, rp2040->queue); } else if (menu_action == ACTION_RP2040_BL) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "RP2040 update..."); + graphics_task(pax_buffer, ili9341, NULL, "RP2040 update..."); rp2040_reboot_to_bootloader(rp2040); esp_restart(); } else if (menu_action == ACTION_INSTALLER) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Installing..."); - appfs_store_app(pax_buffer, ili9341, framebuffer); + graphics_task(pax_buffer, ili9341, NULL, "Not implemented"); } else if (menu_action == ACTION_WIFI_CONNECT) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Connecting..."); + graphics_task(pax_buffer, ili9341, NULL, "Connecting..."); wifi_connect_to_stored(); } else if (menu_action == ACTION_OTA) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Connecting..."); + graphics_task(pax_buffer, ili9341, NULL, "Connecting..."); wifi_connect_to_stored(); - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Firmware update..."); + graphics_task(pax_buffer, ili9341, NULL, "Firmware update..."); ota_update(); + } else if (menu_action == ACTION_FILE_BROWSER) { + file_browser(rp2040->queue, pax_buffer, ili9341); + } else if (menu_action == ACTION_UNINSTALL) { + uninstall_browser(rp2040->queue, pax_buffer, ili9341); } else if (menu_action == ACTION_SETTINGS) { while (true) { - menu_wifi_settings(rp2040->queue, pax_buffer, ili9341, framebuffer, &menu_action); + menu_wifi_settings(rp2040->queue, pax_buffer, ili9341, &menu_action); if (menu_action == ACTION_WIFI_MANUAL) { nvs_handle_t handle; nvs_open("system", NVS_READWRITE, &handle); @@ -458,16 +746,16 @@ void app_main(void) { if (res != ESP_OK) strcpy(password, ""); } } - bool accepted = keyboard(rp2040->queue, pax_buffer, ili9341, framebuffer, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi SSID", "Press HOME to exit", ssid, sizeof(ssid)); + bool accepted = keyboard(rp2040->queue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi SSID", "Press HOME to exit", ssid, sizeof(ssid)); if (accepted) { - accepted = keyboard(rp2040->queue, pax_buffer, ili9341, framebuffer, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi password", "Press HOME to exit", password, sizeof(password)); + accepted = keyboard(rp2040->queue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi password", "Press HOME to exit", password, sizeof(password)); } if (accepted) { nvs_set_str(handle, "wifi.ssid", ssid); nvs_set_str(handle, "wifi.password", password); - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "WiFi settings stored"); + graphics_task(pax_buffer, ili9341, NULL, "WiFi settings stored"); } else { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Canceled"); + graphics_task(pax_buffer, ili9341, NULL, "Canceled"); } nvs_close(handle); } else if (menu_action == ACTION_WIFI_LIST) { @@ -493,7 +781,7 @@ void app_main(void) { nvs_close(handle); char buffer[300]; snprintf(buffer, sizeof(buffer), "SSID is %s\nPassword is %s", ssid, password); - graphics_task(pax_buffer, ili9341, framebuffer, NULL, buffer); + graphics_task(pax_buffer, ili9341, NULL, buffer); } else { break; } diff --git a/main/rp2040_updater.c b/main/rp2040_updater.c index 3f2d52e..cd7d757 100644 --- a/main/rp2040_updater.c +++ b/main/rp2040_updater.c @@ -18,7 +18,7 @@ #include "graphics_wrapper.h" #include "esp32/rom/crc.h" -void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uint8_t* framebuffer) { +void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341) { char message[64]; uint8_t fw_version; @@ -29,7 +29,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Failed to read firmware version"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); restart(); } @@ -38,7 +38,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin memset(message, 0, sizeof(message)); snprintf(message, sizeof(message) - 1, "RP2040 firmware: 0x%02X", fw_version); pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 20*0, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); vTaskDelay(100 / portTICK_PERIOD_MS);*/ if (fw_version < 0x01) { // Update required @@ -48,7 +48,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Starting bootloader"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); rp2040_reboot_to_bootloader(rp2040); esp_restart(); } @@ -58,7 +58,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_background(pax_buffer, 0x325aa8); snprintf(message, sizeof(message) - 1, "Updating RP2040..."); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); uint8_t bl_version; if (rp2040_get_bootloader_version(rp2040, &bl_version) != ESP_OK) { @@ -68,7 +68,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Communication error (1)"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); restart(); } if (bl_version != 0x01) { @@ -77,7 +77,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Unsupported bootloader version"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); restart(); } @@ -89,7 +89,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Waiting for bootloader"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); while (true) { vTaskDelay(1 / portTICK_PERIOD_MS); @@ -101,14 +101,20 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Communication error (2)"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); restart(); } if (bl_state == 0xB0) { break; } if (bl_state > 0xB0) { - graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Unknown BL state"); + pax_noclip(pax_buffer); + pax_background(pax_buffer, 0xa85a32); + snprintf(message, sizeof(message) - 1, "RP2040 update failed"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); + snprintf(message, sizeof(message) - 1, "Unknown bootloader state"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); + ili9341_write(ili9341, pax_buffer->buf); restart(); } } @@ -119,7 +125,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Waiting for bootloader sync"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); char rx_buffer[16]; uint8_t rx_buffer_pos = 0; @@ -140,7 +146,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Failed to read information"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); restart(); } @@ -150,7 +156,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Erasing flash"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); uint32_t erase_length = sizeof(mch2022_firmware_bin); erase_length = erase_length + erase_size - (erase_length % erase_size); // Round up to erase size @@ -168,7 +174,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Failed to erase flash"); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); vTaskDelay(1000 / portTICK_PERIOD_MS); restart(); } @@ -196,7 +202,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message); snprintf(message, sizeof(message) - 1, "Writing @ 0x%08X", 0x10010000 + position); pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); uint32_t checkCrc = 0; memset(txBuffer, 0, write_size); @@ -221,13 +227,13 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin memset(message, 0, sizeof(message)); snprintf(message, sizeof(message) - 1, "Sealing..."); pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 20*0, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); bool sealRes = rp2040_bl_seal(0x10010000, 0x10010000, totalLength, totalCrc); snprintf(message, sizeof(message) - 1, "Result: %s", sealRes ? "OK" : "FAIL"); pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 20*1, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); if (sealRes) { vTaskDelay(2000 / portTICK_PERIOD_MS); @@ -236,7 +242,7 @@ void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341, uin memset(message, 0, sizeof(message)); snprintf(message, sizeof(message) - 1, "Waiting for reset..."); pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 20*0, message); - ili9341_write(ili9341, framebuffer); + ili9341_write(ili9341, pax_buffer->buf); rp2040_bl_go(0x10010000); } From 8df4f62d516bf2dd0a6245dfc2484de41c68f14d Mon Sep 17 00:00:00 2001 From: Renze Nicolai Date: Sun, 15 May 2022 00:15:45 +0200 Subject: [PATCH 2/2] Add internal filesystem support --- main/main.c | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/main/main.c b/main/main.c index 366d5b2..0987068 100644 --- a/main/main.c +++ b/main/main.c @@ -38,6 +38,7 @@ #include "wifi_ota.h" #include "esp_vfs.h" +#include "esp_vfs_fat.h" static const char *TAG = "main"; @@ -55,6 +56,7 @@ typedef enum action { ACTION_WIFI_LIST, ACTION_BACK, ACTION_FILE_BROWSER, + ACTION_FILE_BROWSER_INT, ACTION_UNINSTALL } menu_action_t; @@ -151,7 +153,11 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili menu_args_t* file_browser_args = malloc(sizeof(menu_args_t)); file_browser_args->action = ACTION_FILE_BROWSER; - menu_insert_item(menu, "File browser", NULL, file_browser_args, -1); + menu_insert_item(menu, "File browser (sd card)", NULL, file_browser_args, -1); + + menu_args_t* file_browser_int_args = malloc(sizeof(menu_args_t)); + file_browser_int_args->action = ACTION_FILE_BROWSER_INT; + menu_insert_item(menu, "File browser (internal)", NULL, file_browser_int_args, -1); menu_args_t* uninstall_args = malloc(sizeof(menu_args_t)); uninstall_args->action = ACTION_UNINSTALL; @@ -485,8 +491,9 @@ void find_parent_dir(char* path, char* parent) { parent[last_separator] = '\0'; } -void file_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { - char path[512] = "/sd"; +void file_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, const char* initial_path) { + char path[512] = {0}; + strncpy(path, initial_path, sizeof(path)); while (true) { menu_t* menu = menu_alloc(path); DIR* dir = opendir(path); @@ -679,11 +686,33 @@ void app_main(void) { esp_restart(); } - /* Start SD card */ + /* Start internal filesystem */ + const esp_partition_t* fs_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, "locfd"); + + wl_handle_t s_wl_handle = WL_INVALID_HANDLE; + + if (fs_partition != NULL) { + const esp_vfs_fat_mount_config_t mount_config = { + .format_if_mount_failed = true, + .max_files = 5, + .allocation_unit_size = 0, + }; + esp_err_t res = esp_vfs_fat_spiflash_mount("/internal", "locfd", &mount_config, &s_wl_handle); + if (res != ESP_OK) { + ESP_LOGE(TAG, "failed to mount locfd (%d)", res); + } else { + ESP_LOGI(TAG, "Internal filesystem mounted"); + } + } else { + ESP_LOGE(TAG, "locfd partition not found"); + } + + /* Start SD card filesystem */ res = mount_sd(SD_CMD, SD_CLK, SD_D0, SD_PWR, "/sd", false, 5); bool sdcard_ready = (res == ESP_OK); if (sdcard_ready) { - list_files_in_folder("/sd"); + ESP_LOGI(TAG, "SD card filesystem mounted"); + //list_files_in_folder("/sd"); } /* Start LEDs */ @@ -719,7 +748,9 @@ void app_main(void) { graphics_task(pax_buffer, ili9341, NULL, "Firmware update..."); ota_update(); } else if (menu_action == ACTION_FILE_BROWSER) { - file_browser(rp2040->queue, pax_buffer, ili9341); + file_browser(rp2040->queue, pax_buffer, ili9341, "/sd"); + } else if (menu_action == ACTION_FILE_BROWSER_INT) { + file_browser(rp2040->queue, pax_buffer, ili9341, "/internal"); } else if (menu_action == ACTION_UNINSTALL) { uninstall_browser(rp2040->queue, pax_buffer, ili9341); } else if (menu_action == ACTION_SETTINGS) {