diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a4b2cc..a18b31a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,8 @@ cmake_minimum_required(VERSION 3.5) include($ENV{IDF_PATH}/tools/cmake/project.cmake) + +set(PROJECT_NAME "MCH2022 launcher") +set(PROJECT_VER "0.1") + project(main) diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index bbb07a6..02468fc 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -20,6 +20,10 @@ idf_component_register( "menus/wifi.c" "uninstall.c" "file_browser.c" + "test_common.c" + "factory_test.c" + "animation.c" + "button_test.c" INCLUDE_DIRS "." "include" "menus" @@ -30,4 +34,37 @@ idf_component_register( ${project_dir}/resources/boot.snd ${project_dir}/resources/mch2022_logo.png ${project_dir}/resources/logo_screen.png + ${project_dir}/resources/icons/dev.png + ${project_dir}/resources/icons/home.png + ${project_dir}/resources/icons/settings.png + ${project_dir}/resources/icons/apps.png + ${project_dir}/resources/icons/hatchery.png + ${project_dir}/resources/animation/animation_frame_1.png + ${project_dir}/resources/animation/animation_frame_2.png + ${project_dir}/resources/animation/animation_frame_3.png + ${project_dir}/resources/animation/animation_frame_4.png + ${project_dir}/resources/animation/animation_frame_5.png + ${project_dir}/resources/animation/animation_frame_6.png + ${project_dir}/resources/animation/animation_frame_7.png + ${project_dir}/resources/animation/animation_frame_8.png + ${project_dir}/resources/animation/animation_frame_9.png + ${project_dir}/resources/animation/animation_frame_10.png + ${project_dir}/resources/animation/animation_frame_11.png + ${project_dir}/resources/animation/animation_frame_12.png + ${project_dir}/resources/animation/animation_frame_13.png + ${project_dir}/resources/animation/animation_frame_14.png + ${project_dir}/resources/animation/animation_frame_15.png + ${project_dir}/resources/animation/animation_frame_16.png + ${project_dir}/resources/animation/animation_frame_17.png + ${project_dir}/resources/animation/animation_frame_18.png + ${project_dir}/resources/animation/animation_frame_19.png + ${project_dir}/resources/animation/animation_frame_20.png + ${project_dir}/resources/animation/animation_frame_21.png + ${project_dir}/resources/animation/animation_frame_22.png + ${project_dir}/resources/animation/animation_frame_23.png + ${project_dir}/resources/animation/animation_frame_24.png + ${project_dir}/resources/animation/animation_frame_25.png + ${project_dir}/resources/animation/animation_frame_26.png + ${project_dir}/resources/animation/animation_frame_27.png + ${project_dir}/resources/animation/animation_frame_28.png ) diff --git a/main/animation.c b/main/animation.c new file mode 100644 index 0000000..a3589db --- /dev/null +++ b/main/animation.c @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include "pax_gfx.h" +#include "pax_codecs.h" +#include "ili9341.h" +#include "ws2812.h" +#include "hardware.h" + +extern const uint8_t animation_frame_1_start[] asm("_binary_animation_frame_1_png_start"); +extern const uint8_t animation_frame_1_end[] asm("_binary_animation_frame_1_png_end"); +extern const uint8_t animation_frame_2_start[] asm("_binary_animation_frame_2_png_start"); +extern const uint8_t animation_frame_2_end[] asm("_binary_animation_frame_2_png_end"); +extern const uint8_t animation_frame_3_start[] asm("_binary_animation_frame_3_png_start"); +extern const uint8_t animation_frame_3_end[] asm("_binary_animation_frame_3_png_end"); +extern const uint8_t animation_frame_4_start[] asm("_binary_animation_frame_4_png_start"); +extern const uint8_t animation_frame_4_end[] asm("_binary_animation_frame_4_png_end"); +extern const uint8_t animation_frame_5_start[] asm("_binary_animation_frame_5_png_start"); +extern const uint8_t animation_frame_5_end[] asm("_binary_animation_frame_5_png_end"); +extern const uint8_t animation_frame_6_start[] asm("_binary_animation_frame_6_png_start"); +extern const uint8_t animation_frame_6_end[] asm("_binary_animation_frame_6_png_end"); +extern const uint8_t animation_frame_7_start[] asm("_binary_animation_frame_7_png_start"); +extern const uint8_t animation_frame_7_end[] asm("_binary_animation_frame_7_png_end"); +extern const uint8_t animation_frame_8_start[] asm("_binary_animation_frame_8_png_start"); +extern const uint8_t animation_frame_8_end[] asm("_binary_animation_frame_8_png_end"); +extern const uint8_t animation_frame_9_start[] asm("_binary_animation_frame_9_png_start"); +extern const uint8_t animation_frame_9_end[] asm("_binary_animation_frame_9_png_end"); +extern const uint8_t animation_frame_10_start[] asm("_binary_animation_frame_10_png_start"); +extern const uint8_t animation_frame_10_end[] asm("_binary_animation_frame_10_png_end"); +extern const uint8_t animation_frame_11_start[] asm("_binary_animation_frame_11_png_start"); +extern const uint8_t animation_frame_11_end[] asm("_binary_animation_frame_11_png_end"); +extern const uint8_t animation_frame_12_start[] asm("_binary_animation_frame_12_png_start"); +extern const uint8_t animation_frame_12_end[] asm("_binary_animation_frame_12_png_end"); +extern const uint8_t animation_frame_13_start[] asm("_binary_animation_frame_13_png_start"); +extern const uint8_t animation_frame_13_end[] asm("_binary_animation_frame_13_png_end"); +extern const uint8_t animation_frame_14_start[] asm("_binary_animation_frame_14_png_start"); +extern const uint8_t animation_frame_14_end[] asm("_binary_animation_frame_14_png_end"); +extern const uint8_t animation_frame_15_start[] asm("_binary_animation_frame_15_png_start"); +extern const uint8_t animation_frame_15_end[] asm("_binary_animation_frame_15_png_end"); +extern const uint8_t animation_frame_16_start[] asm("_binary_animation_frame_16_png_start"); +extern const uint8_t animation_frame_16_end[] asm("_binary_animation_frame_16_png_end"); +extern const uint8_t animation_frame_17_start[] asm("_binary_animation_frame_17_png_start"); +extern const uint8_t animation_frame_17_end[] asm("_binary_animation_frame_17_png_end"); +extern const uint8_t animation_frame_18_start[] asm("_binary_animation_frame_18_png_start"); +extern const uint8_t animation_frame_18_end[] asm("_binary_animation_frame_18_png_end"); +extern const uint8_t animation_frame_19_start[] asm("_binary_animation_frame_19_png_start"); +extern const uint8_t animation_frame_19_end[] asm("_binary_animation_frame_19_png_end"); +extern const uint8_t animation_frame_20_start[] asm("_binary_animation_frame_20_png_start"); +extern const uint8_t animation_frame_20_end[] asm("_binary_animation_frame_20_png_end"); +extern const uint8_t animation_frame_21_start[] asm("_binary_animation_frame_21_png_start"); +extern const uint8_t animation_frame_21_end[] asm("_binary_animation_frame_21_png_end"); +extern const uint8_t animation_frame_22_start[] asm("_binary_animation_frame_22_png_start"); +extern const uint8_t animation_frame_22_end[] asm("_binary_animation_frame_22_png_end"); +extern const uint8_t animation_frame_23_start[] asm("_binary_animation_frame_23_png_start"); +extern const uint8_t animation_frame_23_end[] asm("_binary_animation_frame_23_png_end"); +extern const uint8_t animation_frame_24_start[] asm("_binary_animation_frame_24_png_start"); +extern const uint8_t animation_frame_24_end[] asm("_binary_animation_frame_24_png_end"); +extern const uint8_t animation_frame_25_start[] asm("_binary_animation_frame_25_png_start"); +extern const uint8_t animation_frame_25_end[] asm("_binary_animation_frame_25_png_end"); +extern const uint8_t animation_frame_26_start[] asm("_binary_animation_frame_26_png_start"); +extern const uint8_t animation_frame_26_end[] asm("_binary_animation_frame_26_png_end"); +extern const uint8_t animation_frame_27_start[] asm("_binary_animation_frame_27_png_start"); +extern const uint8_t animation_frame_27_end[] asm("_binary_animation_frame_27_png_end"); +extern const uint8_t animation_frame_28_start[] asm("_binary_animation_frame_28_png_start"); +extern const uint8_t animation_frame_28_end[] asm("_binary_animation_frame_28_png_end"); + +const uint8_t* animation_frames[] = { + animation_frame_1_start, + animation_frame_2_start, + animation_frame_3_start, + animation_frame_4_start, + animation_frame_5_start, + animation_frame_6_start, + animation_frame_7_start, + animation_frame_8_start, + animation_frame_9_start, + animation_frame_10_start, + animation_frame_11_start, + animation_frame_12_start, + animation_frame_13_start, + animation_frame_14_start, + animation_frame_15_start, + animation_frame_16_start, + animation_frame_17_start, + animation_frame_18_start, + animation_frame_19_start, + animation_frame_20_start, + animation_frame_21_start, + animation_frame_22_start, + animation_frame_23_start, + animation_frame_24_start, + animation_frame_25_start, + animation_frame_26_start, + animation_frame_27_start, + animation_frame_28_start +}; + +const uint8_t* animation_frames_end[] = { + animation_frame_1_end, + animation_frame_2_end, + animation_frame_3_end, + animation_frame_4_end, + animation_frame_5_end, + animation_frame_6_end, + animation_frame_7_end, + animation_frame_8_end, + animation_frame_9_end, + animation_frame_10_end, + animation_frame_11_end, + animation_frame_12_end, + animation_frame_13_end, + animation_frame_14_end, + animation_frame_15_end, + animation_frame_16_end, + animation_frame_17_end, + animation_frame_18_end, + animation_frame_19_end, + animation_frame_20_end, + animation_frame_21_end, + animation_frame_22_end, + animation_frame_23_end, + animation_frame_24_end, + animation_frame_25_end, + animation_frame_26_end, + animation_frame_27_end, + animation_frame_28_end +}; + +void display_animation(pax_buf_t* pax_buffer, ILI9341* ili9341) { + + gpio_set_direction(GPIO_SD_PWR, GPIO_MODE_OUTPUT); + gpio_set_level(GPIO_SD_PWR, 1); + ws2812_init(GPIO_LED_DATA); + uint8_t led_data[15] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + ws2812_send_data(led_data, sizeof(led_data)); + + pax_noclip(pax_buffer); + pax_background(pax_buffer, 0xFFFFFF); + + for (uint8_t frame = 0; frame < 28; frame++) { + pax_buf_t image; + pax_decode_png_buf(&image, (void*) animation_frames[frame], animation_frames_end[frame] - animation_frames[frame], PAX_BUF_16_565RGB, 0); + pax_draw_image(pax_buffer, &image, 0, 0); + pax_buf_destroy(&image); + ili9341_write(ili9341, pax_buffer->buf); + uint8_t brightness = (frame > 14) ? (frame - 14) : (0); + led_data[1] = brightness; + led_data[3] = brightness; + led_data[8] = brightness; + led_data[9] = brightness / 2; + led_data[10] = brightness / 2; + led_data[14] = brightness; + ws2812_send_data(led_data, sizeof(led_data)); + } + + for (uint8_t brightness = 14; brightness < 50; brightness++) { + led_data[1] = brightness; + led_data[3] = brightness; + led_data[8] = brightness; + led_data[9] = brightness / 2; + led_data[10] = brightness / 2; + led_data[14] = brightness; + ws2812_send_data(led_data, sizeof(led_data)); + vTaskDelay(50 / portTICK_PERIOD_MS); + } +} diff --git a/main/appfs_wrapper.c b/main/appfs_wrapper.c index abcd0d5..c4c022d 100644 --- a/main/appfs_wrapper.c +++ b/main/appfs_wrapper.c @@ -72,15 +72,24 @@ void appfs_store_app(pax_buf_t* pax_buffer, ILI9341* ili9341, char* path, char* res = appfsCreateFile(label, app_size, &handle); if (res != ESP_OK) { - display_boot_screen(pax_buffer, ili9341, "Failed to create on AppFS"); + display_boot_screen(pax_buffer, ili9341, "Failed to create file"); ESP_LOGE(TAG, "Failed to create file on AppFS (%d)", res); vTaskDelay(100 / portTICK_PERIOD_MS); free(app); return; } + int roundedSize=(app_size+(SPI_FLASH_MMU_PAGE_SIZE-1))&(~(SPI_FLASH_MMU_PAGE_SIZE-1)); + res = appfsErase(handle, 0, roundedSize); + if (res != ESP_OK) { + display_boot_screen(pax_buffer, ili9341, "Failed to erase file"); + ESP_LOGE(TAG, "Failed to erase 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"); + display_boot_screen(pax_buffer, ili9341, "Failed to write file"); ESP_LOGE(TAG, "Failed to write to file on AppFS (%d)", res); vTaskDelay(100 / portTICK_PERIOD_MS); free(app); diff --git a/main/button_test.c b/main/button_test.c new file mode 100644 index 0000000..3f67524 --- /dev/null +++ b/main/button_test.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include "ili9341.h" +#include "pax_gfx.h" +#include "rp2040.h" + +void test_buttons(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { + bool render = true; + bool quit = false; + + bool btn_joy_down = false; + bool btn_joy_up = false; + bool btn_joy_left = false; + bool btn_joy_right = false; + bool btn_joy_press = false; + bool btn_home = false; + bool btn_menu = false; + bool btn_select = false; + bool btn_start = false; + bool btn_accept = false; + bool btn_back = 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; + render = true; + switch(pin) { + case RP2040_INPUT_JOYSTICK_DOWN: + btn_joy_down = value; + break; + case RP2040_INPUT_JOYSTICK_UP: + btn_joy_up = value; + break; + case RP2040_INPUT_JOYSTICK_LEFT: + btn_joy_left = value; + break; + case RP2040_INPUT_JOYSTICK_RIGHT: + btn_joy_right = value; + break; + case RP2040_INPUT_JOYSTICK_PRESS: + btn_joy_press = value; + break; + case RP2040_INPUT_BUTTON_HOME: + btn_home = value; + break; + case RP2040_INPUT_BUTTON_MENU: + btn_menu = value; + break; + case RP2040_INPUT_BUTTON_SELECT: + btn_select = value; + break; + case RP2040_INPUT_BUTTON_START: + btn_start = value; + break; + case RP2040_INPUT_BUTTON_ACCEPT: + btn_accept = value; + break; + case RP2040_INPUT_BUTTON_BACK: + btn_back = value; + default: + break; + } + } + + if (render) { + pax_noclip(pax_buffer); + pax_background(pax_buffer, 0x325aa8); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "Press HOME + START to exit"); + char buffer[64]; + snprintf(buffer, sizeof(buffer), "JOY DOWN %s", btn_joy_down ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, buffer); + snprintf(buffer, sizeof(buffer), "JOY UP %s", btn_joy_up ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*2, buffer); + snprintf(buffer, sizeof(buffer), "JOY LEFT %s", btn_joy_left ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*3, buffer); + snprintf(buffer, sizeof(buffer), "JOY RIGHT %s", btn_joy_right ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*4, buffer); + snprintf(buffer, sizeof(buffer), "JOY PRESS %s", btn_joy_press ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*5, buffer); + snprintf(buffer, sizeof(buffer), "BTN HOME %s", btn_home ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*6, buffer); + snprintf(buffer, sizeof(buffer), "BTN MENU %s", btn_menu ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*7, buffer); + snprintf(buffer, sizeof(buffer), "BTN SELECT %s", btn_select ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*8, buffer); + snprintf(buffer, sizeof(buffer), "BTN START %s", btn_start ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*9, buffer); + snprintf(buffer, sizeof(buffer), "BTN A %s", btn_accept ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*10, buffer); + snprintf(buffer, sizeof(buffer), "BTN B %s", btn_back ? "PRESSED" : "released"); + pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*11, buffer); + ili9341_write(ili9341, pax_buffer->buf); + render = false; + } + + if (btn_home && btn_start) { + quit = true; + } + } +} + diff --git a/main/factory_test.c b/main/factory_test.c new file mode 100644 index 0000000..ad286be --- /dev/null +++ b/main/factory_test.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include +#include +#include +#include "hardware.h" +#include "ili9341.h" +#include "ice40.h" +#include "rp2040.h" +#include "fpga_test.h" +#include "pax_gfx.h" +#include "test_common.h" +#include "settings.h" +#include "ws2812.h" +#include "audio.h" + +static const char *TAG = "factory"; + +/* Test routines */ + +bool test_rp2040_init(uint32_t* rc) { + esp_err_t res = bsp_rp2040_init(); + *rc = (uint32_t) res; + return (res == ESP_OK); +} + +bool test_ice40_init(uint32_t* rc) { + esp_err_t res = bsp_ice40_init(); + *rc = (uint32_t) res; + return (res == ESP_OK); +} + +bool test_bno055_init(uint32_t* rc) { + esp_err_t res = bsp_bno055_init(); + *rc = (uint32_t) res; + return (res == ESP_OK); +} + +bool test_bme680_init(uint32_t* rc) { + esp_err_t res = bsp_bme680_init(); + *rc = (uint32_t) res; + return (res == ESP_OK); +} + +bool test_stuck_buttons(uint32_t* rc) { + RP2040* rp2040 = get_rp2040(); + uint16_t state; + esp_err_t res = rp2040_read_buttons(rp2040, &state); + if (res != ESP_OK) { + *rc = 0xFFFFFFFF; + return false; + } + + state &= ~(1 << RP2040_INPUT_FPGA_CDONE); // Ignore FPGA CDONE + + *rc = state; + + return (state == 0x0000); +} + +bool test_sd_power(uint32_t* rc) { + *rc = 0x00000000; + // Init all GPIO pins for SD card and LED + if (gpio_reset_pin(GPIO_SD_PWR) != ESP_OK) return false; + if (gpio_set_direction(GPIO_SD_PWR, GPIO_MODE_INPUT) != ESP_OK) return false; + if (gpio_reset_pin(GPIO_SD_CMD) != ESP_OK) return false; + if (gpio_set_direction(GPIO_SD_CMD, GPIO_MODE_INPUT) != ESP_OK) return false; + if (gpio_reset_pin(GPIO_SD_CLK) != ESP_OK) return false; + if (gpio_set_direction(GPIO_SD_CLK, GPIO_MODE_INPUT) != ESP_OK) return false; + if (gpio_reset_pin(GPIO_SD_D0) != ESP_OK) return false; + if (gpio_set_direction(GPIO_SD_D0, GPIO_MODE_INPUT) != ESP_OK) return false; + if (gpio_reset_pin(GPIO_LED_DATA) != ESP_OK) return false; + if (gpio_set_direction(GPIO_LED_DATA, GPIO_MODE_INPUT) != ESP_OK) return false; + + if (gpio_get_level(GPIO_SD_PWR)) {*rc = 0x01; return false;} // Check that power enable is pulled low + + if (gpio_set_direction(GPIO_SD_PWR, GPIO_MODE_OUTPUT) != ESP_OK) return false; + if (gpio_set_level(GPIO_SD_PWR, 1) != ESP_OK) return false; + + vTaskDelay(10 / portTICK_PERIOD_MS); + + // SD pins should be pulled high + if (!gpio_get_level(GPIO_SD_CMD)) {*rc = 0x02; return false;} + if (!gpio_get_level(GPIO_SD_CLK)) {*rc = 0x04; return false;} + if (!gpio_get_level(GPIO_SD_D0)) {*rc = 0x08; return false;} + + return true; +} + +bool run_basic_tests(pax_buf_t* pax_buffer, ILI9341* ili9341) { + const pax_font_t *font; + int line = 0; + bool ok = true; + + /* Screen init */ + font = pax_get_font("sky mono"); + + pax_noclip(pax_buffer); + pax_background(pax_buffer, 0x8060f0); + ili9341_write(ili9341, pax_buffer->buf); + + /* Run mandatory tests */ + RUN_TEST_MANDATORY("RP2040", test_rp2040_init); + RUN_TEST_MANDATORY("ICE40", test_ice40_init); + RUN_TEST_MANDATORY("BNO055", test_bno055_init); + RUN_TEST_MANDATORY("BME680", test_bme680_init); + RUN_TEST_MANDATORY("STUCK BUTTONS", test_stuck_buttons); + RUN_TEST_MANDATORY("SD/LED POWER", test_sd_power); + + +error: + /* Fail result on screen */ + if (!ok) pax_draw_text(pax_buffer, 0xffff0000, font, 36, 0, 20*line, "FAIL"); + ili9341_write(ili9341, pax_buffer->buf); + return ok; +} + +const uint8_t led_green[15] = {50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0}; +const uint8_t led_red[15] = {0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0}; +const uint8_t led_blue[15] = {0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50}; + +void factory_test(pax_buf_t* pax_buffer, ILI9341* ili9341) { + uint8_t factory_test_done = nvs_get_u8_default("system", "factory_test", 0); + if (!factory_test_done) { + bool result; + + ESP_LOGI(TAG, "Factory test start"); + + result = run_basic_tests(pax_buffer, ili9341); + + gpio_set_direction(GPIO_SD_PWR, GPIO_MODE_OUTPUT); + gpio_set_level(GPIO_SD_PWR, 1); + ws2812_init(GPIO_LED_DATA); + if (result) { + ws2812_send_data(led_blue, sizeof(led_blue)); + } else { + ws2812_send_data(led_red, sizeof(led_red)); + } + + if (!result) goto test_end; + + RP2040* rp2040 = get_rp2040(); + + result = run_fpga_tests(rp2040->queue, pax_buffer, ili9341); + if (!result) { + ws2812_send_data(led_red, sizeof(led_red)); + goto test_end; + } + + ws2812_send_data(led_green, sizeof(led_green)); + + // Wait for the operator to unplug the badge + test_end: + + if (result) { + esp_err_t res = nvs_set_u8_fixed("system", "factory_test", 1); + if (res != ESP_OK) { + ESP_LOGE(TAG, "Failed to store test result %d\n", res); + result = false; + ws2812_send_data(led_red, sizeof(led_red)); + pax_noclip(pax_buffer); + pax_background(pax_buffer, 0xa85a32); + ili9341_write(ili9341, pax_buffer->buf); + } + } + + while (true) { + if (result) play_bootsound(); + vTaskDelay(3000 / portTICK_PERIOD_MS); + } + } +} diff --git a/main/file_browser.c b/main/file_browser.c index 0a5cf91..5adf658 100644 --- a/main/file_browser.c +++ b/main/file_browser.c @@ -15,6 +15,7 @@ #include "menu.h" #include "rp2040.h" #include "appfs_wrapper.h" +#include "bootscreen.h" static const char *TAG = "file browser"; @@ -104,20 +105,24 @@ void find_parent_dir(char* path, char* parent) { } void file_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, const char* initial_path) { + display_boot_screen(pax_buffer, ili9341, "Please wait..."); char path[512] = {0}; strncpy(path, initial_path, sizeof(path)); while (true) { - menu_t* menu = menu_alloc(path); + menu_t* menu = menu_alloc(path, 20, 18); DIR* dir = opendir(path); if (dir == NULL) { - ESP_LOGE(TAG, "Failed to open directory %s", path); + if (path[0] != 0) { + ESP_LOGE(TAG, "Failed to open directory %s", path); + display_boot_screen(pax_buffer, ili9341, "Failed to open directory"); + vTaskDelay(200 / portTICK_PERIOD_MS); + } 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) { @@ -134,8 +139,6 @@ void file_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9 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); } @@ -186,7 +189,8 @@ void file_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9 if (renderbg) { pax_background(pax_buffer, 0xFFFFFF); pax_noclip(pax_buffer); - pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 5, 240 - 19, "[A] install [B] back"); + const pax_font_t *font = pax_get_font("saira regular"); + pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] install [B] back"); renderbg = false; } diff --git a/main/fpga_test.c b/main/fpga_test.c index a621c76..8808cc3 100644 --- a/main/fpga_test.c +++ b/main/fpga_test.c @@ -11,6 +11,7 @@ #include "rp2040.h" #include "fpga_test.h" #include "pax_gfx.h" +#include "test_common.h" extern const uint8_t fpga_selftest_bin_start[] asm("_binary_fpga_selftest_bin_start"); extern const uint8_t fpga_selftest_bin_end[] asm("_binary_fpga_selftest_bin_end"); @@ -114,7 +115,8 @@ static bool soc_message(ICE40* ice40, uint8_t cmd, uint32_t param, uint32_t *res /* Test routines */ -static bool test_bitstream_load(ICE40* ice40, uint32_t *rc) { +static bool test_bitstream_load(uint32_t *rc) { + ICE40* ice40 = get_ice40(); esp_err_t res; res = ice40_load_bitstream(ice40, fpga_selftest_bin_start, fpga_selftest_bin_end - fpga_selftest_bin_start); @@ -127,7 +129,7 @@ static bool test_bitstream_load(ICE40* ice40, uint32_t *rc) { return true; } -static bool test_spi_loopback_one(ICE40* ice40) { +static bool _test_spi_loopback_one(ICE40* ice40) { esp_err_t res; uint8_t data_tx[257]; uint8_t data_rx[258]; @@ -219,12 +221,14 @@ static bool test_spi_loopback_one(ICE40* ice40) { return true; } -static bool test_spi_loopback(ICE40* ice40, uint32_t *rc) { +static bool test_spi_loopback(uint32_t *rc) { int i; + + ICE40* ice40 = get_ice40(); /* Run test 256 times */ for (i=0; i<256; i++) { - if (!test_spi_loopback_one(ice40)) + if (!_test_spi_loopback_one(ice40)) break; } @@ -239,7 +243,9 @@ static bool test_spi_loopback(ICE40* ice40, uint32_t *rc) { return true; } -static bool test_soc_loopback(ICE40 *ice40, uint32_t *rc) { +static bool test_soc_loopback(uint32_t *rc) { + ICE40* ice40 = get_ice40(); + /* Execute command */ if (!soc_message(ice40, SOC_CMD_PING, SOC_CMD_PING_PARAM, rc, 0)) { *rc = -1; @@ -255,7 +261,9 @@ static bool test_soc_loopback(ICE40 *ice40, uint32_t *rc) { return true; } -static bool test_uart_loopback(ICE40* ice40, uint32_t *rc) { +static bool test_uart_loopback(uint32_t *rc) { + ICE40* ice40 = get_ice40(); + /* Enable loopback mode of RP2040 */ rp2040_set_fpga_loopback(get_rp2040(), true, true); vTaskDelay(pdMS_TO_TICKS(10)); @@ -273,7 +281,9 @@ static bool test_uart_loopback(ICE40* ice40, uint32_t *rc) { return *rc == SOC_RESP_OK; } -static bool test_psram(ICE40* ice40, uint32_t *rc) { +static bool test_psram(uint32_t *rc) { + ICE40* ice40 = get_ice40(); + /* Execute command */ if (!soc_message(ice40, SOC_CMD_PSRAM_TEST, 0, rc, pdMS_TO_TICKS(1000))) { *rc = -1; @@ -284,7 +294,9 @@ static bool test_psram(ICE40* ice40, uint32_t *rc) { return *rc == SOC_RESP_OK; } -static bool test_irq_n(ICE40* ice40, uint32_t *rc) { +static bool test_irq_n(uint32_t *rc) { + ICE40* ice40 = get_ice40(); + esp_err_t res; /* Set pin as input */ @@ -327,7 +339,8 @@ static bool test_irq_n(ICE40* ice40, uint32_t *rc) { return true; } -static bool test_lcd_mode(ICE40* ice40, uint32_t *rc) { +static bool test_lcd_mode(uint32_t *rc) { + ICE40* ice40 = get_ice40(); esp_err_t res; bool ok; @@ -371,7 +384,8 @@ static bool test_lcd_mode(ICE40* ice40, uint32_t *rc) { return ok; } -static bool test_pmod_open(ICE40* ice40, uint32_t *rc) { +static bool test_pmod_open(uint32_t *rc) { + ICE40* ice40 = get_ice40(); /* Execute command */ if (!soc_message(ice40, SOC_CMD_PMOD_OPEN_TEST, 0, rc, 0)) { *rc = -1; @@ -382,7 +396,9 @@ static bool test_pmod_open(ICE40* ice40, uint32_t *rc) { return *rc == SOC_RESP_OK; } -static bool test_pmod_plug(ICE40* ice40, uint32_t *rc) { +static bool test_pmod_plug(uint32_t *rc) { + ICE40* ice40 = get_ice40(); + /* Execute command */ if (!soc_message(ice40, SOC_CMD_PMOD_PLUG_TEST, 0, rc, 0)) { *rc = -1; @@ -393,7 +409,9 @@ static bool test_pmod_plug(ICE40* ice40, uint32_t *rc) { return *rc == SOC_RESP_OK; } -static bool test_lcd_init(ICE40* ice40, uint32_t *rc) { +static bool test_lcd_init(uint32_t *rc) { + ICE40* ice40 = get_ice40(); + /* Execute command */ if (!soc_message(ice40, SOC_CMD_LCD_INIT_TEST, 0, rc, 0)) { *rc = -1; @@ -404,83 +422,8 @@ static bool test_lcd_init(ICE40* ice40, uint32_t *rc) { return *rc == SOC_RESP_OK; } - -typedef bool (*test_fn)(ICE40 *ice40, uint32_t *rc); - - -static bool wait_button(xQueueHandle buttonQueue) { - rp2040_input_message_t buttonMessage = {0}; - - while (1) { - if (xQueueReceive(buttonQueue, &buttonMessage, 0) == pdTRUE) { - if (buttonMessage.state) { - switch(buttonMessage.input) { - case RP2040_INPUT_BUTTON_HOME: - case RP2040_INPUT_BUTTON_MENU: - case RP2040_INPUT_BUTTON_BACK: - return false; - case RP2040_INPUT_BUTTON_ACCEPT: - return true; - default: - break; - } - } - } else { - vTaskDelay(pdMS_TO_TICKS(10)); - } - } -} - -static bool run_test(ICE40* ice40, pax_buf_t* pax_buffer, const pax_font_t *font, ILI9341* ili9341, int line, - const char *test_name, test_fn fn) { - bool rv; - uint32_t rc; - - /* Test name */ - pax_draw_text(pax_buffer, 0xffffffff, font, 18, 0, 20*line, test_name); - if (ili9341) - ili9341_write(ili9341, pax_buffer->buf); - - /* Run the test */ - rv = fn(ice40, &rc); - - /* Display result */ - if (!rv) { - /* Error */ - char buf[10]; - snprintf(buf, sizeof(buf), "%08x", rc); - pax_draw_text(pax_buffer, 0xffff0000, font, 18, 200, 20*line, buf); - } else { - /* OK ! */ - pax_draw_text(pax_buffer, 0xff00ff00, font, 18, 200, 20*line, " OK"); - } - - if (ili9341) - ili9341_write(ili9341, pax_buffer->buf); - - /* Pass through the 'OK' status */ - return rv; -} - -#define RUN_TEST(name, fn) do {\ - ok &= run_test(ice40, pax_buffer, font, ili9341, line++, name, fn); \ -} while (0) - -#define RUN_TEST_MANDATORY(name, fn) do {\ - if (!run_test(ice40, pax_buffer, font, ili9341, line++, name, fn)) { \ - pax_draw_text(pax_buffer, 0xffff0000, font, 18, 0, 20*line, "Aborted"); \ - ili9341_write(ili9341, pax_buffer->buf); \ - ok = false; \ - goto error; \ - } \ -} while (0) - -#define RUN_TEST_BLIND(name, fn) do {\ - ok &= run_test(ice40, pax_buffer, font, NULL, line++, name, fn); \ -} while (0) - - -bool run_fpga_tests(xQueueHandle buttonQueue, ICE40* ice40, pax_buf_t* pax_buffer, ILI9341* ili9341) { +bool run_fpga_tests(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { + ICE40* ice40 = get_ice40(); const pax_font_t *font; int line = 0; bool ok = true; @@ -534,9 +477,7 @@ bool run_fpga_tests(xQueueHandle buttonQueue, ICE40* ice40, pax_buf_t* pax_buffe soc_message(ice40, SOC_CMD_LCD_RGB_CYCLE_SET, 1, NULL, 0); /* Wait for button */ - if (!wait_button(buttonQueue)) { - ok = false; - } + RUN_TEST("LCD control", test_wait_for_response); /* Stop LCD / RGB cycling */ soc_message(ice40, SOC_CMD_LCD_RGB_CYCLE_SET, 0, NULL, 0); @@ -550,9 +491,9 @@ error: /* Pass / Fail result on screen */ if (ok) - pax_draw_text(pax_buffer, 0xff00ff00, font, 36, 0, 20*line, "FPGA PASS"); + pax_draw_text(pax_buffer, 0xff00ff00, font, 36, 0, 20*line, "PASS"); else - pax_draw_text(pax_buffer, 0xffff0000, font, 36, 0, 20*line, "FPGA FAIL"); + pax_draw_text(pax_buffer, 0xffff0000, font, 36, 0, 20*line, "FAIL"); ili9341_write(ili9341, pax_buffer->buf); @@ -562,7 +503,7 @@ error: return ok; } -void fpga_test(xQueueHandle buttonQueue, ICE40* ice40, pax_buf_t* pax_buffer, ILI9341* ili9341) { - run_fpga_tests(buttonQueue, ice40, pax_buffer, ili9341); - wait_button(buttonQueue); +void fpga_test(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { + run_fpga_tests(buttonQueue, pax_buffer, ili9341); + test_wait_for_response(NULL); } diff --git a/main/include/animation.h b/main/include/animation.h new file mode 100644 index 0000000..2f9bc39 --- /dev/null +++ b/main/include/animation.h @@ -0,0 +1,4 @@ +#include "pax_gfx.h" +#include "ili9341.h" + +void display_animation(pax_buf_t* pax_buffer, ILI9341* ili9341); diff --git a/main/include/button_test.h b/main/include/button_test.h new file mode 100644 index 0000000..6b16506 --- /dev/null +++ b/main/include/button_test.h @@ -0,0 +1,9 @@ +#include +#include +#include +#include +#include +#include "ili9341.h" +#include "pax_gfx.h" + +void test_buttons(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); diff --git a/main/include/factory_test.h b/main/include/factory_test.h new file mode 100644 index 0000000..5a33254 --- /dev/null +++ b/main/include/factory_test.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include +#include +#include +#include "ili9341.h" +#include "pax_gfx.h" + +void factory_test(pax_buf_t* pax_buffer, ILI9341* ili9341); diff --git a/main/include/fpga_test.h b/main/include/fpga_test.h index 62f9e15..d49c36e 100644 --- a/main/include/fpga_test.h +++ b/main/include/fpga_test.h @@ -10,4 +10,5 @@ #include "ice40.h" #include "pax_gfx.h" -void fpga_test(xQueueHandle buttonQueue, ICE40* ice40, pax_buf_t* pax_buffer, ILI9341* ili9341); +void fpga_test(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); +bool run_fpga_tests(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); diff --git a/main/include/menu.h b/main/include/menu.h index 4a57294..887bffd 100644 --- a/main/include/menu.h +++ b/main/include/menu.h @@ -16,6 +16,8 @@ typedef struct _menu_item { char* label; menu_callback_t callback; void* callbackArgs; + + pax_buf_t* icon; // Linked list struct _menu_item* previousItem; @@ -27,11 +29,27 @@ typedef struct menu { menu_item_t* firstItem; size_t length; size_t position; + float entry_height; + float text_height; + pax_buf_t* icon; + + pax_col_t fgColor; + pax_col_t bgColor; + pax_col_t selectedItemColor; + pax_col_t bgTextColor; + pax_col_t borderColor; + pax_col_t titleColor; + pax_col_t titleBgColor; + pax_col_t scrollbarBgColor; + pax_col_t scrollbarFgColor; + } menu_t; -menu_t* menu_alloc(const char* aTitle); +menu_t* menu_alloc(const char* aTitle, float arg_entry_height, float arg_text_height); void menu_free(menu_t* aMenu); +void menu_set_icon(menu_t* aMenu, pax_buf_t* icon); bool menu_insert_item(menu_t* aMenu, const char* aLabel, menu_callback_t aCallback, void* aCallbackArgs, size_t aPosition); +bool menu_insert_item_icon(menu_t* aMenu, const char* aLabel, menu_callback_t aCallback, void* aCallbackArgs, size_t aPosition, pax_buf_t* icon); bool menu_remove_item(menu_t* aMenu, size_t aPosition); bool menu_navigate_to(menu_t* aMenu, size_t aPosition); void menu_navigate_previous(menu_t* aMenu); diff --git a/main/include/settings.h b/main/include/settings.h index f032a23..7581831 100644 --- a/main/include/settings.h +++ b/main/include/settings.h @@ -6,3 +6,6 @@ #include "ice40.h" esp_err_t nvs_init(); +esp_err_t nvs_get_str_fixed(const char* nvs_namespace, const char* key, char* target, size_t target_size, size_t* size); +uint8_t nvs_get_u8_default(const char* nvs_namespace, const char* key, uint8_t default_value); +esp_err_t nvs_set_u8_fixed(const char* nvs_namespace, const char* key, uint8_t value); diff --git a/main/include/test_common.h b/main/include/test_common.h new file mode 100644 index 0000000..a679df6 --- /dev/null +++ b/main/include/test_common.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include "ili9341.h" +#include "pax_gfx.h" + +typedef bool (*test_fn)(uint32_t *rc); + +bool test_wait_for_response(uint32_t *rc); +bool run_test(pax_buf_t* pax_buffer, const pax_font_t *font, ILI9341* ili9341, int line, const char *test_name, test_fn fn); + +#define RUN_TEST(name, fn) do {\ + ok &= run_test(pax_buffer, font, ili9341, line++, name, fn); \ +} while (0) + +#define RUN_TEST_MANDATORY(name, fn) do {\ + if (!run_test(pax_buffer, font, ili9341, line++, name, fn)) { \ + pax_draw_text(pax_buffer, 0xffff0000, font, 18, 0, 20*line, "Aborted"); \ + ili9341_write(ili9341, pax_buffer->buf); \ + ok = false; \ + goto error; \ + } \ +} while (0) + +#define RUN_TEST_BLIND(name, fn) do {\ + ok &= run_test(pax_buffer, font, NULL, line++, name, fn); \ +} while (0) diff --git a/main/main.c b/main/main.c index 1b5f8a3..3c01c49 100644 --- a/main/main.c +++ b/main/main.c @@ -15,7 +15,7 @@ #include "pax_gfx.h" #include "sdcard.h" #include "appfs.h" - +#include "esp_ota_ops.h" #include "rp2040.h" #include "rp2040bl.h" @@ -48,6 +48,8 @@ #include "menus/start.h" +#include "factory_test.h" + extern const uint8_t wallpaper_png_start[] asm("_binary_wallpaper_png_start"); extern const uint8_t wallpaper_png_end[] asm("_binary_wallpaper_png_end"); @@ -69,6 +71,10 @@ void display_fatal_error(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* li void app_main(void) { esp_err_t res; + + const esp_app_desc_t *app_description = esp_ota_get_app_description(); + ESP_LOGI(TAG, "App version: %s", app_description->version); + //ESP_LOGI(TAG, "Project name: %s", app_description->project_name); /* Initialize memory */ uint8_t* framebuffer = heap_caps_malloc(ILI9341_BUFFER_SIZE, MALLOC_CAP_8BIT); @@ -102,10 +108,18 @@ void app_main(void) { esp_restart(); } - display_boot_screen(pax_buffer, ili9341, "Starting..."); + /* Start NVS */ + res = nvs_init(); + if (res != ESP_OK) { + ESP_LOGE(TAG, "NVS init failed: %d", res); + display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "NVS failed to initialize", "Flash may be corrupted", NULL); + esp_restart(); + } audio_init(); + display_boot_screen(pax_buffer, ili9341, "Starting..."); + if (bsp_rp2040_init() != ESP_OK) { ESP_LOGE(TAG, "Failed to initialize the RP2040 co-processor"); display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "RP2040 co-processor error", NULL, NULL); @@ -119,6 +133,8 @@ void app_main(void) { } rp2040_updater(rp2040, pax_buffer, ili9341); // Handle RP2040 firmware update & bootloader mode + + factory_test(pax_buffer, ili9341); /*uint8_t rp2040_uid[8]; if (rp2040_get_uid(rp2040, rp2040_uid) != ESP_OK) { @@ -178,16 +194,6 @@ void app_main(void) { display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "AppFS failed to initialize", "Flash may be corrupted", NULL); esp_restart(); } - - //display_boot_screen(pax_buffer, ili9341, "Initializing NVS..."); - - /* Start NVS */ - res = nvs_init(); - if (res != ESP_OK) { - ESP_LOGE(TAG, "NVS init failed: %d", res); - display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "NVS failed to initialize", "Flash may be corrupted", NULL); - esp_restart(); - } //display_boot_screen(pax_buffer, ili9341, "Initializing filesystem..."); @@ -217,12 +223,14 @@ void app_main(void) { bool sdcard_ready = (res == ESP_OK); if (sdcard_ready) { ESP_LOGI(TAG, "SD card filesystem mounted"); - } - /* Start LEDs */ - ws2812_init(GPIO_LED_DATA); - uint8_t ledBuffer[15] = {50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0}; - ws2812_send_data(ledBuffer, sizeof(ledBuffer)); + /* LED power is on: start LED driver and turn LEDs off */ + ws2812_init(GPIO_LED_DATA); + const uint8_t led_off[15] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + ws2812_send_data(led_off, sizeof(led_off)); + } else { + gpio_set_level(GPIO_SD_PWR, 0); // Disable power to LEDs and SD card + } /* Start WiFi */ wifi_init(); @@ -232,7 +240,7 @@ void app_main(void) { /* Launcher menu */ while (true) { - menu_start(rp2040->queue, pax_buffer, ili9341); + menu_start(rp2040->queue, pax_buffer, ili9341, app_description->version); } free(framebuffer); diff --git a/main/menu.c b/main/menu.c index c6a57a3..2deba87 100644 --- a/main/menu.c +++ b/main/menu.c @@ -1,9 +1,10 @@ #include #include #include "pax_gfx.h" +#include "pax_codecs.h" #include "menu.h" -menu_t* menu_alloc(const char* aTitle) { +menu_t* menu_alloc(const char* aTitle, float arg_entry_height, float arg_text_height) { if (aTitle == NULL) return NULL; menu_t* menu = malloc(sizeof(menu_t)); if (menu == NULL) return NULL; @@ -17,6 +18,20 @@ menu_t* menu_alloc(const char* aTitle) { menu->firstItem = NULL; menu->length = 0; menu->position = 0; + menu->entry_height = (arg_entry_height > 0) ? arg_entry_height : 20; + menu->text_height = (arg_text_height > 0) ? arg_text_height : (arg_entry_height - 2); + menu->icon = NULL; + + menu->fgColor = 0xFF000000; + menu->bgColor = 0xFFFFFFFF; + menu->bgTextColor = 0xFFFFFFFF; + menu->selectedItemColor = 0xFF000000; + menu->borderColor = 0x88000000; + menu->titleColor = 0xFFFFFFFF; + menu->titleBgColor = 0xFF000000; + menu->scrollbarBgColor = 0xFFCCCCCC; + menu->scrollbarFgColor = 0xFF555555; + return menu; } @@ -37,6 +52,10 @@ void menu_free(menu_t* aMenu) { free(aMenu); } +void menu_set_icon(menu_t* aMenu, pax_buf_t* icon) { + aMenu->icon = icon; +} + menu_item_t* _menu_find_item(menu_t* aMenu, size_t aPosition) { menu_item_t* currentItem = aMenu->firstItem; if (currentItem == NULL) return NULL; @@ -66,11 +85,12 @@ bool menu_insert_item(menu_t* aMenu, const char* aLabel, menu_callback_t aCallba newItem->label = malloc(labelSize); if (newItem->label == NULL) { free(newItem); - return NULL; + return false; } memcpy(newItem->label, aLabel, labelSize); newItem->callback = aCallback; newItem->callbackArgs = aCallbackArgs; + newItem->icon = NULL; if (aMenu->firstItem == NULL) { newItem->nextItem = NULL; newItem->previousItem = NULL; @@ -91,6 +111,21 @@ bool menu_insert_item(menu_t* aMenu, const char* aLabel, menu_callback_t aCallba return true; } +bool menu_insert_item_icon(menu_t* aMenu, const char* aLabel, menu_callback_t aCallback, void* aCallbackArgs, size_t aPosition, pax_buf_t* icon) { + if (!menu_insert_item(aMenu, aLabel, aCallback, aCallbackArgs, aPosition)) { + return false; + } + menu_item_t* item; + if (aPosition >= aMenu->length - 1) { + item = _menu_find_last_item(aMenu); + } else { + item = _menu_find_item(aMenu, aPosition); + } + + item->icon = icon; + return true; +} + bool menu_remove_item(menu_t* aMenu, size_t aPosition) { if (aMenu == NULL) return false; // Can't delete an item from a menu that doesn't exist if (aMenu->length <= aPosition) return false; // Can't delete an item that doesn't exist @@ -175,17 +210,11 @@ void menu_debug(menu_t* aMenu) { } void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, float aWidth, float aHeight, pax_col_t aColor) { - pax_col_t fgColor = aColor; - pax_col_t bgColor = 0xFFFFFFFF; - pax_col_t bgTextColor = 0xFFFFFFFF; - pax_col_t borderColor = 0x88000000; - pax_col_t titleColor = 0xFFFFFFFF; - pax_col_t titleBgColor = aColor; - pax_col_t scrollbarBgColor = 0xFFCCCCCC; - pax_col_t scrollbarFgColor = 0xFF555555; const pax_font_t *font = pax_get_font("saira regular"); - float entry_height = 18 + 2; + float entry_height = aMenu->entry_height;//18 + 2; + float text_height = aMenu->text_height; + float text_offset = ((entry_height - text_height) / 2) + 1; size_t maxItems = aHeight / entry_height; float posY = aPosY; @@ -193,12 +222,20 @@ void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, fl pax_noclip(aBuffer); if (maxItems > 1) { + float offsetX = 0; + if (aMenu->icon != NULL) { + offsetX = aMenu->icon->width; + } + maxItems--; - pax_simple_rect(aBuffer, titleBgColor, aPosX, posY, aWidth, entry_height); - pax_simple_line(aBuffer, titleColor, aPosX + 1, aPosY + entry_height, aPosX + aWidth - 2, aPosY + entry_height - 1); - pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 2, entry_height - 2); - pax_draw_text(aBuffer, titleColor, font, entry_height - 2, aPosX + 1, posY + 1, aMenu->title); + pax_simple_rect(aBuffer, aMenu->titleBgColor, aPosX, posY, aWidth, entry_height); + //pax_simple_line(aBuffer, aMenu->titleColor, aPosX + 1, aPosY + entry_height, aPosX + aWidth - 2, aPosY + entry_height - 1); + pax_clip(aBuffer, aPosX + 1, posY + text_offset, aWidth - 2, text_height); + pax_draw_text(aBuffer, aMenu->titleColor, font, text_height, aPosX + offsetX + 1, posY + text_offset, aMenu->title); pax_noclip(aBuffer); + if (aMenu->icon != NULL) { + pax_draw_image(aBuffer, aMenu->icon, aPosX, posY); + } posY += entry_height; } @@ -207,8 +244,8 @@ void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, fl itemOffset = aMenu->position - maxItems + 1; } - pax_outline_rect(aBuffer, borderColor, aPosX, aPosY, aWidth, aHeight); - pax_simple_rect(aBuffer, bgColor, aPosX, posY, aWidth, aHeight - posY + aPosY); + pax_outline_rect(aBuffer, aMenu->borderColor, aPosX, aPosY, aWidth, aHeight); + pax_simple_rect(aBuffer, aMenu->bgColor, aPosX, posY, aWidth, aHeight - posY + aPosY); for (size_t index = itemOffset; (index < itemOffset + maxItems) && (index < aMenu->length); index++) { menu_item_t* item = _menu_find_item(aMenu, index); @@ -216,18 +253,28 @@ void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, fl printf("Render error: item is NULL at %u\n", index); break; } + + float iconWidth = 0; + if (item->icon != NULL) { + iconWidth = item->icon->width + 1; + } if (index == aMenu->position) { - pax_simple_rect(aBuffer, fgColor, aPosX + 1, posY, aWidth - 2, entry_height); - pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 4, entry_height - 2); - pax_draw_text(aBuffer, bgTextColor, font, entry_height - 2, aPosX + 1, posY + 1, item->label); + pax_simple_rect(aBuffer, aMenu->selectedItemColor, aPosX + 1, posY, aWidth - 2, entry_height); + pax_clip(aBuffer, aPosX + 1, posY + text_offset, aWidth - 4, text_height); + pax_draw_text(aBuffer, aMenu->bgTextColor, font, text_height, aPosX + iconWidth + 1, posY + text_offset, item->label); pax_noclip(aBuffer); } else { - pax_simple_rect(aBuffer, bgColor, aPosX + 1, posY, aWidth - 2, entry_height); - pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 4, entry_height - 2); - pax_draw_text(aBuffer, fgColor, font, entry_height - 2, aPosX + 1, posY + 1, item->label); + pax_simple_rect(aBuffer, aMenu->bgColor, aPosX + 1, posY, aWidth - 2, entry_height); + pax_clip(aBuffer, aPosX + 1, posY + text_offset, aWidth - 4, text_height); + pax_draw_text(aBuffer, aMenu->fgColor, font, text_height, aPosX + iconWidth + 1, posY + text_offset, item->label); pax_noclip(aBuffer); } + + if (item->icon != NULL) { + pax_draw_image(aBuffer, item->icon, aPosX + 1, posY); + } + posY += entry_height; } @@ -242,8 +289,8 @@ void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, fl float scrollbarStart = scrollbarHeight * fractionStart; float scrollbarEnd = scrollbarHeight * fractionEnd; - pax_simple_rect(aBuffer, scrollbarBgColor, aPosX + aWidth - 5, aPosY + entry_height - 1, 4, scrollbarHeight); - pax_simple_rect(aBuffer, scrollbarFgColor, aPosX + aWidth - 5, aPosY + entry_height - 1 + scrollbarStart, 4, scrollbarEnd - scrollbarStart); + pax_simple_rect(aBuffer, aMenu->scrollbarBgColor, aPosX + aWidth - 5, aPosY + entry_height - 1, 4, scrollbarHeight); + pax_simple_rect(aBuffer, aMenu->scrollbarFgColor, aPosX + aWidth - 5, aPosY + entry_height - 1 + scrollbarStart, 4, scrollbarEnd - scrollbarStart); pax_noclip(aBuffer); } diff --git a/main/menus/dev.c b/main/menus/dev.c index c654d27..2db34b2 100644 --- a/main/menus/dev.c +++ b/main/menus/dev.c @@ -10,6 +10,7 @@ #include "appfs.h" #include "ili9341.h" #include "pax_gfx.h" +#include "pax_codecs.h" #include "menu.h" #include "rp2040.h" #include "launcher.h" @@ -19,6 +20,11 @@ #include "hardware.h" #include "file_browser.h" #include "fpga_test.h" +#include "animation.h" +#include "button_test.h" + +extern const uint8_t dev_png_start[] asm("_binary_dev_png_start"); +extern const uint8_t dev_png_end[] asm("_binary_dev_png_end"); typedef enum action { ACTION_NONE, @@ -27,21 +33,41 @@ typedef enum action { ACTION_FPGA_TEST, ACTION_FILE_BROWSER, ACTION_FILE_BROWSER_INT, + ACTION_ANIMATION, + ACTION_BUTTON_TEST } menu_dev_action_t; void render_dev_help(pax_buf_t* pax_buffer) { const pax_font_t *font = pax_get_font("saira regular"); pax_background(pax_buffer, 0xFFFFFF); pax_noclip(pax_buffer); - pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] accept [B] back"); + pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 18, "[A] accept [B] back"); } void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { - menu_t* menu = menu_alloc("Development tools"); + menu_t* menu = menu_alloc("Development tools", 34, 18); + + menu->fgColor = 0xFF000000; + menu->bgColor = 0xFFFFFFFF; + menu->bgTextColor = 0xFF000000; + menu->selectedItemColor = 0xFFfec859; + menu->borderColor = 0xFFfa448c; + menu->titleColor = 0xFFfec859; + menu->titleBgColor = 0xFFfa448c; + menu->scrollbarBgColor = 0xFFCCCCCC; + menu->scrollbarFgColor = 0xFF555555; + + pax_buf_t icon_dev; + pax_decode_png_buf(&icon_dev, (void*) dev_png_start, dev_png_end - dev_png_start, PAX_BUF_32_8888ARGB, 0); + + menu_set_icon(menu, &icon_dev); + menu_insert_item(menu, "FPGA download mode", NULL, (void*) ACTION_FPGA_DL, -1); menu_insert_item(menu, "FPGA selftest", NULL, (void*) ACTION_FPGA_TEST, -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); + menu_insert_item(menu, "Animation", NULL, (void*) ACTION_ANIMATION, -1); + menu_insert_item(menu, "Button test", NULL, (void*) ACTION_BUTTON_TEST, -1); bool render = true; menu_dev_action_t action = ACTION_NONE; @@ -86,7 +112,7 @@ void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) } if (render) { - menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF000000); + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88); ili9341_write(ili9341, pax_buffer->buf); render = false; } @@ -95,11 +121,15 @@ void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) if (action == ACTION_FPGA_DL) { fpga_download(buttonQueue, get_ice40(), pax_buffer, ili9341); } else if (action == ACTION_FPGA_TEST) { - fpga_test(buttonQueue, get_ice40(), pax_buffer, ili9341); + fpga_test(buttonQueue, 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_ANIMATION) { + display_animation(pax_buffer, ili9341); + } else if (action == ACTION_BUTTON_TEST) { + test_buttons(buttonQueue, pax_buffer, ili9341); } else if (action == ACTION_BACK) { break; } @@ -110,4 +140,6 @@ void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) } menu_free(menu); + + pax_buf_destroy(&icon_dev); } diff --git a/main/menus/launcher.c b/main/menus/launcher.c index 86d073a..b9f204e 100644 --- a/main/menus/launcher.c +++ b/main/menus/launcher.c @@ -10,10 +10,14 @@ #include "appfs.h" #include "ili9341.h" #include "pax_gfx.h" +#include "pax_codecs.h" #include "menu.h" #include "rp2040.h" #include "appfs_wrapper.h" +extern const uint8_t apps_png_start[] asm("_binary_apps_png_start"); +extern const uint8_t apps_png_end[] asm("_binary_apps_png_end"); + typedef enum { ACTION_NONE, ACTION_APPFS, @@ -26,7 +30,23 @@ typedef struct { } menu_launcher_args_t; void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { - menu_t* menu = menu_alloc("Apps"); + menu_t* menu = menu_alloc("Apps", 34, 18); + + menu->fgColor = 0xFF000000; + menu->bgColor = 0xFFFFFFFF; + menu->bgTextColor = 0xFFFFFFFF; + menu->selectedItemColor = 0xFFfa448c; + menu->borderColor = 0xFF491d88; + menu->titleColor = 0xFFfa448c; + menu->titleBgColor = 0xFF491d88; + menu->scrollbarBgColor = 0xFFCCCCCC; + menu->scrollbarFgColor = 0xFF555555; + + pax_buf_t icon_apps; + pax_decode_png_buf(&icon_apps, (void*) apps_png_start, apps_png_end - apps_png_start, PAX_BUF_32_8888ARGB, 0); + + menu_set_icon(menu, &icon_apps); + const pax_font_t *font = pax_get_font("saira regular"); appfs_handle_t appfs_fd = APPFS_INVALID_FD; @@ -46,7 +66,7 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili pax_background(pax_buffer, 0xFFFFFF); pax_noclip(pax_buffer); - pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] start app [B] back"); + pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 18, "[A] start app [B] back"); bool quit = false; @@ -88,7 +108,7 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili } if (render) { - menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF000000); + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88); ili9341_write(ili9341, pax_buffer->buf); render = false; } @@ -110,4 +130,5 @@ void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili } menu_free(menu); + pax_buf_destroy(&icon_apps); } diff --git a/main/menus/settings.c b/main/menus/settings.c index 71b142f..2057e65 100644 --- a/main/menus/settings.c +++ b/main/menus/settings.c @@ -10,6 +10,7 @@ #include "appfs.h" #include "ili9341.h" #include "pax_gfx.h" +#include "pax_codecs.h" #include "menu.h" #include "rp2040.h" #include "appfs_wrapper.h" @@ -21,6 +22,9 @@ #include "wifi.h" #include "uninstall.h" +extern const uint8_t settings_png_start[] asm("_binary_settings_png_start"); +extern const uint8_t settings_png_end[] asm("_binary_settings_png_end"); + typedef enum action { ACTION_NONE, ACTION_BACK, @@ -34,11 +38,27 @@ void render_settings_help(pax_buf_t* pax_buffer) { const pax_font_t *font = pax_get_font("saira regular"); pax_background(pax_buffer, 0xFFFFFF); pax_noclip(pax_buffer); - pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] accept [B] back"); + pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 18, "[A] accept [B] back"); } void menu_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { - menu_t* menu = menu_alloc("Settings"); + menu_t* menu = menu_alloc("Settings", 34, 18); + + menu->fgColor = 0xFF000000; + menu->bgColor = 0xFFFFFFFF; + menu->bgTextColor = 0xFFFFFFFF; + menu->selectedItemColor = 0xFF491d88; + menu->borderColor = 0xFF43b5a0; + menu->titleColor = 0xFF491d88; + menu->titleBgColor = 0xFF43b5a0; + menu->scrollbarBgColor = 0xFFCCCCCC; + menu->scrollbarFgColor = 0xFF555555; + + pax_buf_t icon_settings; + pax_decode_png_buf(&icon_settings, (void*) settings_png_start, settings_png_end - settings_png_start, PAX_BUF_32_8888ARGB, 0); + + menu_set_icon(menu, &icon_settings); + menu_insert_item(menu, "WiFi configuration", NULL, (void*) ACTION_WIFI, -1); menu_insert_item(menu, "Firmware update", NULL, (void*) ACTION_OTA, -1); menu_insert_item(menu, "Flash RP2040 firmware", NULL, (void*) ACTION_RP2040_BL, -1); @@ -87,7 +107,7 @@ void menu_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili } if (render) { - menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF000000); + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88); ili9341_write(ili9341, pax_buffer->buf); render = false; } @@ -120,4 +140,5 @@ void menu_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili } menu_free(menu); + pax_buf_destroy(&icon_settings); } diff --git a/main/menus/start.c b/main/menus/start.c index 7dba283..4f1854b 100644 --- a/main/menus/start.c +++ b/main/menus/start.c @@ -10,37 +10,86 @@ #include "appfs.h" #include "ili9341.h" #include "pax_gfx.h" +#include "pax_codecs.h" #include "menu.h" #include "rp2040.h" #include "launcher.h" #include "settings.h" #include "dev.h" +#include "bootscreen.h" + +extern const uint8_t home_png_start[] asm("_binary_home_png_start"); +extern const uint8_t home_png_end[] asm("_binary_home_png_end"); + +extern const uint8_t apps_png_start[] asm("_binary_apps_png_start"); +extern const uint8_t apps_png_end[] asm("_binary_apps_png_end"); + +extern const uint8_t hatchery_png_start[] asm("_binary_hatchery_png_start"); +extern const uint8_t hatchery_png_end[] asm("_binary_hatchery_png_end"); + +extern const uint8_t dev_png_start[] asm("_binary_dev_png_start"); +extern const uint8_t dev_png_end[] asm("_binary_dev_png_end"); + +extern const uint8_t settings_png_start[] asm("_binary_settings_png_start"); +extern const uint8_t settings_png_end[] asm("_binary_settings_png_end"); typedef enum action { ACTION_NONE, ACTION_APPS, + ACTION_HATCHERY, ACTION_DEV, ACTION_SETTINGS } menu_start_action_t; -void render_start_help(pax_buf_t* pax_buffer) { +void render_start_help(pax_buf_t* pax_buffer, const char* version) { const pax_font_t *font = pax_get_font("saira regular"); pax_background(pax_buffer, 0xFFFFFF); pax_noclip(pax_buffer); - pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] accept"); + pax_draw_text(pax_buffer, 0xFF491d88, font, 18, 5, 240 - 18, "[A] accept"); + + char version_text[64]; + snprintf(version_text, sizeof(version_text), "v%s", version); + + pax_vec1_t version_size = pax_text_size(font, 18, version_text); + pax_draw_text(pax_buffer, 0xFF491d88, font, 18, 320 - 5 - version_size.x, 240 - 18, version_text); } -void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { - menu_t* menu = menu_alloc("Main menu"); - menu_insert_item(menu, "Apps", NULL, (void*) ACTION_APPS, -1); - menu_insert_item(menu, "Development tools", NULL, (void*) ACTION_DEV, -1); - menu_insert_item(menu, "Settings", NULL, (void*) ACTION_SETTINGS, -1); +void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, const char* version) { + menu_t* menu = menu_alloc("Main menu", 34, 18); + + menu->fgColor = 0xFF000000; + menu->bgColor = 0xFFFFFFFF; + menu->bgTextColor = 0xFF000000; + menu->selectedItemColor = 0xFFfec859; + menu->borderColor = 0xFF491d88; + menu->titleColor = 0xFFfec859; + menu->titleBgColor = 0xFF491d88; + menu->scrollbarBgColor = 0xFFCCCCCC; + menu->scrollbarFgColor = 0xFF555555; + + pax_buf_t icon_home; + pax_decode_png_buf(&icon_home, (void*) home_png_start, home_png_end - home_png_start, PAX_BUF_32_8888ARGB, 0); + pax_buf_t icon_apps; + pax_decode_png_buf(&icon_apps, (void*) apps_png_start, apps_png_end - apps_png_start, PAX_BUF_32_8888ARGB, 0); + pax_buf_t icon_hatchery; + pax_decode_png_buf(&icon_hatchery, (void*) hatchery_png_start, hatchery_png_end - hatchery_png_start, PAX_BUF_32_8888ARGB, 0); + pax_buf_t icon_dev; + pax_decode_png_buf(&icon_dev, (void*) dev_png_start, dev_png_end - dev_png_start, PAX_BUF_32_8888ARGB, 0); + pax_buf_t icon_settings; + pax_decode_png_buf(&icon_settings, (void*) settings_png_start, settings_png_end - settings_png_start, PAX_BUF_32_8888ARGB, 0); + + menu_set_icon(menu, &icon_home); + + menu_insert_item_icon(menu, "Apps", NULL, (void*) ACTION_APPS, -1, &icon_apps); + menu_insert_item_icon(menu, "Hatchery", NULL, (void*) ACTION_HATCHERY, -1, &icon_hatchery); + menu_insert_item_icon(menu, "Development tools", NULL, (void*) ACTION_DEV, -1, &icon_dev); + menu_insert_item_icon(menu, "Settings", NULL, (void*) ACTION_SETTINGS, -1, &icon_settings); bool render = true; menu_start_action_t action = ACTION_NONE; - render_start_help(pax_buffer); + render_start_help(pax_buffer, version); while (1) { rp2040_input_message_t buttonMessage = {0}; @@ -74,7 +123,7 @@ void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili934 } if (render) { - menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF000000); + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88); ili9341_write(ili9341, pax_buffer->buf); render = false; } @@ -82,6 +131,9 @@ void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili934 if (action != ACTION_NONE) { if (action == ACTION_APPS) { menu_launcher(buttonQueue, pax_buffer, ili9341); + } else if (action == ACTION_HATCHERY) { + // Not implemented + display_boot_screen(pax_buffer, ili9341, "Not implemented"); } else if (action == ACTION_SETTINGS) { menu_settings(buttonQueue, pax_buffer, ili9341); } else if (action == ACTION_DEV) { @@ -89,9 +141,14 @@ void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili934 } action = ACTION_NONE; render = true; - render_start_help(pax_buffer); + render_start_help(pax_buffer, version); } } menu_free(menu); + pax_buf_destroy(&icon_home); + pax_buf_destroy(&icon_apps); + pax_buf_destroy(&icon_hatchery); + pax_buf_destroy(&icon_dev); + pax_buf_destroy(&icon_settings); } diff --git a/main/menus/start.h b/main/menus/start.h index f3de243..88c8ab7 100644 --- a/main/menus/start.h +++ b/main/menus/start.h @@ -5,4 +5,4 @@ #include "pax_gfx.h" #include "ili9341.h" -void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); +void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, const char* version); diff --git a/main/menus/wifi.c b/main/menus/wifi.c index 7a1bfc3..d612074 100644 --- a/main/menus/wifi.c +++ b/main/menus/wifi.c @@ -63,7 +63,7 @@ void render_wifi_help(pax_buf_t* pax_buffer) { const pax_font_t *font = pax_get_font("saira regular"); pax_background(pax_buffer, 0xFFFFFF); pax_noclip(pax_buffer); - pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] accept [B] back"); + pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 18, "[A] accept [B] back"); } void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341); @@ -73,7 +73,7 @@ int wifi_auth_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili int wifi_phase2_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, esp_eap_ttls_phase2_types default_mode); void menu_wifi(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { - menu_t* menu = menu_alloc("WiFi configuration"); + menu_t* menu = menu_alloc("WiFi configuration", 34, 18); menu_insert_item(menu, "Show current settings", NULL, (void*) ACTION_SHOW, -1); menu_insert_item(menu, "Scan for networks", NULL, (void*) ACTION_SCAN, -1); menu_insert_item(menu, "Configure manually", NULL, (void*) ACTION_MANUAL, -1); @@ -121,7 +121,7 @@ void menu_wifi(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341 } if (render) { - menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF2f55a8); + menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88); ili9341_write(ili9341, pax_buffer->buf); render = false; } @@ -195,7 +195,7 @@ void wifi_show(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341 } wifi_ap_record_t *wifi_scan_results(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, size_t num_aps, wifi_ap_record_t *aps) { - menu_t *menu = menu_alloc("Select network"); + menu_t *menu = menu_alloc("Select network", 20, 18); wifi_ap_record_t *picked = NULL; render_wifi_help(pax_buffer); @@ -269,7 +269,7 @@ wifi_ap_record_t *wifi_scan_results(xQueueHandle buttonQueue, pax_buf_t* pax_buf } int wifi_auth_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, wifi_auth_mode_t default_mode) { - menu_t* menu = menu_alloc("Authentication mode"); + menu_t* menu = menu_alloc("Authentication mode", 20, 18); menu_insert_item(menu, "Insecure", NULL, (void*) ACTION_AUTH_OPEN, -1); menu_insert_item(menu, "WEP", NULL, (void*) ACTION_AUTH_WEP, -1); menu_insert_item(menu, "WPA PSK", NULL, (void*) ACTION_AUTH_WPA_PSK, -1); @@ -347,7 +347,7 @@ int wifi_auth_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili } int wifi_phase2_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, esp_eap_ttls_phase2_types default_mode) { - menu_t* menu = menu_alloc("Phase 2 authentication mode"); + menu_t* menu = menu_alloc("Phase 2 authentication mode", 20, 18); menu_insert_item(menu, "ESP", NULL, (void*) ACTION_PHASE2_EAP, -1); menu_insert_item(menu, "MSCHAPv2", NULL, (void*) ACTION_PHASE2_MSCHAPV2, -1); menu_insert_item(menu, "MSCHAP", NULL, (void*) ACTION_PHASE2_MSCHAP, -1); diff --git a/main/settings.c b/main/settings.c index 9af730f..5d2eff1 100644 --- a/main/settings.c +++ b/main/settings.c @@ -23,3 +23,62 @@ esp_err_t nvs_init() { } return ESP_OK; } + +esp_err_t nvs_get_str_fixed(const char* nvs_namespace, const char* key, char* target, size_t target_size, size_t* size) { + nvs_handle_t handle; + esp_err_t res; + + res = nvs_open(nvs_namespace, NVS_READWRITE, &handle); + if (res != ESP_OK) return res; + + size_t required_size; + res = nvs_get_str(handle, key, NULL, &required_size); + if (res != ESP_OK) { + nvs_close(handle); + return res; + } + + if (required_size > target_size) { + nvs_close(handle); + return ESP_FAIL; + } + + res = nvs_get_str(handle, key, target, &required_size); + + if (size != NULL) *size = required_size; + + nvs_close(handle); + + return res; +} + +uint8_t nvs_get_u8_default(const char* nvs_namespace, const char* key, uint8_t default_value) { + nvs_handle_t handle; + esp_err_t res; + + res = nvs_open(nvs_namespace, NVS_READWRITE, &handle); + if (res != ESP_OK) return default_value; + + uint8_t target; + res = nvs_get_u8(handle, key, &target); + if (res != ESP_OK) { + nvs_close(handle); + return default_value; + } + + nvs_close(handle); + return target; +} + +esp_err_t nvs_set_u8_fixed(const char* nvs_namespace, const char* key, uint8_t value) { + nvs_handle_t handle; + esp_err_t res; + + res = nvs_open(nvs_namespace, NVS_READWRITE, &handle); + if (res != ESP_OK) return res; + + res = nvs_set_u8(handle, key, value); + nvs_close(handle); + + return res; +} diff --git a/main/test_common.c b/main/test_common.c new file mode 100644 index 0000000..c074816 --- /dev/null +++ b/main/test_common.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include +#include +#include +#include "hardware.h" +#include "ili9341.h" +#include "ice40.h" +#include "rp2040.h" +#include "pax_gfx.h" + +typedef bool (*test_fn)(uint32_t *rc); + +bool test_wait_for_response(uint32_t *rc) { + RP2040* rp2040 = get_rp2040(); + rp2040_input_message_t button_message = {0}; + if (rc != NULL) *rc = 0; + while (1) { + if (xQueueReceive(rp2040->queue, &button_message, portMAX_DELAY) == pdTRUE) { + if (button_message.state) { + switch(button_message.input) { + case RP2040_INPUT_BUTTON_HOME: + case RP2040_INPUT_BUTTON_MENU: + case RP2040_INPUT_BUTTON_BACK: + return false; + case RP2040_INPUT_BUTTON_ACCEPT: + if (rc != NULL) *rc = 1; + return true; + default: + break; + } + } + } + } +} + +bool run_test(pax_buf_t* pax_buffer, const pax_font_t *font, ILI9341* ili9341, int line, const char *test_name, test_fn fn) { + bool test_result; + uint32_t rc; + + /* Test name */ + pax_draw_text(pax_buffer, 0xffffffff, font, 18, 0, 20*line, test_name); + if (ili9341) ili9341_write(ili9341, pax_buffer->buf); + + /* Run the test */ + test_result = fn(&rc); + + /* Display result */ + if (!test_result) { + /* Error */ + char buf[10]; + snprintf(buf, sizeof(buf), "%08x", rc); + pax_draw_text(pax_buffer, 0xffff0000, font, 18, 200, 20*line, buf); + } else { + /* OK ! */ + pax_draw_text(pax_buffer, 0xff00ff00, font, 18, 200, 20*line, " OK"); + } + + if (ili9341) ili9341_write(ili9341, pax_buffer->buf); + + /* Pass through the 'OK' status */ + return test_result; +} diff --git a/main/uninstall.c b/main/uninstall.c index 11c0e43..b678f0a 100644 --- a/main/uninstall.c +++ b/main/uninstall.c @@ -26,7 +26,7 @@ typedef struct _uninstall_menu_args { } uninstall_menu_args_t; void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) { - menu_t* menu = menu_alloc("Uninstall application"); + menu_t* menu = menu_alloc("Uninstall application", 20, 18); const pax_font_t *font = pax_get_font("saira regular"); appfs_handle_t appfs_fd = APPFS_INVALID_FD; @@ -50,7 +50,7 @@ void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* pax_background(pax_buffer, 0xFFFFFF); pax_noclip(pax_buffer); - pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 19, "[A] uninstall app [B] back"); + pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 18, "[A] uninstall app [B] back"); bool quit = false; diff --git a/resources/animation/animation_frame_1.png b/resources/animation/animation_frame_1.png new file mode 100644 index 0000000..d55e776 Binary files /dev/null and b/resources/animation/animation_frame_1.png differ diff --git a/resources/animation/animation_frame_10.png b/resources/animation/animation_frame_10.png new file mode 100644 index 0000000..abe0588 Binary files /dev/null and b/resources/animation/animation_frame_10.png differ diff --git a/resources/animation/animation_frame_11.png b/resources/animation/animation_frame_11.png new file mode 100644 index 0000000..4e53573 Binary files /dev/null and b/resources/animation/animation_frame_11.png differ diff --git a/resources/animation/animation_frame_12.png b/resources/animation/animation_frame_12.png new file mode 100644 index 0000000..5b9b57d Binary files /dev/null and b/resources/animation/animation_frame_12.png differ diff --git a/resources/animation/animation_frame_13.png b/resources/animation/animation_frame_13.png new file mode 100644 index 0000000..17b6ec4 Binary files /dev/null and b/resources/animation/animation_frame_13.png differ diff --git a/resources/animation/animation_frame_14.png b/resources/animation/animation_frame_14.png new file mode 100644 index 0000000..6b72f3f Binary files /dev/null and b/resources/animation/animation_frame_14.png differ diff --git a/resources/animation/animation_frame_15.png b/resources/animation/animation_frame_15.png new file mode 100644 index 0000000..5a6d463 Binary files /dev/null and b/resources/animation/animation_frame_15.png differ diff --git a/resources/animation/animation_frame_16.png b/resources/animation/animation_frame_16.png new file mode 100644 index 0000000..41d3952 Binary files /dev/null and b/resources/animation/animation_frame_16.png differ diff --git a/resources/animation/animation_frame_17.png b/resources/animation/animation_frame_17.png new file mode 100644 index 0000000..47f6323 Binary files /dev/null and b/resources/animation/animation_frame_17.png differ diff --git a/resources/animation/animation_frame_18.png b/resources/animation/animation_frame_18.png new file mode 100644 index 0000000..5db8ed8 Binary files /dev/null and b/resources/animation/animation_frame_18.png differ diff --git a/resources/animation/animation_frame_19.png b/resources/animation/animation_frame_19.png new file mode 100644 index 0000000..3bd9465 Binary files /dev/null and b/resources/animation/animation_frame_19.png differ diff --git a/resources/animation/animation_frame_2.png b/resources/animation/animation_frame_2.png new file mode 100644 index 0000000..ab8f15f Binary files /dev/null and b/resources/animation/animation_frame_2.png differ diff --git a/resources/animation/animation_frame_20.png b/resources/animation/animation_frame_20.png new file mode 100644 index 0000000..64facb9 Binary files /dev/null and b/resources/animation/animation_frame_20.png differ diff --git a/resources/animation/animation_frame_21.png b/resources/animation/animation_frame_21.png new file mode 100644 index 0000000..81a5937 Binary files /dev/null and b/resources/animation/animation_frame_21.png differ diff --git a/resources/animation/animation_frame_22.png b/resources/animation/animation_frame_22.png new file mode 100644 index 0000000..59cfd17 Binary files /dev/null and b/resources/animation/animation_frame_22.png differ diff --git a/resources/animation/animation_frame_23.png b/resources/animation/animation_frame_23.png new file mode 100644 index 0000000..9d25bf6 Binary files /dev/null and b/resources/animation/animation_frame_23.png differ diff --git a/resources/animation/animation_frame_24.png b/resources/animation/animation_frame_24.png new file mode 100644 index 0000000..47cecee Binary files /dev/null and b/resources/animation/animation_frame_24.png differ diff --git a/resources/animation/animation_frame_25.png b/resources/animation/animation_frame_25.png new file mode 100644 index 0000000..494a3cb Binary files /dev/null and b/resources/animation/animation_frame_25.png differ diff --git a/resources/animation/animation_frame_26.png b/resources/animation/animation_frame_26.png new file mode 100644 index 0000000..16d73fe Binary files /dev/null and b/resources/animation/animation_frame_26.png differ diff --git a/resources/animation/animation_frame_27.png b/resources/animation/animation_frame_27.png new file mode 100644 index 0000000..4ba0b0f Binary files /dev/null and b/resources/animation/animation_frame_27.png differ diff --git a/resources/animation/animation_frame_28.png b/resources/animation/animation_frame_28.png new file mode 100644 index 0000000..e132200 Binary files /dev/null and b/resources/animation/animation_frame_28.png differ diff --git a/resources/animation/animation_frame_3.png b/resources/animation/animation_frame_3.png new file mode 100644 index 0000000..d55e776 Binary files /dev/null and b/resources/animation/animation_frame_3.png differ diff --git a/resources/animation/animation_frame_4.png b/resources/animation/animation_frame_4.png new file mode 100644 index 0000000..ab8f15f Binary files /dev/null and b/resources/animation/animation_frame_4.png differ diff --git a/resources/animation/animation_frame_5.png b/resources/animation/animation_frame_5.png new file mode 100644 index 0000000..d55e776 Binary files /dev/null and b/resources/animation/animation_frame_5.png differ diff --git a/resources/animation/animation_frame_6.png b/resources/animation/animation_frame_6.png new file mode 100644 index 0000000..ab8f15f Binary files /dev/null and b/resources/animation/animation_frame_6.png differ diff --git a/resources/animation/animation_frame_7.png b/resources/animation/animation_frame_7.png new file mode 100644 index 0000000..8be03c6 Binary files /dev/null and b/resources/animation/animation_frame_7.png differ diff --git a/resources/animation/animation_frame_8.png b/resources/animation/animation_frame_8.png new file mode 100644 index 0000000..e5150de Binary files /dev/null and b/resources/animation/animation_frame_8.png differ diff --git a/resources/animation/animation_frame_9.png b/resources/animation/animation_frame_9.png new file mode 100644 index 0000000..31be636 Binary files /dev/null and b/resources/animation/animation_frame_9.png differ diff --git a/resources/icons/apps.png b/resources/icons/apps.png new file mode 100644 index 0000000..535f73c Binary files /dev/null and b/resources/icons/apps.png differ diff --git a/resources/icons/dev.png b/resources/icons/dev.png new file mode 100644 index 0000000..1185139 Binary files /dev/null and b/resources/icons/dev.png differ diff --git a/resources/icons/hatchery.png b/resources/icons/hatchery.png new file mode 100644 index 0000000..7cf5a6a Binary files /dev/null and b/resources/icons/hatchery.png differ diff --git a/resources/icons/home.png b/resources/icons/home.png new file mode 100644 index 0000000..03d2f3d Binary files /dev/null and b/resources/icons/home.png differ diff --git a/resources/icons/settings.png b/resources/icons/settings.png new file mode 100644 index 0000000..2f4a61c Binary files /dev/null and b/resources/icons/settings.png differ diff --git a/sdkconfig b/sdkconfig index f8b80b7..7461ec7 100644 --- a/sdkconfig +++ b/sdkconfig @@ -157,15 +157,15 @@ CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y CONFIG_APP_BUILD_GENERATE_BINARIES=y CONFIG_APP_BUILD_BOOTLOADER=y CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y -CONFIG_APP_REPRODUCIBLE_BUILD=y +# CONFIG_APP_REPRODUCIBLE_BUILD is not set # end of Build type # # Application manager # # CONFIG_APP_COMPILE_TIME_DATE is not set -CONFIG_APP_EXCLUDE_PROJECT_VER_VAR=y -CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR=y +# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set +# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set # CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16 # end of Application manager @@ -675,7 +675,7 @@ CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT=y CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 -CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 +CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192 CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y # CONFIG_ESP_MAIN_TASK_AFFINITY_CPU1 is not set # CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set @@ -1475,7 +1475,7 @@ CONFIG_ESP32S2_PANIC_PRINT_HALT=y # CONFIG_ESP32S2_PANIC_GDBSTUB is not set CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 -CONFIG_MAIN_TASK_STACK_SIZE=3584 +CONFIG_MAIN_TASK_STACK_SIZE=8192 CONFIG_CONSOLE_UART_DEFAULT=y # CONFIG_CONSOLE_UART_CUSTOM is not set # CONFIG_ESP_CONSOLE_UART_NONE is not set