diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 260c1aa..f48ff6d 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -19,6 +19,8 @@ idf_component_register( "menus/start.c" "menus/dev.c" "menus/wifi.c" + "uninstall.c" + "file_browser.c" INCLUDE_DIRS "." "include" "menus" diff --git a/main/appfs_wrapper.c b/main/appfs_wrapper.c index 705651a..abcd0d5 100644 --- a/main/appfs_wrapper.c +++ b/main/appfs_wrapper.c @@ -1,8 +1,27 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "appfs.h" +#include "ili9341.h" +#include "pax_gfx.h" +#include "menu.h" +#include "rp2040.h" #include "appfs_wrapper.h" +#include "hardware.h" +#include "system_wrapper.h" +#include "bootscreen.h" #include "esp_sleep.h" #include "soc/rtc.h" #include "soc/rtc_cntl_reg.h" +static const char *TAG = "appfs wrapper"; + esp_err_t appfs_init(void) { return appfsInit(APPFS_PART_TYPE, APPFS_PART_SUBTYPE); } @@ -29,3 +48,47 @@ void appfs_boot_app(int fd) { esp_deep_sleep_start(); } +void appfs_store_app(pax_buf_t* pax_buffer, ILI9341* ili9341, char* path, char* label) { + display_boot_screen(pax_buffer, ili9341, "Installing app..."); + esp_err_t res; + appfs_handle_t handle; + FILE* app_fd = fopen(path, "rb"); + if (app_fd == NULL) { + display_boot_screen(pax_buffer, ili9341, "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) { + display_boot_screen(pax_buffer, ili9341, "Failed to load app to RAM"); + ESP_LOGE(TAG, "Failed to load application into RAM"); + vTaskDelay(100 / portTICK_PERIOD_MS); + return; + } + + ESP_LOGI(TAG, "Application size %d", app_size); + + res = appfsCreateFile(label, app_size, &handle); + if (res != ESP_OK) { + display_boot_screen(pax_buffer, ili9341, "Failed to create on AppFS"); + ESP_LOGE(TAG, "Failed to create file on AppFS (%d)", res); + vTaskDelay(100 / portTICK_PERIOD_MS); + free(app); + return; + } + res = appfsWrite(handle, 0, app, app_size); + if (res != ESP_OK) { + display_boot_screen(pax_buffer, ili9341, "Failed to write to AppFS"); + ESP_LOGE(TAG, "Failed to write to file on AppFS (%d)", res); + vTaskDelay(100 / portTICK_PERIOD_MS); + free(app); + return; + } + free(app); + ESP_LOGI(TAG, "Application is now stored in AppFS"); + display_boot_screen(pax_buffer, ili9341, "App installed!"); + vTaskDelay(100 / portTICK_PERIOD_MS); + return; +} diff --git a/main/file_browser.c b/main/file_browser.c new file mode 100644 index 0000000..719c02b --- /dev/null +++ b/main/file_browser.c @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "esp_vfs.h" +#include "esp_vfs_fat.h" +#include "appfs.h" +#include "ili9341.h" +#include "pax_gfx.h" +#include "menu.h" +#include "rp2040.h" +#include "appfs_wrapper.h" + +static const char *TAG = "file browser"; + +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 _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, 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); + 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; + + pax_background(pax_buffer, 0xFFFFFF); + pax_noclip(pax_buffer); + pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] install [B] back"); + + 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_BACK: + if (value) { + menuArgs = pd_args; + } + case RP2040_INPUT_BUTTON_ACCEPT: + case RP2040_INPUT_JOYSTICK_PRESS: + 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) { + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF72008a); + ili9341_write(ili9341, pax_buffer->buf); + 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); + } +} diff --git a/main/include/appfs_wrapper.h b/main/include/appfs_wrapper.h index 33bc1b8..e9f4c48 100644 --- a/main/include/appfs_wrapper.h +++ b/main/include/appfs_wrapper.h @@ -14,3 +14,4 @@ esp_err_t appfs_init(void); uint8_t* load_file_to_ram(FILE* fd, size_t* fsize); void appfs_boot_app(int fd); +void appfs_store_app(pax_buf_t* pax_buffer, ILI9341* ili9341, char* path, char* label); diff --git a/main/include/file_browser.h b/main/include/file_browser.h new file mode 100644 index 0000000..6afd69e --- /dev/null +++ b/main/include/file_browser.h @@ -0,0 +1,9 @@ +#include +#include +#include +#include +#include "ili9341.h" +#include "pax_gfx.h" + +void list_files_in_folder(const char* path); +void file_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, const char* initial_path); diff --git a/main/include/uninstall.h b/main/include/uninstall.h new file mode 100644 index 0000000..56e4646 --- /dev/null +++ b/main/include/uninstall.h @@ -0,0 +1,8 @@ +#include +#include +#include +#include +#include "pax_gfx.h" +#include "ili9341.h" + +void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); diff --git a/main/main.c b/main/main.c index 02caf18..6bed481 100644 --- a/main/main.c +++ b/main/main.c @@ -57,146 +57,6 @@ extern const uint8_t logo_screen_png_end[] asm("_binary_logo_screen_png_end"); static const char *TAG = "main"; -typedef enum action { - ACTION_NONE, - ACTION_APPFS, - ACTION_INSTALLER, - ACTION_SETTINGS, - ACTION_OTA, - ACTION_FPGA, - ACTION_FPGA_DL, - ACTION_RP2040_BL, - ACTION_WIFI_CONNECT, - ACTION_WIFI_SCAN, - ACTION_WIFI_MANUAL, - ACTION_WIFI_LIST, - ACTION_BACK, - ACTION_FILE_BROWSER, - ACTION_FILE_BROWSER_INT, - ACTION_UNINSTALL -} menu_action_t; - -typedef struct _menu_args { - appfs_handle_t fd; - menu_action_t action; -} menu_args_t; - -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(path, "rb"); - if (app_fd == NULL) { - 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, NULL, "Failed to load app to RAM"); - ESP_LOGE(TAG, "Failed to load application into RAM"); - vTaskDelay(100 / portTICK_PERIOD_MS); - return; - } - - ESP_LOGI(TAG, "Application size %d", app_size); - - res = appfsCreateFile(label, app_size, &handle); - if (res != ESP_OK) { - 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); - return; - } - res = appfsWrite(handle, 0, app, app_size); - if (res != ESP_OK) { - 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); - return; - } - free(app); - ESP_LOGI(TAG, "Application is now stored in AppFS"); - graphics_task(pax_buffer, ili9341, NULL, "App installed!"); - vTaskDelay(100 / portTICK_PERIOD_MS); - return; -} - -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; - - menu_args_t* wifi_scan_args = malloc(sizeof(menu_args_t)); - wifi_scan_args->action = ACTION_WIFI_SCAN; - menu_insert_item(menu, "Add by scan...", NULL, wifi_scan_args, -1); - - menu_args_t* wifi_manual_args = malloc(sizeof(menu_args_t)); - wifi_manual_args->action = ACTION_WIFI_MANUAL; - menu_insert_item(menu, "Add manually...", NULL, wifi_manual_args, -1); - - menu_args_t* wifi_list_args = malloc(sizeof(menu_args_t)); - wifi_list_args->action = ACTION_WIFI_LIST; - menu_insert_item(menu, "List known networks", NULL, wifi_list_args, -1); - - menu_args_t* back_args = malloc(sizeof(menu_args_t)); - back_args->action = ACTION_BACK; - menu_insert_item(menu, "< Back", NULL, back_args, -1); - - bool render = true; - 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: - case RP2040_INPUT_JOYSTICK_PRESS: - if (value) { - menuArgs = menu_get_callback_args(menu, menu_get_position(menu)); - } - break; - default: - break; - } - } - - if (render) { - menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF72008a); - ili9341_write(ili9341, pax_buffer->buf); - render = false; - } - - if (menuArgs != NULL) { - *menu_action = menuArgs->action; - break; - } - } - - for (size_t index = 0; index < menu_get_length(menu); index++) { - free(menu_get_callback_args(menu, index)); - } - - menu_free(menu); -} - void display_fatal_error(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* line0, const char* line1, const char* line2, const char* line3) { pax_noclip(pax_buffer); pax_background(pax_buffer, 0xa85a32); @@ -207,281 +67,6 @@ void display_fatal_error(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* li ili9341_write(ili9341, pax_buffer->buf); } -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: - case RP2040_INPUT_JOYSTICK_PRESS: - 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) { - menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF72008a); - ili9341_write(ili9341, pax_buffer->buf); - 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, 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); - 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: - case RP2040_INPUT_JOYSTICK_PRESS: - 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) { - menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF72008a); - ili9341_write(ili9341, pax_buffer->buf); - 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; @@ -516,7 +101,8 @@ void app_main(void) { ESP_LOGE(TAG, "ili9341 is NULL"); esp_restart(); } - + + audio_init(); display_boot_screen(pax_buffer, ili9341, "Initializing RP2040..."); @@ -633,10 +219,9 @@ void app_main(void) { bool sdcard_ready = (res == ESP_OK); if (sdcard_ready) { ESP_LOGI(TAG, "SD card filesystem mounted"); - //list_files_in_folder("/sd"); } - display_boot_screen(pax_buffer, ili9341, "Initializing LEDs..."); + play_bootsound(); /* Start LEDs */ ws2812_init(GPIO_LED_DATA); @@ -648,89 +233,8 @@ void app_main(void) { /* Launcher menu */ while (true) { - menu_action_t menu_action = ACTION_NONE; - appfs_handle_t appfs_fd = -1; menu_start(rp2040->queue, pax_buffer, ili9341); - if (menu_action == ACTION_FPGA) { - graphics_task(pax_buffer, ili9341, NULL, "Loading..."); - fpga_test(ili9341, ice40, rp2040->queue); - } else if (menu_action == ACTION_FILE_BROWSER) { - 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) { - while (true) { - 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); - char ssid[33]; - char password[33]; - size_t requiredSize; - esp_err_t res = nvs_get_str(handle, "wifi.ssid", NULL, &requiredSize); - if (res != ESP_OK) { - strcpy(ssid, ""); - strcpy(password, ""); - } else if (requiredSize < sizeof(ssid)) { - res = nvs_get_str(handle, "wifi.ssid", ssid, &requiredSize); - if (res != ESP_OK) strcpy(ssid, ""); - res = nvs_get_str(handle, "wifi.password", NULL, &requiredSize); - if (res != ESP_OK) { - strcpy(password, ""); - } else if (requiredSize < sizeof(password)) { - res = nvs_get_str(handle, "wifi.password", password, &requiredSize); - if (res != ESP_OK) strcpy(password, ""); - } - } - 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, 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, NULL, "WiFi settings stored"); - } else { - graphics_task(pax_buffer, ili9341, NULL, "Canceled"); - } - nvs_set_u8(handle, "wifi.use_ent", 0); - nvs_close(handle); - } else if (menu_action == ACTION_WIFI_LIST) { - nvs_handle_t handle; - nvs_open("system", NVS_READWRITE, &handle); - char ssid[33]; - char password[33]; - size_t requiredSize; - esp_err_t res = nvs_get_str(handle, "wifi.ssid", NULL, &requiredSize); - if (res != ESP_OK) { - strcpy(ssid, ""); - } else if (requiredSize < sizeof(ssid)) { - res = nvs_get_str(handle, "wifi.ssid", ssid, &requiredSize); - if (res != ESP_OK) strcpy(ssid, ""); - res = nvs_get_str(handle, "wifi.password", NULL, &requiredSize); - if (res != ESP_OK) { - strcpy(password, ""); - } else if (requiredSize < sizeof(password)) { - res = nvs_get_str(handle, "wifi.password", password, &requiredSize); - if (res != ESP_OK) strcpy(password, ""); - } - } - nvs_close(handle); - char buffer[300]; - snprintf(buffer, sizeof(buffer), "SSID is %s\nPassword is %s", ssid, password); - graphics_task(pax_buffer, ili9341, NULL, buffer); - } else if (menu_action == ACTION_WIFI_SCAN) { - // Scan for WiFi networks. - wifi_scan(NULL); - } else { - break; - } - } - } } - free(framebuffer); } diff --git a/main/menus/dev.c b/main/menus/dev.c index daaa077..2b63cb9 100644 --- a/main/menus/dev.c +++ b/main/menus/dev.c @@ -17,11 +17,14 @@ #include "dev.h" #include "fpga_download.h" #include "hardware.h" +#include "file_browser.h" typedef enum action { ACTION_NONE, ACTION_BACK, - ACTION_FPGA_DL + ACTION_FPGA_DL, + ACTION_FILE_BROWSER, + ACTION_FILE_BROWSER_INT, } menu_dev_action_t; void render_dev_help(pax_buf_t* pax_buffer) { @@ -33,7 +36,8 @@ void render_dev_help(pax_buf_t* pax_buffer) { void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { menu_t* menu = menu_alloc("Development tools"); menu_insert_item(menu, "FPGA download mode", NULL, (void*) ACTION_FPGA_DL, -1); - + menu_insert_item(menu, "File browser (SD card)", NULL, (void*) ACTION_FILE_BROWSER, -1); + menu_insert_item(menu, "File browser (internal)", NULL, (void*) ACTION_FILE_BROWSER_INT, -1); bool render = true; menu_dev_action_t action = ACTION_NONE; @@ -86,6 +90,10 @@ void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) if (action != ACTION_NONE) { if (action == ACTION_FPGA_DL) { fpga_download(buttonQueue, get_ice40(), pax_buffer, ili9341); + } else if (action == ACTION_FILE_BROWSER) { + file_browser(buttonQueue, pax_buffer, ili9341, "/sd"); + } else if (action == ACTION_FILE_BROWSER_INT) { + file_browser(buttonQueue, pax_buffer, ili9341, "/internal"); } else if (action == ACTION_BACK) { break; } diff --git a/main/menus/launcher.c b/main/menus/launcher.c index f2d0936..dbf4902 100644 --- a/main/menus/launcher.c +++ b/main/menus/launcher.c @@ -27,10 +27,6 @@ typedef struct { void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { menu_t* menu = menu_alloc("Apps"); - - menu_launcher_args_t* back_args = malloc(sizeof(menu_launcher_args_t)); - back_args->action = ACTION_BACK; - menu_insert_item(menu, "< Back", NULL, back_args, -1); appfs_handle_t appfs_fd = APPFS_INVALID_FD; while (1) { @@ -51,6 +47,8 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili pax_noclip(pax_buffer); pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] start app [B] back"); + bool quit = false; + while (1) { rp2040_input_message_t buttonMessage = {0}; if (xQueueReceive(buttonQueue, &buttonMessage, 16 / portTICK_PERIOD_MS) == pdTRUE) { @@ -72,7 +70,7 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili case RP2040_INPUT_BUTTON_HOME: case RP2040_INPUT_BUTTON_BACK: if (value) { - menuArgs = back_args; + quit = true; } break; case RP2040_INPUT_BUTTON_ACCEPT: @@ -100,6 +98,10 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili } break; } + + if (quit) { + break; + } } for (size_t index = 0; index < menu_get_length(menu); index++) { diff --git a/main/menus/settings.c b/main/menus/settings.c index 0c83e2b..c840187 100644 --- a/main/menus/settings.c +++ b/main/menus/settings.c @@ -19,6 +19,7 @@ #include "wifi_connect.h" #include "wifi_ota.h" #include "wifi.h" +#include "uninstall.h" typedef enum action { ACTION_NONE, @@ -106,6 +107,8 @@ void menu_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili } } else if (action == ACTION_WIFI) { menu_wifi(buttonQueue, pax_buffer, ili9341); + } else if (action == ACTION_UNINSTALL) { + uninstall_browser(buttonQueue, pax_buffer, ili9341); } else if (action == ACTION_BACK) { break; } diff --git a/main/menus/wifi.c b/main/menus/wifi.c index c0ee3d9..b0774f0 100644 --- a/main/menus/wifi.c +++ b/main/menus/wifi.c @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include "appfs.h" #include "ili9341.h" #include "pax_gfx.h" @@ -18,6 +20,9 @@ #include "bootscreen.h" #include "wifi_connect.h" #include "wifi_ota.h" +#include "graphics_wrapper.h" + +static const char *TAG = "wifi menu"; typedef enum action { ACTION_NONE, @@ -33,6 +38,9 @@ void render_wifi_help(pax_buf_t* pax_buffer) { pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] accept [B] back"); } +void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); +void wifi_setup(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, bool scan); + void menu_wifi(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { menu_t* menu = menu_alloc("WiFi configuration"); menu_insert_item(menu, "Show current settings", NULL, (void*) ACTION_SHOW, -1); @@ -89,7 +97,11 @@ void menu_wifi(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341 if (action != ACTION_NONE) { if (action == ACTION_SHOW) { - + wifi_show(buttonQueue, pax_buffer, ili9341); + } else if (action == ACTION_SCAN) { + wifi_setup(buttonQueue, pax_buffer, ili9341, true); + } else if (action == ACTION_MANUAL) { + wifi_setup(buttonQueue, pax_buffer, ili9341, false); } else if (action == ACTION_BACK) { break; } @@ -101,3 +113,89 @@ void menu_wifi(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341 menu_free(menu); } + +void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { + nvs_handle_t handle; + + nvs_open("system", NVS_READWRITE, &handle); + char ssid[33] = ""; + char password[33] = ""; + size_t requiredSize; + + esp_err_t res = nvs_get_str(handle, "wifi.ssid", NULL, &requiredSize); + if ((res == ESP_OK) && (requiredSize < sizeof(ssid))) { + res = nvs_get_str(handle, "wifi.ssid", ssid, &requiredSize); + } + + res = nvs_get_str(handle, "wifi.password", NULL, &requiredSize); + if ((res == ESP_OK) && (requiredSize < sizeof(password))) { + res = nvs_get_str(handle, "wifi.password", password, &requiredSize); + } + + nvs_close(handle); + + char buffer[300]; + pax_noclip(pax_buffer); + pax_background(pax_buffer, 0xFFFFFF); + snprintf(buffer, sizeof(buffer), "SSID is %s", ssid); + pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 20*0, buffer); + snprintf(buffer, sizeof(buffer), "Password is %s", password); + pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 20*1, buffer); + ili9341_write(ili9341, pax_buffer->buf); + + bool quit = false; + while (!quit) { + 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_BUTTON_HOME: + case RP2040_INPUT_BUTTON_BACK: + case RP2040_INPUT_BUTTON_ACCEPT: + case RP2040_INPUT_JOYSTICK_PRESS: + case RP2040_INPUT_BUTTON_SELECT: + case RP2040_INPUT_BUTTON_START: + if (value) quit = true; + break; + default: + break; + } + } + } +} + +void wifi_setup(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, bool scan) { + nvs_handle_t handle; + nvs_open("system", NVS_READWRITE, &handle); + char ssid[33]; + char password[33]; + size_t requiredSize; + esp_err_t res = nvs_get_str(handle, "wifi.ssid", NULL, &requiredSize); + if (res != ESP_OK) { + strcpy(ssid, ""); + strcpy(password, ""); + } else if (requiredSize < sizeof(ssid)) { + res = nvs_get_str(handle, "wifi.ssid", ssid, &requiredSize); + if (res != ESP_OK) strcpy(ssid, ""); + res = nvs_get_str(handle, "wifi.password", NULL, &requiredSize); + if (res != ESP_OK) { + strcpy(password, ""); + } else if (requiredSize < sizeof(password)) { + res = nvs_get_str(handle, "wifi.password", password, &requiredSize); + if (res != ESP_OK) strcpy(password, ""); + } + } + bool accepted = keyboard(buttonQueue, 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(buttonQueue, 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); + display_boot_screen(pax_buffer, ili9341, "WiFi settings stored"); + } + nvs_set_u8(handle, "wifi.use_ent", 0); + nvs_close(handle); +} + diff --git a/main/uninstall.c b/main/uninstall.c new file mode 100644 index 0000000..08da592 --- /dev/null +++ b/main/uninstall.c @@ -0,0 +1,119 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "appfs.h" +#include "ili9341.h" +#include "pax_gfx.h" +#include "menu.h" +#include "rp2040.h" +#include "appfs_wrapper.h" +#include "hardware.h" +#include "system_wrapper.h" +#include "bootscreen.h" +#include "uninstall.h" + +static const char *TAG = "uninstaller"; + +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) { + menu_t* menu = menu_alloc("Uninstall application"); + + appfs_handle_t appfs_fd = APPFS_INVALID_FD; + 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); + } + + bool render = true; + uninstall_menu_args_t* menuArgs = NULL; + + pax_background(pax_buffer, 0xFFFFFF); + pax_noclip(pax_buffer); + pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] uninstall app [B] back"); + + bool quit = 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_HOME: + case RP2040_INPUT_BUTTON_BACK: + if (value) { + quit = true; + } + break; + case RP2040_INPUT_BUTTON_ACCEPT: + case RP2040_INPUT_JOYSTICK_PRESS: + case RP2040_INPUT_BUTTON_SELECT: + case RP2040_INPUT_BUTTON_START: + if (value) { + menuArgs = menu_get_callback_args(menu, menu_get_position(menu)); + } + break; + default: + break; + } + } + + if (render) { + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF72008a); + ili9341_write(ili9341, pax_buffer->buf); + render = false; + } + + if (menuArgs != NULL) { + char message[1024]; + sprintf(message, "Uninstalling %s...", menuArgs->name); + printf("%s\n", message); + display_boot_screen(pax_buffer, ili9341, message); + appfsDeleteFile(menuArgs->name); + menuArgs = NULL; + break; + } + + if (quit) { + break; + } + } + + for (size_t index = 0; index < menu_get_length(menu); index++) { + free(menu_get_callback_args(menu, index)); + } + + menu_free(menu); +}