MORE DEMO APP

This commit is contained in:
RobotMan2412 2022-06-08 16:24:28 +02:00
parent 752ffe9c1e
commit f9daf1868d
99 changed files with 38 additions and 5355 deletions

View file

@ -4,7 +4,7 @@ IDF_PATH ?= $(shell pwd)/esp-idf
IDF_EXPORT_QUIET ?= 0 IDF_EXPORT_QUIET ?= 0
SHELL := /usr/bin/env bash SHELL := /usr/bin/env bash
.PHONY: prepare clean build flash erase monitor menuconfig image qemu install .PHONY: prepare clean build flash erase monitor menuconfig image
all: prepare build flash all: prepare build flash
@ -35,9 +35,3 @@ image:
cd "$(BUILDDIR)"; dd if=bootloader/bootloader.bin bs=1 seek=4096 of=flash.bin conv=notrunc cd "$(BUILDDIR)"; dd if=bootloader/bootloader.bin bs=1 seek=4096 of=flash.bin conv=notrunc
cd "$(BUILDDIR)"; dd if=partition_table/partition-table.bin bs=1 seek=36864 of=flash.bin conv=notrunc cd "$(BUILDDIR)"; dd if=partition_table/partition-table.bin bs=1 seek=36864 of=flash.bin conv=notrunc
cd "$(BUILDDIR)"; dd if=main.bin bs=1 seek=65536 of=flash.bin conv=notrunc cd "$(BUILDDIR)"; dd if=main.bin bs=1 seek=65536 of=flash.bin conv=notrunc
qemu: image
cd "$(BUILDDIR)"; qemu-system-xtensa -nographic -machine esp32 -drive 'file=flash.bin,if=mtd,format=raw'
install: flash

View file

@ -1,6 +1,6 @@
# MCH2022 ESP32 firmware: Launcher # MCH2022 template app
This repository contains the ESP32 part of the firmware for the MCH2022 badge. This firmware allows for device testing, setup, OTA updates and of course launching apps. This repository contains a template app for the MCH2022 badge.
## License ## License

View file

@ -1 +0,0 @@
../components/appfs

View file

@ -1 +0,0 @@
../components/appfs/bootloader_main

View file

@ -1,72 +1,6 @@
idf_component_register( idf_component_register(
SRCS "main.c" SRCS
"appfs_wrapper.c" "main.c"
"fpga_test.c" INCLUDE_DIRS
"graphics_wrapper.c" "." "include"
"menu.c"
"rp2040_updater.c"
"settings.c"
"system_wrapper.c"
"wifi_connection.c"
"wifi_connect.c"
"wifi_ota.c"
"fpga_download.c"
"audio.c"
"bootscreen.c"
"menus/launcher.c"
"menus/settings.c"
"menus/start.c"
"menus/dev.c"
"menus/wifi.c"
"uninstall.c"
"file_browser.c"
"test_common.c"
"factory_test.c"
"animation.c"
"button_test.c"
"adc_test.c"
"webusb.c"
INCLUDE_DIRS "."
"include"
"menus"
EMBED_TXTFILES ${project_dir}/resources/isrgrootx1.pem
EMBED_FILES ${project_dir}/resources/wallpaper.png
${project_dir}/resources/fpga_selftest.bin
${project_dir}/resources/rp2040_firmware.bin
${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
) )

View file

@ -1,76 +0,0 @@
#include <stdio.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "ili9341.h"
#include "pax_gfx.h"
#include "rp2040.h"
#include "hardware.h"
void test_adc(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
bool quit = false;
RP2040* rp2040 = get_rp2040();
const pax_font_t* font = pax_get_font("saira regular");
while (!quit) {
bool error = false;
float vbat = 0;
if (rp2040_read_vbat(rp2040, &vbat) != ESP_OK) {
error = true;
}
float vusb = 0;
if (rp2040_read_vusb(rp2040, &vusb) != ESP_OK) {
error = true;
}
/*uint16_t raw_temperature = 0;
if (rp2040_read_temp(rp2040, &raw_temperature) != ESP_OK) {
error = true;
}
uint8_t charging = 0;
if (rp2040_get_charging(rp2040, &charging) != ESP_OK) {
error = true;
}*/
//const float conversion_factor = 3.3f / (1 << 12); // 12-bit ADC with 3.3v vref
//float vtemperature = raw_temperature * conversion_factor; // Inside of RP2040 chip
//float temperature = 27 - (vtemperature - 0.706) / 0.001721; // From https://raspberrypi.github.io/pico-sdk-doxygen/group__hardware__adc.html
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0x325aa8);
pax_draw_text(pax_buffer, 0xFFFFFFFF, font, 18, 0, 20*0, "Analog inputs");
char buffer[64];
snprintf(buffer, sizeof(buffer), "Battery voltage %f v", vbat);
pax_draw_text(pax_buffer, 0xFFFFFFFF, font, 18, 0, 20*1, buffer);
snprintf(buffer, sizeof(buffer), "USB voltage %f v", vusb);
pax_draw_text(pax_buffer, 0xFFFFFFFF, font, 18, 0, 20*2, buffer);
/*snprintf(buffer, sizeof(buffer), "Temperature %f *c", temperature);
pax_draw_text(pax_buffer, 0xFFFFFFFF, font, 18, 0, 20*3, buffer);
snprintf(buffer, sizeof(buffer), "Charging %02X", charging);
pax_draw_text(pax_buffer, 0xFFFFFFFF, font, 18, 0, 20*4, buffer);*/
pax_draw_text(pax_buffer, 0xFFFFFFFF, font, 18, 0, 20*5, (error ? "ERROR" : ""));
ili9341_write(ili9341, pax_buffer->buf);
rp2040_input_message_t buttonMessage = {0};
if (xQueueReceive(buttonQueue, &buttonMessage, 250 / portTICK_PERIOD_MS) == pdTRUE) {
uint8_t pin = buttonMessage.input;
bool value = buttonMessage.state;
if (value) {
switch(pin) {
case RP2040_INPUT_BUTTON_HOME:
case RP2040_INPUT_BUTTON_BACK:
quit = true;
default:
break;
}
}
}
}
}

View file

@ -1,167 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <driver/gpio.h>
#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);
}
}

View file

@ -1,103 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#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);
}
uint8_t* load_file_to_ram(FILE* fd, size_t* fsize) {
fseek(fd, 0, SEEK_END);
*fsize = ftell(fd);
fseek(fd, 0, SEEK_SET);
uint8_t* file = malloc(*fsize);
if (file == NULL) return NULL;
fread(file, *fsize, 1, fd);
return file;
}
void appfs_boot_app(int fd) {
if (fd<0 || fd>255) {
REG_WRITE(RTC_CNTL_STORE0_REG, 0);
} else {
REG_WRITE(RTC_CNTL_STORE0_REG, 0xA5000000|fd);
}
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_ON);
esp_sleep_enable_timer_wakeup(10);
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 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 file");
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;
}

View file

@ -1,92 +0,0 @@
#include "audio.h"
#include "freertos/FreeRTOS.h"
#include <freertos/task.h>
#include "esp_system.h"
#include "driver/i2s.h"
#include "driver/rtc_io.h"
#include <stdio.h>
#include <string.h>
void _audio_init(int i2s_num) {
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_TX,
.sample_rate = 8000,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_MSB,
.dma_buf_count = 8,
.dma_buf_len = 256,
.intr_alloc_flags = 0,
.use_apll = false,
.bits_per_chan = I2S_BITS_PER_SAMPLE_16BIT
};
i2s_driver_install(i2s_num, &i2s_config, 0, NULL);
i2s_pin_config_t pin_config = {
.mck_io_num = 0,
.bck_io_num = 4,
.ws_io_num = 12,
.data_out_num = 13,
.data_in_num = I2S_PIN_NO_CHANGE
};
i2s_set_pin(i2s_num, &pin_config);
}
typedef struct _audio_player_cfg {
uint8_t* buffer;
size_t size;
bool free_buffer;
} audio_player_cfg_t;
void audio_player_task(void* arg) {
audio_player_cfg_t* config = (audio_player_cfg_t*) arg;
size_t sample_length = config->size;
uint8_t* sample_buffer = config->buffer;
size_t count;
size_t position = 0;
while (position < sample_length) {
size_t length = sample_length - position;
if (length > 256) length = 256;
uint8_t buffer[256];
memcpy(buffer, &sample_buffer[position], length);
for (size_t l = 0; l < length; l+=2) {
int16_t* sample = (int16_t*) &buffer[l];
*sample *= 0.50;
}
i2s_write(0, buffer, length, &count, portMAX_DELAY);
if (count != length) {
printf("i2s_write_bytes: count (%d) != length (%d)\n", count, length);
abort();
}
position += length;
}
i2s_zero_dma_buffer(0); // Fill buffer with silence
if (config->free_buffer) free(sample_buffer);
vTaskDelete(NULL); // Tell FreeRTOS that the task is done
}
void audio_init() {
_audio_init(0);
}
extern const uint8_t boot_snd_start[] asm("_binary_boot_snd_start");
extern const uint8_t boot_snd_end[] asm("_binary_boot_snd_end");
audio_player_cfg_t bootsound;
void play_bootsound() {
TaskHandle_t handle;
bootsound.buffer = boot_snd_start,
bootsound.size = boot_snd_end - boot_snd_start;
bootsound.free_buffer = false;
xTaskCreate(&audio_player_task, "Audio player", 4096, (void*) &bootsound, 10, &handle);
}

View file

@ -1,24 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include "pax_gfx.h"
#include "pax_codecs.h"
#include "ili9341.h"
extern const uint8_t mch2022_logo_png_start[] asm("_binary_mch2022_logo_png_start");
extern const uint8_t mch2022_logo_png_end[] asm("_binary_mch2022_logo_png_end");
void display_boot_screen(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* text) {
const pax_font_t *font = pax_get_font("saira regular");
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xFFFFFF);
pax_buf_t logo;
pax_decode_png_buf(&logo, (void*) mch2022_logo_png_start, mch2022_logo_png_end - mch2022_logo_png_start, PAX_BUF_16_565RGB, 0);
pax_draw_image(pax_buffer, &logo, (320 / 2) - (212 / 2), ((240 - 32 - 10) / 2) - (160 / 2));
pax_buf_destroy(&logo);
pax_vec1_t size = pax_text_size(font, 18, text);
pax_draw_text(pax_buffer, 0xFF000000, font, 18, (320 / 2) - (size.x / 2), 240 - 32, text);
ili9341_write(ili9341, pax_buffer->buf);
}

View file

@ -1,130 +0,0 @@
#include <stdio.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#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;
bool btn_joy_down_green = false;
bool btn_joy_up_green = false;
bool btn_joy_left_green = false;
bool btn_joy_right_green = false;
bool btn_joy_press_green = false;
bool btn_home_green = false;
bool btn_menu_green = false;
bool btn_select_green = false;
bool btn_start_green = false;
bool btn_accept_green = false;
bool btn_back_green = 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;
if (value) btn_joy_down_green = true;
break;
case RP2040_INPUT_JOYSTICK_UP:
btn_joy_up = value;
if (value) btn_joy_up_green = true;
break;
case RP2040_INPUT_JOYSTICK_LEFT:
btn_joy_left = value;
if (value) btn_joy_left_green = true;
break;
case RP2040_INPUT_JOYSTICK_RIGHT:
btn_joy_right = value;
if (value) btn_joy_right_green = true;
break;
case RP2040_INPUT_JOYSTICK_PRESS:
btn_joy_press = value;
if (value) btn_joy_press_green = true;
break;
case RP2040_INPUT_BUTTON_HOME:
btn_home = value;
if (value) btn_home_green = true;
break;
case RP2040_INPUT_BUTTON_MENU:
btn_menu = value;
if (value) btn_menu_green = true;
break;
case RP2040_INPUT_BUTTON_SELECT:
btn_select = value;
if (value) btn_select_green = true;
break;
case RP2040_INPUT_BUTTON_START:
btn_start = value;
if (value) btn_start_green = true;
break;
case RP2040_INPUT_BUTTON_ACCEPT:
btn_accept = value;
if (value) btn_accept_green = true;
break;
case RP2040_INPUT_BUTTON_BACK:
btn_back = value;
if (value) btn_back_green = true;
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, btn_joy_down_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*1, buffer);
snprintf(buffer, sizeof(buffer), "JOY UP %s", btn_joy_up ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_joy_up_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*2, buffer);
snprintf(buffer, sizeof(buffer), "JOY LEFT %s", btn_joy_left ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_joy_right_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*3, buffer);
snprintf(buffer, sizeof(buffer), "JOY RIGHT %s", btn_joy_right ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_joy_left_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*4, buffer);
snprintf(buffer, sizeof(buffer), "JOY PRESS %s", btn_joy_press ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_joy_press_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*5, buffer);
snprintf(buffer, sizeof(buffer), "BTN HOME %s", btn_home ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_home_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*6, buffer);
snprintf(buffer, sizeof(buffer), "BTN MENU %s", btn_menu ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_menu_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*7, buffer);
snprintf(buffer, sizeof(buffer), "BTN SELECT %s", btn_select ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_select_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*8, buffer);
snprintf(buffer, sizeof(buffer), "BTN START %s", btn_start ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_start_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*9, buffer);
snprintf(buffer, sizeof(buffer), "BTN A %s", btn_accept ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_accept_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*10, buffer);
snprintf(buffer, sizeof(buffer), "BTN B %s", btn_back ? "PRESSED" : "released");
pax_draw_text(pax_buffer, btn_back_green ? 0xFF00FF00 : 0xFFFFFFFF, NULL, 18, 0, 20*11, buffer);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
if (btn_home && btn_start) {
quit = true;
}
}
}

View file

@ -1,192 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <driver/gpio.h>
#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_adc_vbat(uint32_t* rc) {
float value = 0;
esp_err_t res = rp2040_read_vbat(get_rp2040(), &value);
*rc = value * 100;
return ((res == ESP_OK) && (value < 4.3) && (value > 3.9));
}
bool test_adc_vusb(uint32_t* rc) {
float value = 0;
esp_err_t res = rp2040_read_vusb(get_rp2040(), &value);
*rc = value * 100;
return ((res == ESP_OK) && (value > 4.5));
}
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 tests */
RUN_TEST("STUCK BUTTONS", test_stuck_buttons);
RUN_TEST("SD/LED POWER", test_sd_power);
RUN_TEST("Battery voltage", test_adc_vbat);
RUN_TEST("USB voltage", test_adc_vusb);
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);
}
}
}

View file

@ -1,227 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#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"
#include "bootscreen.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) {
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, 20, 18);
DIR* dir = opendir(path);
if (dir == NULL) {
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);
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';
}
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 renderbg = 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_BACK:
if (value) {
menuArgs = pd_args;
}
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 (renderbg) {
pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer);
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;
}
if (render) {
menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF000000);
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;
renderbg = 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);
}
}

View file

@ -1,267 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#include "driver/uart.h"
#include "hardware.h"
#include "managed_i2c.h"
#include "pax_gfx.h"
#include "ice40.h"
#include "system_wrapper.h"
#include "graphics_wrapper.h"
#include "esp32/rom/crc.h"
void fpga_install_uart() {
fflush(stdout);
ESP_ERROR_CHECK(uart_driver_install(0, 2048, 0, 0, NULL, 0));
uart_config_t uart_config = {
.baud_rate = 921600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
ESP_ERROR_CHECK(uart_param_config(0, &uart_config));
}
void fpga_uninstall_uart() {
uart_driver_delete(0);
}
bool fpga_read_stdin(uint8_t* buffer, uint32_t len, uint32_t timeout) {
int read = uart_read_bytes(0, buffer, len, timeout / portTICK_PERIOD_MS);
return (read == len);
}
bool fpga_uart_sync(uint32_t* length, uint32_t* crc) {
uint8_t data[256];
uart_read_bytes(0, data, sizeof(data), 10 / portTICK_PERIOD_MS);
char command[] = "FPGA";
uart_write_bytes(0, command, 4);
uint8_t rx_buffer[4 * 3];
fpga_read_stdin(rx_buffer, sizeof(rx_buffer), 1000);
if (memcmp(rx_buffer, "FPGA", 4) != 0) return false;
memcpy((uint8_t*) length, &rx_buffer[4 * 1], 4);
memcpy((uint8_t*) crc, &rx_buffer[4 * 2], 4);
return true;
}
bool fpga_uart_load(uint8_t* buffer, uint32_t length) {
return fpga_read_stdin(buffer, length, 3000);
}
void fpga_uart_mess(const char *mess) {
uart_write_bytes(0, mess, strlen(mess));
}
esp_err_t fpga_process_events(xQueueHandle buttonQueue, ICE40* ice40, uint16_t *key_state, uint16_t *idle_count)
{
rp2040_input_message_t buttonMessage = {0};
while (xQueueReceive(buttonQueue, &buttonMessage, 0) == pdTRUE) {
uint8_t pin = buttonMessage.input;
bool value = buttonMessage.state;
uint16_t key_mask = 0;
switch(pin) {
case RP2040_INPUT_JOYSTICK_DOWN:
key_mask = 1 << 0;
break;
case RP2040_INPUT_JOYSTICK_UP:
key_mask = 1 << 1;
break;
case RP2040_INPUT_JOYSTICK_LEFT:
key_mask = 1 << 2;
break;
case RP2040_INPUT_JOYSTICK_RIGHT:
key_mask = 1 << 3;
break;
case RP2040_INPUT_JOYSTICK_PRESS:
key_mask = 1 << 4;
break;
case RP2040_INPUT_BUTTON_HOME:
key_mask = 1 << 5;
break;
case RP2040_INPUT_BUTTON_MENU:
key_mask = 1 << 6;
break;
case RP2040_INPUT_BUTTON_SELECT:
key_mask = 1 << 7;
break;
case RP2040_INPUT_BUTTON_START:
key_mask = 1 << 8;
break;
case RP2040_INPUT_BUTTON_ACCEPT:
key_mask = 1 << 9;
break;
case RP2040_INPUT_BUTTON_BACK:
key_mask = 1 << 10;
default:
break;
}
if (key_mask != 0)
{
if (value) {
*key_state |= key_mask;
}
else {
*key_state &= ~key_mask;
}
uint8_t spi_message[5] = { 0xf4 };
spi_message[1] = *key_state >> 8;
spi_message[2] = *key_state & 0xff;
spi_message[3] = key_mask >> 8;
spi_message[4] = key_mask & 0xff;
esp_err_t res = ice40_send(ice40, spi_message, 5);
if (res != ESP_OK) {
return res;
}
}
*idle_count = 0;
}
return ESP_OK;
}
void fpga_download(xQueueHandle buttonQueue, ICE40* ice40, pax_buf_t* pax_buffer, ILI9341* ili9341) {
char message[64];
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0x325aa8);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "FPGA download mode");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, "Preparing...");
ili9341_write(ili9341, pax_buffer->buf);
fpga_install_uart();
ice40_disable(ice40);
ili9341_init(ili9341);
uint8_t counter = 0;
uint32_t length = 0;
uint32_t crc = 0;
while (!fpga_uart_sync(&length, &crc)) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0x325aa8);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "FPGA download mode");
snprintf(message, sizeof(message), "Waiting for bitstream%s%s%s", (counter > 0) ? "." : " ", (counter > 1) ? "." : " ", (counter > 2) ? "." : " ");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
counter++;
if (counter > 3) counter = 0;
}
while (true) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0x325aa8);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "FPGA download mode");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, "Receiving bitstream...");
ili9341_write(ili9341, pax_buffer->buf);
uint8_t* buffer = malloc(length);
if (buffer == NULL) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "FPGA download mode");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, "Malloc failed");
ili9341_write(ili9341, pax_buffer->buf);
vTaskDelay(1000 / portTICK_PERIOD_MS);
fpga_uninstall_uart();
return;
}
if (!fpga_uart_load(buffer, length)) {
free(buffer);
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "FPGA download mode");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, "Timeout while loading");
ili9341_write(ili9341, pax_buffer->buf);
vTaskDelay(1000 / portTICK_PERIOD_MS);
fpga_uninstall_uart();
return;
}
uint32_t checkCrc = crc32_le(0, buffer, length);
if (checkCrc != crc) {
free(buffer);
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "FPGA download mode");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, "CRC incorrect");
snprintf(message, sizeof(message), "Provided CRC: %08X", crc);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*2, message);
snprintf(message, sizeof(message), "Calculated CRC: %08X", checkCrc);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*3, message);
ili9341_write(ili9341, pax_buffer->buf);
vTaskDelay(1000 / portTICK_PERIOD_MS);
snprintf(message, sizeof(message), "CRC incorrect %08X %08x\n", crc, checkCrc);
fpga_uart_mess(message);
fpga_uninstall_uart();
return;
}
fpga_uart_mess("CRC correct\n");
ili9341_deinit(ili9341);
ili9341_select(ili9341, false);
vTaskDelay(200 / portTICK_PERIOD_MS);
ili9341_select(ili9341, true);
esp_err_t res = ice40_load_bitstream(ice40, buffer, length);
free(buffer);
if (res != ESP_OK) {
ice40_disable(ice40);
ili9341_init(ili9341);
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "FPGA download mode");
snprintf(message, sizeof(message), "Upload failed: %d", res);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
vTaskDelay(1000 / portTICK_PERIOD_MS);
snprintf(message, sizeof(message), "uploading bitstream failed with %d\n", res);
fpga_uart_mess(message);
fpga_uninstall_uart();
return;
}
snprintf(message, sizeof(message), "bitstream has uploaded\n");
fpga_uart_mess(message);
// Waiting for next download and sending key strokes to FPGA
uint16_t key_state = 0;
uint16_t idle_count = 0;
while (true) {
if (idle_count >= 200) {
if (fpga_uart_sync(&length, &crc)) {
break;
}
idle_count = 0;
}
esp_err_t res = fpga_process_events(buttonQueue, ice40, &key_state, &idle_count);
if (res != ESP_OK) {
ice40_disable(ice40);
ili9341_init(ili9341);
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "FPGA download mode");
snprintf(message, sizeof(message), "Error: %d", res);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
vTaskDelay(1000 / portTICK_PERIOD_MS);
snprintf(message, sizeof(message), "processing events failed with %d\n", res);
fpga_uart_mess(message);
fpga_uninstall_uart();
return;
}
vTaskDelay(10 / portTICK_PERIOD_MS);
idle_count++;
}
ice40_disable(ice40);
ili9341_init(ili9341);
}
}

View file

@ -1,509 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <driver/gpio.h>
#include "hardware.h"
#include "ili9341.h"
#include "ice40.h"
#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");
static const char *TAG = "fpga_test";
/* SPI commands */
#define SPI_CMD_NOP1 0x00
#define SPI_CMD_SOC_MSG 0x10
#define SPI_CMD_REG_ACCESS 0xf0
#define SPI_CMD_LOOPBACK 0xf1
#define SPI_CMD_LCD_PASSTHROUGH 0xf2
#define SPI_CMD_BUTTON_REPORT 0xf4
#define SPI_CMD_IRQ_ACK 0xfd
#define SPI_CMD_RESP_ACK 0xfe
#define SPI_CMD_NOP2 0xff
/* Messages to self-test SoC */
#define SOC_CMD_PING 0x00
#define SOC_CMD_PING_PARAM 0xc0ffee
#define SOC_CMD_PING_RESP 0xcafebabe
#define SOC_CMD_RGB_STATE_SET 0x10
#define SOC_CMD_IRQN_SET 0x11
#define SOC_CMD_LCD_RGB_CYCLE_SET 0x12
#define SOC_CMD_PMOD_CYCLE_SET 0x13
#define SOC_CMD_LCD_PASSTHROUGH_SET 0x14
#define SOC_CMD_PSRAM_TEST 0x20
#define SOC_CMD_UART_LOOPBACK_TEST 0x21
#define SOC_CMD_PMOD_OPEN_TEST 0x22
#define SOC_CMD_PMOD_PLUG_TEST 0x23
#define SOC_CMD_LCD_INIT_TEST 0x24
#define SOC_CMD_LCD_CHECK_MODE 0x30
#define SOC_RESP_OK 0x00000000
/* SoC commands */
static bool soc_message(ICE40* ice40, uint8_t cmd, uint32_t param, uint32_t *resp, TickType_t ticks_to_wait) {
esp_err_t res;
uint8_t data_tx[6];
uint8_t data_rx[6];
/* Default delay */
ticks_to_wait /= 10; /* We do 10 retries */
if (!ticks_to_wait)
ticks_to_wait = pdMS_TO_TICKS(50);
/* Prepare message */
data_tx[0] = SPI_CMD_SOC_MSG;
data_tx[1] = cmd;
data_tx[2] = (param >> 16) & 0xff;
data_tx[3] = (param >> 8) & 0xff;
data_tx[4] = (param ) & 0xff;
/* Send message to PicoRV */
res = ice40_send_turbo(ice40, data_tx, 5);
if (res != ESP_OK) {
ESP_LOGE(TAG, "SoC message TX failed");
return false;
}
/* Poll until we get a response */
data_tx[0] = SPI_CMD_RESP_ACK;
for (int i=0; i<10; i++) {
/* Poll */
res = ice40_transaction(ice40, data_tx, 6, data_rx, 6);
if (res != ESP_OK) {
ESP_LOGE(TAG, "SoC response RX failed");
return false;
}
/* Was response valid ? */
if (data_rx[1] & 0x80)
break;
/* Wait before retry */
vTaskDelay(ticks_to_wait);
}
if (!(data_rx[1] & 0x80)) {
ESP_LOGE(TAG, "SoC response RX timeout");
return false;
}
/* Report response */
if (resp) {
*resp = 0;
for (int i=0; i<4; i++)
*resp = (*resp << 8) | data_rx[2+i];
}
return true;
}
/* Test routines */
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);
if (res != ESP_OK) {
*rc = res;
return false;
}
*rc = 0;
return true;
}
static bool _test_spi_loopback_one(ICE40* ice40) {
esp_err_t res;
uint8_t data_tx[257];
uint8_t data_rx[258];
/* Generate pseudo random sequence */
data_tx[1] = 1;
for (int i = 2; i < 257; i++)
data_tx[i] = (data_tx[i-1] << 1) ^ ((data_tx[i-1] & 0x80) ? 0x1d : 0x00);
/* Send 256 bytes at high speed with echo command */
data_tx[0] = SPI_CMD_LOOPBACK;
res = ice40_send_turbo(ice40, data_tx, 257);
if (res != ESP_OK) {
ESP_LOGE(TAG, "SPI loopback transaction 1 failed (Turbo TX)");
return false;
}
/* Execute full duplex transaction with next 128 bytes */
res = ice40_transaction(ice40, data_tx, 257, data_rx, 257);
if (res != ESP_OK) {
ESP_LOGE(TAG, "SPI loopback transaction 2 failed (Full Duplex)");
return false;
}
/* Validate response present */
if ((data_rx[1] & 0x80) == 0) {
ESP_LOGE(TAG, "SPI loopback transaction 2 reports no response available\n");
return false;
}
/* Validate RX data (only 254 byte got read) */
if (memcmp(&data_rx[2], &data_tx[1], 254)) {
ESP_LOGE(TAG, "SPI loopback transaction 1->2 integrity fail:\n");
for (int i = 0; i < 254; i++)
printf("%02X%c", data_rx[i], ((i&0xf)==0xf) ? '\n' : ' ');
printf("\n");
return false;
}
/* Read two responses and ack them */
for (int t = 0; t < 2; t++) {
/* Receive half duplex */
res = ice40_receive(ice40, data_rx, 258);
if (res != ESP_OK) {
ESP_LOGE(TAG, "SPI loopback transaction 3.%d failed (Half Duplex RX)", t);
return false;
}
/* Short acknowledge command */
data_tx[0] = SPI_CMD_RESP_ACK;
res = ice40_send_turbo(ice40, data_tx, 1);
if (res != ESP_OK) {
ESP_LOGE(TAG, "SPI loopback transaction 4.%d failed (Turbo ACK)", t);
return false;
}
/* Validate response present */
if ((data_rx[1] & 0x80) == 0) {
ESP_LOGE(TAG, "SPI loopback transaction 3.%d reports no response available\n", t);
return false;
}
/* Validate RX data (only 254 byte got read) */
if (memcmp(&data_rx[2], &data_tx[1], 254)) {
ESP_LOGE(TAG, "SPI loopback transaction %d->3.%d integrity fail:\n", 1+t, t);
for (int i = 0; i < 254; i++)
printf("%02X%c", data_rx[i], ((i&0xf)==0xf) ? '\n' : ' ');
printf("\n");
return false;
}
}
/* Check there is no more responses pending */
data_tx[0] = SPI_CMD_NOP2;
res = ice40_transaction(ice40, data_tx, 2, data_rx, 2);
if (res != ESP_OK) {
ESP_LOGE(TAG, "SPI loopback transaction 5 failed (Full Duplex)");
return false;
}
if ((data_rx[1] & 0x80) != 0) {
ESP_LOGE(TAG, "SPI loopback transaction 5 reports response available\n");
return false;
}
return true;
}
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))
break;
}
/* Failure ? */
if (i != 256) {
*rc = i + 1;
return false;
}
/* OK ! */
*rc = 0;
return true;
}
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;
return false;
}
/* Check response */
if (*rc != SOC_CMD_PING_RESP)
return false;
/* Success */
*rc = 0;
return true;
}
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));
/* Execute command */
if (!soc_message(ice40, SOC_CMD_UART_LOOPBACK_TEST, 0, rc, 0)) {
*rc = -1;
return false;
}
/* Disable loopback mode of RP2040 */
rp2040_set_fpga_loopback(get_rp2040(), true, false);
/* Check response */
return *rc == SOC_RESP_OK;
}
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;
return false;
}
/* Check response */
return *rc == SOC_RESP_OK;
}
static bool test_irq_n(uint32_t *rc) {
ICE40* ice40 = get_ice40();
esp_err_t res;
/* Set pin as input */
res = gpio_set_direction(GPIO_INT_FPGA, GPIO_MODE_INPUT);
if (res != ESP_OK) {
*rc = 32;
return false;
}
/* Assert interrupt line */
if (!soc_message(ice40, SOC_CMD_IRQN_SET, 1, rc, 0)) {
*rc = -1;
return false;
}
if (*rc != SOC_RESP_OK)
return false;
/* Check level is 0 */
if (gpio_get_level(GPIO_INT_FPGA) != 0) {
*rc = 16;
return false;
}
/* Release interrupt line */
if (!soc_message(ice40, SOC_CMD_IRQN_SET, 0, rc, 0)) {
*rc = -1;
return false;
}
if (*rc != SOC_RESP_OK)
return false;
/* Check level is 1 */
if (gpio_get_level(GPIO_INT_FPGA) != 1) {
*rc = 16;
return false;
}
return true;
}
static bool test_lcd_mode(uint32_t *rc) {
ICE40* ice40 = get_ice40();
esp_err_t res;
bool ok;
/* Defaults */
ok = true;
*rc = 0;
/* Check state is 0 */
if (!soc_message(ice40, SOC_CMD_LCD_CHECK_MODE, 0, rc, 0)) {
*rc = 16;
return false;
}
if (*rc != SOC_RESP_OK)
return false;
/* Set LCD mode to 1 */
res = gpio_set_level(GPIO_LCD_MODE, 1);
if (res != ESP_OK) {
*rc = 32;
return false;
}
/* Check state is 1 */
if (!soc_message(ice40, SOC_CMD_LCD_CHECK_MODE, 1, rc, 0)) {
*rc = 17;
ok = false;
}
if (*rc != SOC_RESP_OK)
ok = false;
/* Set LCD mode back to 0 */
res = gpio_set_level(GPIO_LCD_MODE, 0);
if (res != ESP_OK) {
*rc = 33;
return false;
}
/* All good */
return ok;
}
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;
return false;
}
/* Check response */
return *rc == SOC_RESP_OK;
}
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;
return false;
}
/* Check response */
return *rc == SOC_RESP_OK;
}
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;
return false;
}
/* Check response */
return *rc == SOC_RESP_OK;
}
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;
/* 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("Bitstream load", test_bitstream_load);
RUN_TEST_MANDATORY("SPI loopback", test_spi_loopback);
RUN_TEST_MANDATORY("SoC loopback", test_soc_loopback);
/* Set indicator to "in-progress" */
soc_message(ice40, SOC_CMD_RGB_STATE_SET, 1, NULL, 0);
/* Run non-interactive tests */
RUN_TEST("UART loopback", test_uart_loopback);
RUN_TEST("PSRAM", test_psram);
RUN_TEST("IRQ_n signal", test_irq_n);
RUN_TEST("LCD_MODE signal", test_lcd_mode);
RUN_TEST("PMOD open", test_pmod_open);
/* Show instructions for interactive test */
/*pax_draw_text(pax_buffer, 0xffc0c0c0, font, 9, 25, 20*line+ 0, "Insert PMOD plug");
pax_draw_text(pax_buffer, 0xffc0c0c0, font, 9, 25, 20*line+10, "Then press button for interactive test");
pax_draw_text(pax_buffer, 0xffc0c0c0, font, 9, 25, 20*line+20, " - Check LCD color bars");
pax_draw_text(pax_buffer, 0xffc0c0c0, font, 9, 25, 20*line+30, " - Then LCD & RGB led color cycling");
ili9341_write(ili9341, pax_buffer->buf);*/
/* Wait for button */
//wait_button(buttonQueue);
/* Clear the instructions from buffer */
//pax_draw_rect(pax_buffer, 0xff8060f0, 0, 20*line, 320, 240-20*line);
/* Handover LCD to FPGA */
ili9341_deinit(ili9341);
/* Run interactive tests */
//RUN_TEST("PMOD plug", test_pmod_plug);
RUN_TEST("LCD init", test_lcd_init);
/* Wait a second (for user to see color bars) */
vTaskDelay(pdMS_TO_TICKS(1000));
/* Start LCD / RGB cycling */
soc_message(ice40, SOC_CMD_LCD_RGB_CYCLE_SET, 1, NULL, 0);
/* Wait for button */
RUN_TEST("LCD control", test_wait_for_response);
/* Stop LCD / RGB cycling */
soc_message(ice40, SOC_CMD_LCD_RGB_CYCLE_SET, 0, NULL, 0);
/* Take control of the LCD back and refresh screen */
ili9341_init(ili9341);
error:
/* Update indicator */
soc_message(ice40, SOC_CMD_RGB_STATE_SET, ok ? 2 : 3, NULL, 0);
/* Pass / Fail result on screen */
if (ok)
pax_draw_text(pax_buffer, 0xff00ff00, font, 36, 0, 20*line, "PASS");
else
pax_draw_text(pax_buffer, 0xffff0000, font, 36, 0, 20*line, "FAIL");
ili9341_write(ili9341, pax_buffer->buf);
/* Cleanup */
ice40_disable(ice40);
return ok;
}
void fpga_test(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
run_fpga_tests(buttonQueue, pax_buffer, ili9341);
test_wait_for_response(NULL);
}

View file

@ -1,161 +0,0 @@
#include <string.h>
#include "graphics_wrapper.h"
#include "hardware.h"
#include "pax_keyboard.h"
#include "rp2040.h"
void render_message(pax_buf_t *pax_buffer, char* message, float aPosX, float aPosY, float aWidth, float aHeight) {
pax_col_t fgColor = 0xFFFF0000;
pax_col_t bgColor = 0xFFFFD4D4;
pax_clip(pax_buffer, aPosX, aPosY, aWidth, aHeight);
pax_simple_rect(pax_buffer, bgColor, aPosX, aPosY, aWidth, aHeight);
pax_outline_rect(pax_buffer, fgColor, aPosX, aPosY, aWidth, aHeight);
pax_clip(pax_buffer, aPosX + 1, aPosY + 1, aWidth - 2, aHeight - 2);
pax_draw_text(pax_buffer, fgColor, NULL, 18, aPosX + 1, aPosY + 1, message);
pax_noclip(pax_buffer);
}
esp_err_t graphics_task(pax_buf_t* pax_buffer, ILI9341* ili9341, menu_t* menu, char* message) {
pax_background(pax_buffer, 0xCCCCCC);
if (menu != NULL) {
menu_render(pax_buffer, menu, 10, 10, 320-20, 240-20, 0xFF000000);
}
if (message != NULL) {
render_message(pax_buffer, message, 20, 110, 320-40, 20);
}
return ili9341_write(ili9341, pax_buffer->buf);
}
bool keyboard(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, float aPosX, float aPosY, float aWidth, float aHeight, const char* aTitle, const char* aHint, char* aOutput, size_t aOutputSize) {
const pax_font_t *font = pax_get_font("saira regular");
bool accepted = false;
pkb_ctx_t kb_ctx;
pkb_init(pax_buffer, &kb_ctx, 1024);
pkb_set_content(&kb_ctx, aOutput);
kb_ctx.kb_font = font;
kb_ctx.text_font = font;
pax_col_t fgColor = 0xFF000000;
pax_col_t bgColor = 0xFFFFFFFF;
pax_col_t shadowColor = 0xFFC0C3C8;
pax_col_t borderColor = 0xFF0000AA;
pax_col_t titleBgColor = 0xFF080764;
pax_col_t titleColor = 0xFFFFFFFF;
pax_col_t selColor = 0xff007fff;
kb_ctx.text_col = borderColor;
kb_ctx.sel_text_col = bgColor;
kb_ctx.sel_col = selColor;
kb_ctx.bg_col = bgColor;
kb_ctx.kb_font_size = 18;
float titleHeight = 20;
float hintHeight = 14;
pax_noclip(pax_buffer);
pax_simple_rect(pax_buffer, shadowColor, aPosX+5, aPosY+5, aWidth, aHeight);
pax_simple_rect(pax_buffer, bgColor, aPosX, aPosY, aWidth, aHeight);
pax_outline_rect(pax_buffer, borderColor, aPosX, aPosY, aWidth, aHeight);
pax_simple_rect(pax_buffer, titleBgColor, aPosX, aPosY, aWidth, titleHeight);
pax_simple_line(pax_buffer, titleColor, aPosX + 1, aPosY + titleHeight, aPosX + aWidth - 2, aPosY + titleHeight - 1);
pax_clip(pax_buffer, aPosX + 1, aPosY + 1, aWidth - 2, titleHeight - 2);
pax_draw_text(pax_buffer, titleColor, font, titleHeight - 2, aPosX + 1, aPosY + 1, aTitle);
pax_clip(pax_buffer, aPosX + 1, aPosY + aHeight - hintHeight, aWidth - 2, hintHeight);
pax_draw_text(pax_buffer, borderColor, font, hintHeight - 2, aPosX + 1, aPosY + aHeight - hintHeight, aHint);
pax_noclip(pax_buffer);
kb_ctx.x = aPosX + 1;
kb_ctx.y = aPosY + titleHeight + 1 ;
kb_ctx.width = aWidth - 2;
kb_ctx.height = aHeight - 3 - titleHeight - hintHeight;
bool running = true;
while (running) {
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) {
pkb_press(&kb_ctx, PKB_DOWN);
} else {
pkb_release(&kb_ctx, PKB_DOWN);
}
break;
case RP2040_INPUT_JOYSTICK_UP:
if (value) {
pkb_press(&kb_ctx, PKB_UP);
} else {
pkb_release(&kb_ctx, PKB_UP);
}
break;
case RP2040_INPUT_JOYSTICK_LEFT:
if (value) {
pkb_press(&kb_ctx, PKB_LEFT);
} else {
pkb_release(&kb_ctx, PKB_LEFT);
}
break;
case RP2040_INPUT_JOYSTICK_RIGHT:
if (value) {
pkb_press(&kb_ctx, PKB_RIGHT);
} else {
pkb_release(&kb_ctx, PKB_RIGHT);
}
break;
case RP2040_INPUT_JOYSTICK_PRESS:
if (value) {
pkb_press(&kb_ctx, PKB_SHIFT);
} else {
pkb_release(&kb_ctx, PKB_SHIFT);
}
break;
case RP2040_INPUT_BUTTON_ACCEPT:
if (value) {
pkb_press(&kb_ctx, PKB_CHARSELECT);
} else {
pkb_release(&kb_ctx, PKB_CHARSELECT);
}
break;
case RP2040_INPUT_BUTTON_BACK:
if (value) {
pkb_press(&kb_ctx, PKB_DELETE_BEFORE);
} else {
pkb_release(&kb_ctx, PKB_DELETE_BEFORE);
}
break;
case RP2040_INPUT_BUTTON_SELECT:
if (value) {
pkb_press(&kb_ctx, PKB_MODESELECT);
} else {
pkb_release(&kb_ctx, PKB_MODESELECT);
}
break;
case RP2040_INPUT_BUTTON_HOME:
if (value) {
running = false;
}
break;
default:
break;
}
}
pkb_loop(&kb_ctx);
if (kb_ctx.dirty) {
pkb_redraw(pax_buffer, &kb_ctx);
ili9341_write(ili9341, pax_buffer->buf);
}
if (kb_ctx.input_accepted) {
memset(aOutput, 0, aOutputSize);
strncpy(aOutput, kb_ctx.content, aOutputSize - 1);
running = false;
accepted = true;
}
}
pkb_destroy(&kb_ctx);
return accepted;
}

View file

@ -1,9 +0,0 @@
#include <stdio.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "ili9341.h"
#include "pax_gfx.h"
void test_adc(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,4 +0,0 @@
#include "pax_gfx.h"
#include "ili9341.h"
void display_animation(pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,17 +0,0 @@
#pragma once
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#include "appfs.h"
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);

View file

@ -1,3 +0,0 @@
#pragma once
void audio_init();
void play_bootsound();

View file

@ -1,4 +0,0 @@
#include "pax_gfx.h"
#include "ili9341.h"
void display_boot_screen(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* text);

View file

@ -1,9 +0,0 @@
#include <stdio.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "ili9341.h"
#include "pax_gfx.h"
void test_buttons(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,10 +0,0 @@
#pragma once
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "ili9341.h"
#include "pax_gfx.h"
void factory_test(pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,9 +0,0 @@
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#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);

View file

@ -1,8 +0,0 @@
#pragma once
#include "ice40.h"
#include "pax_gfx.h"
#include "ili9341.h"
#include <freertos/FreeRTOS.h>
void fpga_download(xQueueHandle buttonQueue, ICE40* ice40, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,14 +0,0 @@
#pragma once
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "hardware.h"
#include "rp2040.h"
#include "ili9341.h"
#include "ice40.h"
#include "pax_gfx.h"
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);

View file

@ -1,16 +0,0 @@
#pragma once
#include <stdint.h>
#include <sdkconfig.h>
#include <esp_system.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "pax_gfx.h"
#include "ili9341.h"
#include "menu.h"
esp_err_t graphics_task(pax_buf_t* pax_buffer, ILI9341* ili9341, menu_t* menu, char* message);
bool keyboard(xQueueHandle buttonQueue, pax_buf_t* aBuffer, ILI9341* ili9341, float aPosX, float aPosY, float aWidth, float aHeight, const char* aTitle, const char* aHint, char* aOutput, size_t aOutputSize);

0
main/include/main.h Normal file
View file

View file

@ -1,65 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif //__cplusplus
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "pax_gfx.h"
typedef bool (*menu_callback_t)();
typedef struct _menu_item {
char* label;
menu_callback_t callback;
void* callbackArgs;
pax_buf_t* icon;
// Linked list
struct _menu_item* previousItem;
struct _menu_item* nextItem;
} menu_item_t;
typedef struct menu {
char* title;
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, 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);
void menu_navigate_next(menu_t* aMenu);
size_t menu_get_position(menu_t* aMenu);
size_t menu_get_length(menu_t* aMenu);
void* menu_get_callback_args(menu_t* aMenu, size_t aPosition);
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);
#ifdef __cplusplus
}
#endif //__cplusplus

View file

@ -1,13 +0,0 @@
#pragma once
#include <stdint.h>
#include <sdkconfig.h>
#include <esp_system.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "pax_gfx.h"
#include "ili9341.h"
void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,11 +0,0 @@
#pragma once
#include "hardware.h"
#include "rp2040.h"
#include "ili9341.h"
#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);

View file

@ -1,3 +0,0 @@
#pragma once
void restart();

View file

@ -1,28 +0,0 @@
#pragma once
#include <stdio.h>
#include <string.h>
#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)

View file

@ -1,8 +0,0 @@
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "pax_gfx.h"
#include "ili9341.h"
void uninstall_browser(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,8 +0,0 @@
#pragma once
#include "ice40.h"
#include "pax_gfx.h"
#include "ili9341.h"
#include <freertos/FreeRTOS.h>
void webusb_main(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,5 +0,0 @@
#pragma once
#include <stdbool.h>
bool wifi_connect_to_stored();

View file

@ -1,46 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include "esp_wifi.h"
#include "esp_wifi_types.h"
#include "esp_wpa2.h"
#define WIFI_MCH2022_SSID "MCH2022"
#define WIFI_MCH2022_USER "mch2022"
#define WIFI_MCH2022_IDENT "mch2022"
#define WIFI_MCH2022_PASSWORD "mch2022"
#define WIFI_MCH2022_AUTH WIFI_AUTH_WPA2_ENTERPRISE
#define WIFI_MCH2022_PHASE2 ESP_EAP_TTLS_PHASE2_MSCHAPV2
// Simpler interpretation of WiFi signal strength.
typedef enum {
WIFI_STRENGTH_VERY_BAD,
WIFI_STRENGTH_BAD,
WIFI_STRENGTH_GOOD,
WIFI_STRENGTH_VERY_GOOD,
} wifi_strength_t;
// Thresholds for aforementioned signal strength definitions.
#define WIFI_THRESH_BAD -80
#define WIFI_THRESH_GOOD -70
#define WIFI_THRESH_VERY_GOOD -67
// Firt time initialisation of the WiFi stack.
void wifi_init();
// Connect to a traditional username/password WiFi network.
bool wifi_connect(const char* aSsid, const char* aPassword, wifi_auth_mode_t aAuthmode, uint8_t aRetryMax);
// Connect to a WPA2 enterprise WiFi network.
bool wifi_connect_ent(const char* aSsid, const char *aIdent, const char *aAnonIdent, const char* aPassword, esp_eap_ttls_phase2_types phase2, uint8_t aRetryMax);
// Scan for WiFi networks.
// Updates the APs pointer if non-null.
// Returns the number of APs found.
size_t wifi_scan(wifi_ap_record_t **aps);
// Get the strength value for a given RSSI.
wifi_strength_t wifi_rssi_to_strength(int8_t rssi);

View file

@ -1,6 +0,0 @@
#pragma once
#include "pax_gfx.h"
#include "ili9341.h"
void ota_update(pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,295 +1,38 @@
#include <stdio.h>
#include <string.h> // This file contains a simple hello world app which you can base you own apps on.
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h> #include "main.h"
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <nvs.h>
#include "driver/uart.h"
#include "hardware.h" #include "hardware.h"
#include "managed_i2c.h"
#include "pax_gfx.h" #include "pax_gfx.h"
#include "sdcard.h" #include "pax_codecs.h"
#include "appfs.h" #include "ili9341.h"
#include "esp_ota_ops.h" #include "freertos/FreeRTOS.h"
#include "rp2040.h" #include "freertos/task.h"
#include "rp2040bl.h" #include "freertos/queue.h"
#include "esp_system.h"
#include "fpga_test.h" pax_buf_t buf;
xQueueHandle buttonQueue;
#include "menu.h" static const char *TAG = "mch2022-demo-app";
#include "system_wrapper.h"
#include "graphics_wrapper.h"
#include "appfs_wrapper.h"
#include "settings.h"
#include "wifi_connection.h"
#include "rp2040_updater.h"
#include "ws2812.h" void disp_flush() {
ili9341_write(get_ili9341(), buf.buf);
#include "esp32/rom/crc.h"
#include "efuse.h"
#include "wifi_ota.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include <pax_codecs.h>
#include "audio.h"
#include "bootscreen.h"
#include "menus/start.h"
#include "factory_test.h"
#include "fpga_download.h"
#include "webusb.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");
extern const uint8_t logo_screen_png_start[] asm("_binary_logo_screen_png_start");
extern const uint8_t logo_screen_png_end[] asm("_binary_logo_screen_png_end");
static const char *TAG = "main";
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);
if (line0 != NULL) pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, line0);
if (line1 != NULL) pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*1, line1);
if (line2 != NULL) pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*2, line2);
if (line3 != NULL) pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 12, 0, 20*3, line3);
ili9341_write(ili9341, pax_buffer->buf);
} }
void stop() { void app_main() {
ESP_LOGW(TAG, "*** HALTED ***"); // Init HW.
gpio_set_direction(GPIO_SD_PWR, GPIO_MODE_OUTPUT); bsp_init();
gpio_set_level(GPIO_SD_PWR, 1); bsp_rp2040_init();
ws2812_init(GPIO_LED_DATA); buttonQueue = get_rp2040()->queue;
uint8_t led_off[15] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
uint8_t led_red[15] = {0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0, 0, 50, 0}; // Init GFX.
uint8_t led_red2[15] = {0, 0xFF, 0, 0, 0xFF, 0, 0, 0xFF, 0, 0, 0xFF, 0, 0, 0xFF, 0}; pax_buf_init(&buf, NULL, 320, 240, PAX_BUF_16_565RGB);
while (true) {
ws2812_send_data(led_red2, sizeof(led_red2)); // Show some hello world.
vTaskDelay(pdMS_TO_TICKS(200)); pax_background(&buf, 0xffff00ff);
ws2812_send_data(led_red, sizeof(led_red)); disp_flush();
vTaskDelay(pdMS_TO_TICKS(200));
ws2812_send_data(led_off, sizeof(led_off)); // Just wait.
vTaskDelay(pdMS_TO_TICKS(200)); while (1) vTaskDelay(10000);
}
}
void app_main(void) {
esp_err_t res;
audio_init();
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);
if (framebuffer == NULL) {
ESP_LOGE(TAG, "Failed to allocate framebuffer");
esp_restart();
}
memset(framebuffer, 0, ILI9341_BUFFER_SIZE);
pax_buf_t* pax_buffer = malloc(sizeof(pax_buf_t));
if (framebuffer == NULL) {
ESP_LOGE(TAG, "Failed to allocate buffer for PAX graphics library");
esp_restart();
}
memset(pax_buffer, 0, sizeof(pax_buf_t));
pax_buf_init(pax_buffer, framebuffer, ILI9341_WIDTH, ILI9341_HEIGHT, PAX_BUF_16_565RGB);
/* Initialize hardware */
efuse_protect();
if (bsp_init() != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize basic board support functions");
esp_restart();
}
ILI9341* ili9341 = get_ili9341();
if (ili9341 == NULL) {
ESP_LOGE(TAG, "ili9341 is NULL");
esp_restart();
}
/* 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);
stop();
}
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);
stop();
}
RP2040* rp2040 = get_rp2040();
if (rp2040 == NULL) {
ESP_LOGE(TAG, "rp2040 is NULL");
stop();
}
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) {
ESP_LOGE(TAG, "Failed to get RP2040 UID");
display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "Failed to read UID", NULL, NULL);
stop();
}
printf("RP2040 UID: %02X%02X%02X%02X%02X%02X%02X%02X\n", rp2040_uid[0], rp2040_uid[1], rp2040_uid[2], rp2040_uid[3], rp2040_uid[4], rp2040_uid[5], rp2040_uid[6], rp2040_uid[7]);*/
if (bsp_ice40_init() != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize the ICE40 FPGA");
display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "ICE40 FPGA error", NULL, NULL);
stop();
}
ICE40* ice40 = get_ice40();
if (ice40 == NULL) {
ESP_LOGE(TAG, "ice40 is NULL");
stop();
}
/*display_boot_screen(pax_buffer, ili9341, "Initializing BNO055...");
if (bsp_bno055_init() != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize the BNO055 position sensor");
display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "BNO055 sensor error", "Check I2C bus", "Remove SAO and try again");
stop();
}
BNO055* bno055 = get_bno055();
if (bno055 == NULL) {
ESP_LOGE(TAG, "bno055 is NULL");
stop();
}*/
/*display_boot_screen(pax_buffer, ili9341, "Initializing BME680...");
if (bsp_bme680_init() != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize the BME680 position sensor");
display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "BME680 sensor error", "Check I2C bus", "Remove SAO and try again");
stop();
}
BME680* bme680 = get_bme680();
if (bme680 == NULL) {
ESP_LOGE(TAG, "bme680 is NULL");
stop();
}*/
//display_boot_screen(pax_buffer, ili9341, "Initializing AppFS...");
/* Start AppFS */
res = appfs_init();
if (res != ESP_OK) {
ESP_LOGE(TAG, "AppFS init failed: %d", res);
display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "AppFS failed to initialize", "Flash may be corrupted", NULL);
stop();
}
//display_boot_screen(pax_buffer, ili9341, "Initializing filesystem...");
/* Start internal filesystem */
const esp_partition_t* fs_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_FAT, "locfd");
wl_handle_t s_wl_handle = WL_INVALID_HANDLE;
if (fs_partition != NULL) {
const esp_vfs_fat_mount_config_t mount_config = {
.format_if_mount_failed = true,
.max_files = 5,
.allocation_unit_size = 0,
};
esp_err_t res = esp_vfs_fat_spiflash_mount("/internal", "locfd", &mount_config, &s_wl_handle);
if (res != ESP_OK) {
ESP_LOGE(TAG, "failed to mount locfd (%d)", res);
} else {
ESP_LOGI(TAG, "Internal filesystem mounted");
}
} else {
ESP_LOGE(TAG, "locfd partition not found");
}
/* Start SD card filesystem */
res = mount_sd(GPIO_SD_CMD, GPIO_SD_CLK, GPIO_SD_D0, GPIO_SD_PWR, "/sd", false, 5);
bool sdcard_ready = (res == ESP_OK);
if (sdcard_ready) {
ESP_LOGI(TAG, "SD card filesystem mounted");
/* 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();
/* Check WebUSB mode */
uint8_t webusb_mode;
res = rp2040_get_webusb_mode(rp2040, &webusb_mode);
if (res != ESP_OK) {
ESP_LOGE(TAG, "Failed to read WebUSB mode: %d", res);
display_fatal_error(pax_buffer, ili9341, "Failed to initialize", "Failed to read WebUSB mode", NULL, NULL);
stop();
}
ESP_LOGI(TAG, "WebUSB mode 0x%02X", webusb_mode);
if (webusb_mode == 0x00) { // Normal boot
/* Rick that roll */
play_bootsound();
/* Launcher menu */
while (true) {
menu_start(rp2040->queue, pax_buffer, ili9341, app_description->version);
}
} else if (webusb_mode == 0x01) {
display_boot_screen(pax_buffer, ili9341, "WebUSB mode");
while (true) {
webusb_main(rp2040->queue, pax_buffer, ili9341);
}
} else if (webusb_mode == 0x02) {
display_boot_screen(pax_buffer, ili9341, "FPGA download mode");
while (true) {
fpga_download(rp2040->queue, get_ice40(), pax_buffer, ili9341);
}
} else {
char buffer[64];
snprintf(buffer, sizeof(buffer), "Invalid mode 0x%02X", webusb_mode);
display_boot_screen(pax_buffer, ili9341, buffer);
}
free(framebuffer);
} }

View file

@ -1,296 +0,0 @@
#include <stdio.h>
#include <string.h>
#include "pax_gfx.h"
#include "pax_codecs.h"
#include "menu.h"
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;
size_t titleSize = strlen(aTitle) + 1;
menu->title = malloc(titleSize);
if (menu->title == NULL) {
free(menu);
return NULL;
}
memcpy(menu->title, aTitle, titleSize);
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;
}
void _menu_free_item(menu_item_t* aMenuItem) {
free(aMenuItem->label);
free(aMenuItem);
}
void menu_free(menu_t* aMenu) {
if (aMenu == NULL) return;
free(aMenu->title);
menu_item_t* currentItem = aMenu->firstItem;
while (currentItem != NULL) {
menu_item_t* nextItem = currentItem->nextItem;
_menu_free_item(currentItem);
currentItem = nextItem;
}
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;
size_t index = 0;
while (index < aPosition) {
if (currentItem->nextItem == NULL) break;
currentItem = currentItem->nextItem;
index++;
}
return currentItem;
}
menu_item_t* _menu_find_last_item(menu_t* aMenu) {
menu_item_t* lastItem = aMenu->firstItem;
if (lastItem == NULL) return NULL;
while (lastItem->nextItem != NULL) {
lastItem = lastItem->nextItem;
}
return lastItem;
}
bool menu_insert_item(menu_t* aMenu, const char* aLabel, menu_callback_t aCallback, void* aCallbackArgs, size_t aPosition) {
if (aMenu == NULL) return false;
menu_item_t* newItem = malloc(sizeof(menu_item_t));
if (newItem == NULL) return false;
size_t labelSize = strlen(aLabel) + 1;
newItem->label = malloc(labelSize);
if (newItem->label == NULL) {
free(newItem);
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;
aMenu->firstItem = newItem;
} else {
if (aPosition >= aMenu->length) {
newItem->previousItem = _menu_find_last_item(aMenu);
newItem->nextItem = NULL;
newItem->previousItem->nextItem = newItem;
} else {
newItem->nextItem = _menu_find_item(aMenu, aPosition);
newItem->previousItem = newItem->nextItem->previousItem; // Copy pointer to previous item to new item
if (newItem->nextItem != NULL) newItem->nextItem->previousItem = newItem; // Replace pointer to previous item with new item
if (newItem->previousItem != NULL) newItem->previousItem->nextItem = newItem; // Replace pointer to next item in previous item
}
}
aMenu->length++;
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
menu_item_t* item;
if (aPosition == 0) {
item = aMenu->firstItem;
if (item == NULL) return false; // Can't delete if no linked list is allocated
if (item->nextItem != NULL) {
aMenu->firstItem = item->nextItem;
aMenu->firstItem->previousItem = NULL;
} else {
aMenu->firstItem = NULL;
}
} else {
item = _menu_find_item(aMenu, aPosition);
if (item == NULL) return false;
if (item->previousItem != NULL) item->previousItem->nextItem = item->nextItem;
if (item->nextItem != NULL) item->nextItem->previousItem = item->previousItem;
}
free(item->label);
free(item);
aMenu->length--;
return true;
}
bool menu_navigate_to(menu_t* aMenu, size_t aPosition) {
if (aMenu == NULL) return false;
if (aMenu->length < 1) return false;
aMenu->position = aPosition;
if (aMenu->position >= aMenu->length) aMenu->position = aMenu->length - 1;
return true;
}
void menu_navigate_previous(menu_t* aMenu) {
if (aMenu == NULL) return;
if (aMenu->length < 1) return;
aMenu->position--;
if (aMenu->position > aMenu->length) {
aMenu->position = aMenu->length - 1;
}
}
void menu_navigate_next(menu_t* aMenu) {
if (aMenu == NULL) return;
if (aMenu->length < 1) return;
aMenu->position = (aMenu->position + 1) % aMenu->length;
}
size_t menu_get_position(menu_t* aMenu) {
return aMenu->position;
}
size_t menu_get_length(menu_t* aMenu) {
return aMenu->length;
}
void* menu_get_callback_args(menu_t* aMenu, size_t aPosition) {
menu_item_t* item = _menu_find_item(aMenu, aPosition);
if (item == NULL) return NULL;
return item->callbackArgs;
}
void menu_debug(menu_t* aMenu) {
if (aMenu == NULL) {
printf("Menu pointer is NULL\n");
return;
}
printf("Title: %s\n", aMenu->title);
printf("Length: %u\n", aMenu->length);
printf("Position: %u\n", aMenu->position);
menu_item_t* item = aMenu->firstItem;
if (item == NULL) {
printf("Menu contains no items\n");
} else {
while (item != NULL) {
printf("> %s\n", item->label);
item = item->nextItem;
}
}
printf("------\n");
}
void menu_render(pax_buf_t *aBuffer, menu_t* aMenu, float aPosX, float aPosY, float aWidth, float aHeight, pax_col_t aColor) {
const pax_font_t *font = pax_get_font("saira regular");
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;
pax_noclip(aBuffer);
if (maxItems > 1) {
float offsetX = 0;
if (aMenu->icon != NULL) {
offsetX = aMenu->icon->width;
}
maxItems--;
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;
}
size_t itemOffset = 0;
if (aMenu->position >= maxItems) {
itemOffset = aMenu->position - maxItems + 1;
}
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);
if (item == NULL) {
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, 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, 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;
}
pax_clip(aBuffer, aPosX + aWidth - 5, aPosY + entry_height, 4, aHeight - 1 - entry_height);
float fractionStart = itemOffset / (aMenu->length * 1.0);
float fractionSelected = aMenu->position / (aMenu->length * 1.0);
float fractionEnd = (itemOffset + maxItems) / (aMenu->length * 1.0);
if (fractionEnd > 1.0) fractionEnd = 1.0;
float scrollbarHeight = aHeight - entry_height;
float scrollbarStart = scrollbarHeight * fractionStart;
float scrollbarEnd = scrollbarHeight * fractionEnd;
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);
}

View file

@ -1,150 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#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 "fpga_download.h"
#include "hardware.h"
#include "file_browser.h"
#include "fpga_test.h"
#include "animation.h"
#include "button_test.h"
#include "adc_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,
ACTION_BACK,
ACTION_FPGA_DL,
ACTION_FPGA_TEST,
ACTION_FILE_BROWSER,
ACTION_FILE_BROWSER_INT,
ACTION_ANIMATION,
ACTION_BUTTON_TEST,
ACTION_ADC_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 - 18, "[A] accept [B] back");
}
void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
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);
menu_insert_item(menu, "Analog inputs", NULL, (void*) ACTION_ADC_TEST, -1);
bool render = true;
menu_dev_action_t action = ACTION_NONE;
render_dev_help(pax_buffer);
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) {
action = ACTION_BACK;
}
break;
case RP2040_INPUT_BUTTON_ACCEPT:
case RP2040_INPUT_JOYSTICK_PRESS:
case RP2040_INPUT_BUTTON_SELECT:
case RP2040_INPUT_BUTTON_START:
if (value) {
action = (menu_dev_action_t) menu_get_callback_args(menu, menu_get_position(menu));
}
break;
default:
break;
}
}
if (render) {
menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
if (action != ACTION_NONE) {
if (action == ACTION_FPGA_DL) {
fpga_download(buttonQueue, get_ice40(), pax_buffer, ili9341);
} else if (action == ACTION_FPGA_TEST) {
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_ADC_TEST) {
test_adc(buttonQueue, pax_buffer, ili9341);
} else if (action == ACTION_BACK) {
break;
}
action = ACTION_NONE;
render = true;
render_dev_help(pax_buffer);
}
}
menu_free(menu);
pax_buf_destroy(&icon_dev);
}

View file

@ -1,8 +0,0 @@
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "pax_gfx.h"
#include "ili9341.h"
void menu_dev(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,134 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#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,
ACTION_BACK
} menu_launcher_action_t;
typedef struct {
appfs_handle_t fd;
menu_launcher_action_t action;
} menu_launcher_args_t;
void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
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;
while (1) {
appfs_fd = appfsNextEntry(appfs_fd);
if (appfs_fd == APPFS_INVALID_FD) break;
const char* name = NULL;
appfsEntryInfo(appfs_fd, &name, NULL);
menu_launcher_args_t* args = malloc(sizeof(menu_launcher_args_t));
args->fd = appfs_fd;
args->action = ACTION_APPFS;
menu_insert_item(menu, name, NULL, (void*) args, -1);
}
bool render = true;
menu_launcher_args_t* menuArgs = NULL;
pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer);
pax_draw_text(pax_buffer, 0xFF000000, font, 18, 5, 240 - 18, "[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) {
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, 0xFF491d88);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
if (menuArgs != NULL) {
if (menuArgs->action == ACTION_APPFS) {
appfs_boot_app(menuArgs->fd);
}
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);
pax_buf_destroy(&icon_apps);
}

View file

@ -1,8 +0,0 @@
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "pax_gfx.h"
#include "ili9341.h"
void menu_launcher(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,144 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#include "appfs.h"
#include "ili9341.h"
#include "pax_gfx.h"
#include "pax_codecs.h"
#include "menu.h"
#include "rp2040.h"
#include "appfs_wrapper.h"
#include "hardware.h"
#include "system_wrapper.h"
#include "bootscreen.h"
#include "wifi_connect.h"
#include "wifi_ota.h"
#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,
ACTION_WIFI,
ACTION_OTA,
ACTION_RP2040_BL,
ACTION_UNINSTALL
} menu_settings_action_t;
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 - 18, "[A] accept [B] back");
}
void menu_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
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);
menu_insert_item(menu, "Uninstall app", NULL, (void*) ACTION_UNINSTALL, -1);
bool render = true;
menu_settings_action_t action = ACTION_NONE;
render_settings_help(pax_buffer);
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) {
action = ACTION_BACK;
}
break;
case RP2040_INPUT_BUTTON_ACCEPT:
case RP2040_INPUT_JOYSTICK_PRESS:
case RP2040_INPUT_BUTTON_SELECT:
case RP2040_INPUT_BUTTON_START:
if (value) {
action = (menu_settings_action_t) menu_get_callback_args(menu, menu_get_position(menu));
}
break;
default:
break;
}
}
if (render) {
menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
if (action != ACTION_NONE) {
if (action == ACTION_RP2040_BL) {
display_boot_screen(pax_buffer, ili9341, "Please wait...");
rp2040_reboot_to_bootloader(get_rp2040());
esp_restart();
} else if (action == ACTION_OTA) {
display_boot_screen(pax_buffer, ili9341, "Connecting to WiFi...");
if (wifi_connect_to_stored()) {
display_boot_screen(pax_buffer, ili9341, "Starting firmware update...");
ota_update(pax_buffer, ili9341);
} else {
display_boot_screen(pax_buffer, ili9341, "Failed to connect to WiFi");
vTaskDelay(500 / portTICK_PERIOD_MS);
}
} 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;
}
render = true;
action = ACTION_NONE;
render_settings_help(pax_buffer);
}
}
menu_free(menu);
pax_buf_destroy(&icon_settings);
}

View file

@ -1,8 +0,0 @@
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "pax_gfx.h"
#include "ili9341.h"
void menu_settings(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,186 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#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"
#include "hardware.h"
#include "math.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, const char* text) {
const pax_font_t *font = pax_get_font("saira regular");
pax_background(pax_buffer, 0xFFFFFF);
pax_noclip(pax_buffer);
pax_draw_text(pax_buffer, 0xFF491d88, font, 18, 5, 240 - 18, "[A] accept");
pax_vec1_t version_size = pax_text_size(font, 18, text);
pax_draw_text(pax_buffer, 0xFF491d88, font, 18, 320 - 5 - version_size.x, 240 - 18, text);
}
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;
uint8_t analogReadTimer = 0;
float battery_voltage = 0;
float usb_voltage = 0;
//uint8_t rp2040_usb = 0;
// Calculated:
uint8_t battery_percent = 0;
bool battery_charging = false;
RP2040* rp2040 = get_rp2040();
while (1) {
rp2040_input_message_t buttonMessage = {0};
if (xQueueReceive(buttonQueue, &buttonMessage, 100 / 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:
case RP2040_INPUT_BUTTON_SELECT:
case RP2040_INPUT_BUTTON_START:
if (value) {
action = (menu_start_action_t) menu_get_callback_args(menu, menu_get_position(menu));
}
break;
default:
break;
}
}
if (analogReadTimer > 0) {
analogReadTimer--;
} else {
analogReadTimer = 10; // No need to update these values really quickly
if (rp2040_read_vbat(rp2040, &battery_voltage) != ESP_OK) {
battery_voltage = 0;
}
if (rp2040_read_vusb(rp2040, &usb_voltage) != ESP_OK) {
usb_voltage = 0;
}
if (battery_voltage >= 3.6) {
battery_percent = ((battery_voltage - 3.6) * 100) / (4.2 - 3.6);
if (battery_percent > 100) battery_percent = 100;
} else {
battery_percent = 0;
}
battery_charging = (usb_voltage > 4.0) && (battery_percent < 100);
render = true;
}
if (render) {
char textBuffer[64];
snprintf(textBuffer, sizeof(textBuffer), "B%1.1fv U%1.1fv %03u%%%c v%s", battery_voltage, usb_voltage, battery_percent, battery_charging ? '+' : ' ', version);
render_start_help(pax_buffer, textBuffer);
menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
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) {
menu_dev(buttonQueue, pax_buffer, ili9341);
}
action = ACTION_NONE;
render = true;
}
}
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);
}

View file

@ -1,8 +0,0 @@
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "pax_gfx.h"
#include "ili9341.h"
void menu_start(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, const char* version);

View file

@ -1,535 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <nvs.h>
#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 "wifi_connect.h"
#include "wifi_connection.h"
#include "wifi_ota.h"
#include "graphics_wrapper.h"
static const char *TAG = "wifi menu";
typedef enum action {
/* ==== GENERIC ACTIONS ==== */
// Nothing happens.
ACTION_NONE,
// Go back to the parent menu.
ACTION_BACK,
/* ==== MAIN MENU ACTIONS ==== */
// Show the current WiFi settings.
ACTION_SHOW,
// Scan for networks and pick one to connect to.
ACTION_SCAN,
// Manually edit the current WiFi settings.
ACTION_MANUAL,
/* ==== AUTH MODES ==== */
ACTION_AUTH_OPEN,
ACTION_AUTH_WEP,
ACTION_AUTH_WPA_PSK,
ACTION_AUTH_WPA2_PSK,
ACTION_AUTH_WPA_WPA2_PSK,
ACTION_AUTH_WPA2_ENTERPRISE,
ACTION_AUTH_WPA3_PSK,
ACTION_AUTH_WPA2_WPA3_PSK,
ACTION_AUTH_WAPI_PSK,
/* ==== PHASE2 AUTH MODES ==== */
ACTION_PHASE2_EAP,
ACTION_PHASE2_MSCHAPV2,
ACTION_PHASE2_MSCHAP,
ACTION_PHASE2_PAP,
ACTION_PHASE2_CHAP,
} menu_wifi_action_t;
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 - 18, "[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);
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);
int wifi_auth_menu(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, wifi_auth_mode_t default_mode);
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", 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);
bool render = true;
menu_wifi_action_t action = ACTION_NONE;
render_wifi_help(pax_buffer);
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) {
action = ACTION_BACK;
}
break;
case RP2040_INPUT_BUTTON_ACCEPT:
case RP2040_INPUT_JOYSTICK_PRESS:
case RP2040_INPUT_BUTTON_SELECT:
case RP2040_INPUT_BUTTON_START:
if (value) {
action = (menu_wifi_action_t) menu_get_callback_args(menu, menu_get_position(menu));
}
break;
default:
break;
}
}
if (render) {
menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF491d88);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
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;
}
render = true;
action = ACTION_NONE;
render_wifi_help(pax_buffer);
}
}
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] = "<not set>";
char password[33] = "<not set>";
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), "WiFi SSID:\n%s\nWiFi password:\n%s", ssid, password);
pax_draw_text(pax_buffer, 0xFF000000, NULL, 18, 0, 0, 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;
}
}
}
}
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", 20, 18);
wifi_ap_record_t *picked = NULL;
render_wifi_help(pax_buffer);
for (size_t i = 0; i < num_aps; i++) {
menu_insert_item(menu, (const char*) aps[i].ssid, NULL, (void *) (i + 1), -1);
}
bool render = true;
size_t selection = 0;
while (1) {
rp2040_input_message_t buttonMessage = {0};
selection = -1;
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) {
selection = 0;
}
break;
case RP2040_INPUT_BUTTON_ACCEPT:
case RP2040_INPUT_JOYSTICK_PRESS:
case RP2040_INPUT_BUTTON_SELECT:
case RP2040_INPUT_BUTTON_START:
if (value) {
selection = (size_t) menu_get_callback_args(menu, menu_get_position(menu));
}
break;
default:
break;
}
}
if (render) {
menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF2f55a8);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
if (selection != (size_t) -1) {
if (selection == 0) {
break;
} else {
// You picked one, yay!
picked = &aps[selection-1];
break;
}
render = true;
selection = -1;
render_wifi_help(pax_buffer);
}
}
menu_free(menu);
return picked;
}
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", 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);
menu_insert_item(menu, "WPA2 PSK", NULL, (void*) ACTION_AUTH_WPA2_PSK, -1);
// menu_insert_item(menu, "QQQQQQQQQQQQ", NULL, (void*) ACTION_AUTH_WPA_WPA2_PSK, -1);
menu_insert_item(menu, "WPA2 Enterprise", NULL, (void*) ACTION_AUTH_WPA2_ENTERPRISE, -1);
menu_insert_item(menu, "WPA3 PSK", NULL, (void*) ACTION_AUTH_WPA3_PSK, -1);
// menu_insert_item(menu, "QQQQQQQQQQQQ", NULL, (void*) ACTION_AUTH_WPA2_WPA3_PSK, -1);
// menu_insert_item(menu, "WAPI PSK", NULL, (void*) ACTION_AUTH_WAPI_PSK, -1);
bool render = true;
menu_wifi_action_t action = ACTION_NONE;
wifi_auth_mode_t pick = default_mode;
render_wifi_help(pax_buffer);
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) {
action = ACTION_BACK;
}
break;
case RP2040_INPUT_BUTTON_ACCEPT:
case RP2040_INPUT_JOYSTICK_PRESS:
case RP2040_INPUT_BUTTON_SELECT:
case RP2040_INPUT_BUTTON_START:
if (value) {
action = (menu_wifi_action_t) menu_get_callback_args(menu, menu_get_position(menu));
}
break;
default:
break;
}
}
if (render) {
menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF2f55a8);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
if (action != ACTION_NONE) {
if (action == ACTION_BACK) {
break;
} else {
pick = (wifi_auth_mode_t) (action - ACTION_AUTH_OPEN);
break;
}
render = true;
action = ACTION_NONE;
render_wifi_help(pax_buffer);
}
}
menu_free(menu);
return pick;
}
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", 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);
menu_insert_item(menu, "PAP", NULL, (void*) ACTION_PHASE2_PAP, -1);
menu_insert_item(menu, "CHAP", NULL, (void*) ACTION_PHASE2_CHAP, -1);
bool render = true;
menu_wifi_action_t action = ACTION_NONE;
esp_eap_ttls_phase2_types pick = default_mode;
render_wifi_help(pax_buffer);
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) {
action = ACTION_BACK;
}
break;
case RP2040_INPUT_BUTTON_ACCEPT:
case RP2040_INPUT_JOYSTICK_PRESS:
case RP2040_INPUT_BUTTON_SELECT:
case RP2040_INPUT_BUTTON_START:
if (value) {
action = (menu_wifi_action_t) menu_get_callback_args(menu, menu_get_position(menu));
}
break;
default:
break;
}
}
if (render) {
menu_render(pax_buffer, menu, 0, 0, 320, 220, 0xFF2f55a8);
ili9341_write(ili9341, pax_buffer->buf);
render = false;
}
if (action != ACTION_NONE) {
if (action == ACTION_BACK) {
break;
} else {
pick = (wifi_auth_mode_t) (action - ACTION_PHASE2_EAP);
break;
}
render = true;
action = ACTION_NONE;
render_wifi_help(pax_buffer);
}
}
menu_free(menu);
return pick;
}
// Sorts WiFi APs by RSSI (best RSSI first in the list).
static int wifi_ap_sorter(const void *a0, const void *b0) {
const wifi_ap_record_t *a = a0;
const wifi_ap_record_t *b = b0;
return b->rssi - a->rssi;
}
void wifi_setup(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341, bool scan) {
char ssid[33] = {0};
char username[33] = {0};
char password[33] = {0};
nvs_handle_t handle;
nvs_open("system", NVS_READWRITE, &handle);
bool accepted = true;
wifi_auth_mode_t authmode = WIFI_AUTH_WPA2_PSK;
esp_eap_ttls_phase2_types phase2 = ESP_EAP_TTLS_PHASE2_EAP;
/* ==== scanning phase ==== */
if (scan) {
// Show a little bit of text.
display_boot_screen(pax_buffer, ili9341, "Scanning WiFi networks...");
// Scan for networks.
wifi_ap_record_t *aps;
size_t n_aps = wifi_scan(&aps);
// Sort them by RSSI.
qsort(aps, n_aps, sizeof(wifi_ap_record_t), wifi_ap_sorter);
// Make a de-duplicated list.
wifi_ap_record_t *dedup = malloc(sizeof(wifi_ap_record_t) * n_aps);
size_t n_dedup = 0;
for (size_t i = 0; i < n_aps; ) {
for (size_t x = 0; x < n_dedup; x++) {
if (!strcmp((const char *) aps[i].ssid, (const char *) dedup[x].ssid)) goto cont;
}
dedup[n_dedup] = aps[i];
n_dedup ++;
cont:
i++;
}
// Open a little menu for picking a network.
wifi_ap_record_t *pick = wifi_scan_results(buttonQueue, pax_buffer, ili9341, n_dedup, dedup);
if (!pick) {
nvs_close(handle);
return;
}
// Copy the SSID in.
memcpy(ssid, pick->ssid, 33);
authmode = pick->authmode;
// Free memories.
free(aps);
free(dedup);
} else {
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, "");
}
}
// Select SSID.
accepted = keyboard(buttonQueue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi SSID", "Press HOME to cancel", ssid, sizeof(ssid));
// Select auth mode.
if (accepted) {
authmode = wifi_auth_menu(buttonQueue, pax_buffer, ili9341, -1);
accepted = authmode != -1;
}
}
/* ==== manual entering phase ==== */
if (authmode == WIFI_AUTH_WPA2_ENTERPRISE) {
if (accepted) {
// Phase2 method.
phase2 = wifi_phase2_menu(buttonQueue, pax_buffer, ili9341, -1);
accepted = phase2 != -1;
}
if (accepted) {
// Username.
accepted = keyboard(buttonQueue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi username", "Press HOME to cancel", username, sizeof(username));
}
}
if (accepted) {
// Password.
accepted = keyboard(buttonQueue, pax_buffer, ili9341, 30, 30, pax_buffer->width - 60, pax_buffer->height - 60, "WiFi password", "Press HOME to cancel", password, sizeof(password));
}
if (accepted) {
nvs_set_str(handle, "wifi.ssid", ssid);
nvs_set_str(handle, "wifi.password", password);
nvs_set_u8 (handle, "wifi.authmode", authmode);
if (authmode == WIFI_AUTH_WPA2_ENTERPRISE) {
nvs_set_str(handle, "wifi.username", username);
nvs_set_u8 (handle, "wifi.phase2", phase2);
}
display_boot_screen(pax_buffer, ili9341, "WiFi settings stored");
}
nvs_close(handle);
}

View file

@ -1,8 +0,0 @@
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include "pax_gfx.h"
#include "ili9341.h"
void menu_wifi(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341);

View file

@ -1,219 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#include "driver/uart.h"
#include "hardware.h"
#include "managed_i2c.h"
#include "pax_gfx.h"
#include "rp2040.h"
#include "rp2040bl.h"
#include "system_wrapper.h"
#include "graphics_wrapper.h"
#include "esp32/rom/crc.h"
extern const uint8_t rp2040_firmware_bin_start[] asm("_binary_rp2040_firmware_bin_start");
extern const uint8_t rp2040_firmware_bin_end[] asm("_binary_rp2040_firmware_bin_end");
void display_rp2040_update_state(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* text) {
pax_noclip(pax_buffer);
const pax_font_t* font = pax_get_font("sky mono");
pax_background(pax_buffer, 0xFFFFFF);
pax_vec1_t title_size = pax_text_size(font, 18, "Co-processor update");
pax_draw_text(pax_buffer, 0xFF000000, font, 18, (320 / 2) - (title_size.x / 2), 120 - 30, "Co-processor update");
pax_vec1_t size = pax_text_size(font, 18, text);
pax_draw_text(pax_buffer, 0xFF000000, font, 18, (320 / 2) - (size.x / 2), 120 + 10, text);
ili9341_write(ili9341, pax_buffer->buf);
}
void rp2040_updater(RP2040* rp2040, pax_buf_t* pax_buffer, ILI9341* ili9341) {
size_t firmware_size = rp2040_firmware_bin_end - rp2040_firmware_bin_start;
char message[64];
uint8_t fw_version;
if (rp2040_get_firmware_version(rp2040, &fw_version) != ESP_OK) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
snprintf(message, sizeof(message) - 1, "RP2040 error");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message);
snprintf(message, sizeof(message) - 1, "Failed to read firmware version");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 13, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
restart();
}
if (fw_version < 0x03) { // Update required
display_rp2040_update_state(pax_buffer, ili9341, "Starting bootloader...");
rp2040_reboot_to_bootloader(rp2040);
esp_restart();
}
if (fw_version == 0xFF) { // RP2040 is in bootloader mode
display_rp2040_update_state(pax_buffer, ili9341, "Starting update...");
uint8_t bl_version;
if (rp2040_get_bootloader_version(rp2040, &bl_version) != ESP_OK) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
snprintf(message, sizeof(message) - 1, "RP2040 update failed");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message);
snprintf(message, sizeof(message) - 1, "Communication error (1)");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 13, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
restart();
}
if (bl_version != 0x01) {
pax_background(pax_buffer, 0xa85a32);
snprintf(message, sizeof(message) - 1, "RP2040 update failed");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message);
snprintf(message, sizeof(message) - 1, "Unsupported bootloader version");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 13, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
restart();
}
rp2040_bl_install_uart();
display_rp2040_update_state(pax_buffer, ili9341, "Preparing...");
while (true) {
vTaskDelay(1 / portTICK_PERIOD_MS);
uint8_t bl_state;
if (rp2040_get_bootloader_state(rp2040, &bl_state) != ESP_OK) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
snprintf(message, sizeof(message) - 1, "RP2040 update failed");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message);
snprintf(message, sizeof(message) - 1, "Communication error (2)");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 13, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
restart();
}
if (bl_state == 0xB0) {
break;
}
if (bl_state > 0xB0) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
snprintf(message, sizeof(message) - 1, "RP2040 update failed");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message);
snprintf(message, sizeof(message) - 1, "Unknown bootloader state");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 13, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
restart();
}
}
display_rp2040_update_state(pax_buffer, ili9341, "Synchronizing...");
while (true) {
if (rp2040_bl_sync()) break;
vTaskDelay(100 / portTICK_PERIOD_MS);
}
uint32_t flash_start = 0, flash_size = 0, erase_size = 0, write_size = 0, max_data_len = 0;
bool success = rp2040_bl_get_info(&flash_start, &flash_size, &erase_size, &write_size, &max_data_len);
if (!success) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
snprintf(message, sizeof(message) - 1, "RP2040 update failed");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message);
snprintf(message, sizeof(message) - 1, "Failed to read information");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 13, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
restart();
}
display_rp2040_update_state(pax_buffer, ili9341, "Erasing...");
uint32_t erase_length = firmware_size;
erase_length = erase_length + erase_size - (erase_length % erase_size); // Round up to erase size
if (erase_length > flash_size - erase_size) {
erase_length = flash_size - erase_size;
}
bool eraseSuccess = rp2040_bl_erase(flash_start, flash_size - erase_size);//erase_length); < erase whole flash as workaround for a yet to be fixed bug in the calculation of erase_length
if (!eraseSuccess) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xa85a32);
snprintf(message, sizeof(message) - 1, "RP2040 update failed");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, message);
snprintf(message, sizeof(message) - 1, "Failed to erase flash");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 13, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
vTaskDelay(1000 / portTICK_PERIOD_MS);
restart();
}
uint32_t position = 0;
uint32_t txSize = write_size;
uint8_t* txBuffer = malloc(write_size);
uint32_t blockCrc = 0;
uint32_t totalCrc = 0;
uint32_t totalLength = 0;
while (true) {
if ((firmware_size - position) < txSize) {
txSize = firmware_size - position;
}
if (txSize == 0) break;
uint8_t percentage = position * 100 / firmware_size;
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0x325aa8);
snprintf(message, sizeof(message) - 1, "Writing... %u%%", percentage);
display_rp2040_update_state(pax_buffer, ili9341, message);
uint32_t checkCrc = 0;
memset(txBuffer, 0, write_size);
memcpy(txBuffer, &rp2040_firmware_bin_start[position], txSize);
blockCrc = crc32_le(0, txBuffer, write_size);
totalCrc = crc32_le(totalCrc, txBuffer, write_size);
totalLength += write_size;
bool writeSuccess = rp2040_bl_write(0x10010000 + position, write_size, txBuffer, &checkCrc);
if (writeSuccess && (blockCrc == checkCrc)) {
position += txSize;
} else {
display_rp2040_update_state(pax_buffer, ili9341, "CRC mismatch");
while (!rp2040_bl_sync()) {
vTaskDelay(20 / portTICK_PERIOD_MS);
}
}
}
free(txBuffer);
display_rp2040_update_state(pax_buffer, ili9341, "Finalizing...");
bool sealRes = rp2040_bl_seal(0x10010000, 0x10010000, totalLength, totalCrc);
if (sealRes) {
vTaskDelay(2000 / portTICK_PERIOD_MS);
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0xCCCCCC);
memset(message, 0, sizeof(message));
display_rp2040_update_state(pax_buffer, ili9341, "Update completed");
rp2040_bl_go(0x10010000);
} else {
display_rp2040_update_state(pax_buffer, ili9341, "Update failed");
vTaskDelay(1000 / portTICK_PERIOD_MS);
restart();
}
while (true) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
}

View file

@ -1,84 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <nvs_flash.h>
#include <nvs.h>
#include "ili9341.h"
#include "ice40.h"
#include "hardware.h"
static const char *TAG = "settings";
esp_err_t nvs_init() {
const esp_partition_t * nvs_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_DATA_NVS, NULL);
if (nvs_partition == NULL) return ESP_FAIL;
esp_err_t res = nvs_flash_init();
if (res != ESP_OK) {
res = esp_partition_erase_range(nvs_partition, 0, nvs_partition->size);
if (res != ESP_OK) return res;
res = nvs_flash_init();
if (res != ESP_OK) return res;
}
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;
}

View file

@ -1,18 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <esp_system.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include "system_wrapper.h"
void restart() {
/*for (int i = 3; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
printf("Restarting now.\n");*/
vTaskDelay(1000 / portTICK_PERIOD_MS);
fflush(stdout);
esp_restart();
}

View file

@ -1,65 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <esp_log.h>
#include <freertos/FreeRTOS.h>
#include <freertos/queue.h>
#include <driver/gpio.h>
#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;
}

View file

@ -1,120 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#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", 20, 18);
const pax_font_t *font = pax_get_font("saira regular");
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, font, 18, 5, 240 - 18, "[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);
}

View file

@ -1,117 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#include "driver/uart.h"
#include "hardware.h"
#include "managed_i2c.h"
#include "pax_gfx.h"
#include "ice40.h"
#include "system_wrapper.h"
#include "graphics_wrapper.h"
#include "esp32/rom/crc.h"
void webusb_install_uart() {
fflush(stdout);
ESP_ERROR_CHECK(uart_driver_install(0, 2048, 0, 0, NULL, 0));
uart_config_t uart_config = {
.baud_rate = 921600,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_APB,
};
ESP_ERROR_CHECK(uart_param_config(0, &uart_config));
}
void webusb_uninstall_uart() {
uart_driver_delete(0);
}
bool webusb_read_stdin(uint8_t* buffer, uint32_t len, uint32_t timeout) {
int read = uart_read_bytes(0, buffer, len, timeout / portTICK_PERIOD_MS);
return (read == len);
}
bool webusb_uart_sync(uint32_t* length, uint32_t* crc) {
uint8_t rx_buffer[4*3];
webusb_read_stdin(rx_buffer, sizeof(rx_buffer), 100);
if (memcmp(rx_buffer, "WUSB", 4) != 0) return false;
memcpy((uint8_t*) length, &rx_buffer[4 * 1], 4);
memcpy((uint8_t*) crc, &rx_buffer[4 * 2], 4);
return true;
}
bool webusb_uart_load(uint8_t* buffer, uint32_t length) {
return webusb_read_stdin(buffer, length, 3000);
}
void webusb_uart_mess(const char *mess) {
uart_write_bytes(0, mess, strlen(mess));
}
void webusb_print_status(pax_buf_t* pax_buffer, ILI9341* ili9341, char* message) {
pax_noclip(pax_buffer);
pax_background(pax_buffer, 0x325aa8);
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*0, "WebUSB mode");
pax_draw_text(pax_buffer, 0xFFFFFFFF, NULL, 18, 0, 20*1, message);
ili9341_write(ili9341, pax_buffer->buf);
}
void webusb_main(xQueueHandle buttonQueue, pax_buf_t* pax_buffer, ILI9341* ili9341) {
webusb_install_uart();
while (true) {
webusb_print_status(pax_buffer, ili9341, "Waiting...");
// 1) Wait for WUSB followed by data length as uint32 and CRC32 of the data as uint32
uint32_t length, crc;
while (!webusb_uart_sync(&length, &crc)) {
webusb_uart_mess("WUSB");
}
webusb_print_status(pax_buffer, ili9341, "Receiving...");
// 2) Allocate RAM for the data to be received
uint8_t* buffer = malloc(length);
if (buffer == NULL) {
webusb_uart_mess("EMEM");
webusb_print_status(pax_buffer, ili9341, "Error: malloc failed");
vTaskDelay(100 / portTICK_PERIOD_MS);
continue;
}
// 3) Receive data into the buffer
if (!webusb_uart_load(buffer, length)) {
free(buffer);
webusb_uart_mess("ERCV");
webusb_print_status(pax_buffer, ili9341, "Error: receive failed");
vTaskDelay(100 / portTICK_PERIOD_MS);
continue;
}
// 4) Check CRC
uint32_t checkCrc = crc32_le(0, buffer, length);
if (checkCrc != crc) {
free(buffer);
webusb_uart_mess("ECRC");
webusb_print_status(pax_buffer, ili9341, "Error: CRC invalid");
vTaskDelay(100 / portTICK_PERIOD_MS);
continue;
}
webusb_uart_mess("OKOK");
webusb_print_status(pax_buffer, ili9341, "Packet received");
// To-do: parse packet
}
webusb_uninstall_uart();
}

View file

@ -1,104 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sdkconfig.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <freertos/queue.h>
#include <esp_system.h>
#include <esp_err.h>
#include <esp_log.h>
#include <nvs_flash.h>
#include <nvs.h>
#include "pax_gfx.h"
#include "system_wrapper.h"
#include "settings.h"
#include "wifi_connection.h"
static const char *TAG = "wifi_connect";
bool wifi_connect_to_stored() {
bool result = false;
// Open NVS.
nvs_handle_t handle;
nvs_open("system", NVS_READWRITE, &handle);
wifi_auth_mode_t authmode = 0;
esp_eap_ttls_phase2_types phase2 = 0;
char *ssid = NULL;
char *ident = NULL;
char *anon_ident = NULL;
char *password = NULL;
size_t len;
// Read NVS.
esp_err_t res;
// Read SSID.
res = nvs_get_str(handle, "wifi.ssid", NULL, &len);
if (res) goto errcheck;
ssid = malloc(len);
res = nvs_get_str(handle, "wifi.ssid", ssid, &len);
if (res) goto errcheck;
// Check whether connection is enterprise.
res = nvs_get_u8(handle, "wifi.authmode", &authmode);
bool use_ent = authmode == WIFI_AUTH_WPA2_ENTERPRISE;
if (res) goto errcheck;
if (use_ent) {
// Read enterprise-specific parameters.
// Read phase2 mode.
res = nvs_get_u8(handle, "wifi.phase2", &phase2);
if (res) goto errcheck;
// Read identity.
res = nvs_get_str(handle, "wifi.username", NULL, &len);
if (res) goto errcheck;
ident = malloc(len);
res = nvs_get_str(handle, "wifi.username", ident, &len);
// Read anonymous identity.
res = nvs_get_str(handle, "wifi.anon_ident", NULL, &len);
if (res == ESP_ERR_NVS_NOT_FOUND) {
// Default is use the same thing.
anon_ident = strdup(ident);
} else {
if (res) goto errcheck;
anon_ident = malloc(len);
res = nvs_get_str(handle, "wifi.anon_ident", anon_ident, &len);
if (res) goto errcheck;
}
}
// Read password.
res = nvs_get_str(handle, "wifi.password", NULL, &len);
if (res) goto errcheck;
password = malloc(len);
res = nvs_get_str(handle, "wifi.password", password, &len);
if (res) goto errcheck;
// Close NVS.
nvs_close(handle);
// Open the appropriate connection.
if (use_ent) {
result = wifi_connect_ent(ssid, ident, anon_ident, password, phase2, 3);
} else {
result = wifi_connect(ssid, password, authmode, 3);
}
errcheck:
if (res == ESP_ERR_NVS_NOT_FOUND || res == ESP_ERR_NVS_NOT_INITIALIZED) {
// When NVS is not initialised.
ESP_LOGI(TAG, "WiFi settings not stored in NVS.");
} else if (res) {
// Other errors.
ESP_LOGE(TAG, "Error connecting to WiFi: %s", esp_err_to_name(res));
}
// Free memory.
if (ssid) free(ssid);
if (ident) free(ident);
if (anon_ident) free(anon_ident);
if (password) free(password);
return result;
}

View file

@ -1,272 +0,0 @@
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "lwip/err.h"
#include "lwip/sys.h"
#include "wifi_connection.h"
static const char *TAG = "wifi_connection";
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
#define WIFI_STARTED_BIT BIT2
static EventGroupHandle_t wifiEventGroup;
static uint8_t retryCount = 0;
static uint8_t maxRetries = 3;
static bool isScanning = false;
static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
xEventGroupSetBits(wifiEventGroup, WIFI_STARTED_BIT);
if (!isScanning) {
// Connect only if we're not scanning the WiFi.
esp_wifi_connect();
}
ESP_LOGI(TAG, "WiFi station start.");
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_STOP) {
xEventGroupClearBits(wifiEventGroup, WIFI_STARTED_BIT);
ESP_LOGI(TAG, "WiFi station stop.");
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (retryCount < 3) {
esp_wifi_connect();
retryCount++;
ESP_LOGI(TAG, "Retrying connection");
} else {
ESP_LOGI(TAG, "Connection failed");
xEventGroupSetBits(wifiEventGroup, WIFI_FAIL_BIT);
}
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "Got ip:" IPSTR, IP2STR(&event->ip_info.ip));
retryCount = 0;
xEventGroupSetBits(wifiEventGroup, WIFI_CONNECTED_BIT);
}
}
void wifi_init() {
// Create an event group for WiFi things.
wifiEventGroup = xEventGroupCreate();
// Initialise WiFi stack.
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
// Register event handlers for WiFi.
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL, &instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL, &instance_got_ip));
// Turn off WiFi hardware.
ESP_ERROR_CHECK(esp_wifi_stop());
}
bool wifi_connect(const char* aSsid, const char* aPassword, wifi_auth_mode_t aAuthmode, uint8_t aRetryMax) {
// Set the retry counts.
retryCount = 0;
maxRetries = aRetryMax;
// Create a config.
wifi_config_t wifi_config = {0};
strcpy((char*) wifi_config.sta.ssid, aSsid);
strcpy((char*) wifi_config.sta.password, aPassword);
wifi_config.sta.threshold.authmode = aAuthmode;
// Set WiFi config.
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
// Disable 11b as NOC asked.
esp_wifi_config_11b_rate(WIFI_IF_STA, true);
// Start WiFi.
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "Connecting to WiFi...");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(wifiEventGroup, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "Connected to WiFi");
return true;
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGE(TAG, "Failed to connect");
ESP_ERROR_CHECK(esp_wifi_stop());
} else {
ESP_LOGE(TAG, "Unknown event received while waiting on connection");
ESP_ERROR_CHECK(esp_wifi_stop());
}
return false;
}
bool wifi_connect_ent(const char* aSsid, const char *aIdent, const char *aAnonIdent, const char* aPassword, esp_eap_ttls_phase2_types phase2, uint8_t aRetryMax) {
retryCount = 0;
maxRetries = aRetryMax;
wifi_config_t wifi_config = {0};
if (strlen(aSsid) > 32) {
ESP_LOGE(TAG, "SSID is too long (%zu > 32)!", strlen(aSsid));
return false;
}
strncpy((char*) wifi_config.sta.ssid, aSsid, 32);
// Set WiFi config.
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
// Set WPA2 ENT config.
esp_wifi_sta_wpa2_ent_set_identity((const uint8_t *) aAnonIdent, strlen(aAnonIdent));
esp_wifi_sta_wpa2_ent_set_username((const uint8_t *) aIdent, strlen(aIdent));
esp_wifi_sta_wpa2_ent_set_password((const uint8_t *) aPassword, strlen(aPassword));
esp_wifi_sta_wpa2_ent_set_ttls_phase2_method(phase2);
// Enable enterprise auth.
esp_wifi_sta_wpa2_ent_enable();
// Disable 11b as NOC asked.
esp_wifi_config_11b_rate(WIFI_IF_STA, true);
// Start the connection.
esp_wifi_start();
ESP_LOGI(TAG, "Connecting to '%s' as '%s'/'%s': %s", aSsid, aIdent, aAnonIdent, aPassword);
ESP_LOGI(TAG, "Phase2 mode: %d", phase2);
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(wifiEventGroup, WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, pdFALSE, pdFALSE, portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "Connected to WiFi");
return true;
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGE(TAG, "Failed to connect");
ESP_ERROR_CHECK(esp_wifi_stop());
} else {
ESP_LOGE(TAG, "Unknown event received while waiting on connection");
ESP_ERROR_CHECK(esp_wifi_stop());
}
return false;
}
// Shows a nice info message describing an AP record.
static inline void wifi_desc_record(wifi_ap_record_t *record) {
// Make a string representation of BSSID.
char *bssid_str = malloc(3*6);
if (!bssid_str) return;
snprintf(bssid_str, 3*6, "%02X:%02X:%02X:%02X:%02X:%02X",
record->bssid[0], record->bssid[1], record->bssid[2],
record->bssid[3], record->bssid[4], record->bssid[5]
);
// Make a string representation of 11b/g/n modes.
char *phy_str = malloc(9);
if (!phy_str) {
free(bssid_str);
return;
}
*phy_str = 0;
if (record->phy_11b | record->phy_11g | record->phy_11n) {
strcpy(phy_str, " 1");
}
if (record->phy_11b) {
strcat(phy_str, "/b");
}
if (record->phy_11g) {
strcat(phy_str, "/g");
}
if (record->phy_11n) {
strcat(phy_str, "/n");
}
phy_str[2] = '1';
ESP_LOGI(TAG, "AP %s %s rssi=%hhd%s", bssid_str, record->ssid, record->rssi, phy_str);
free(bssid_str);
free(phy_str);
}
// Scan for WiFi access points.
size_t wifi_scan(wifi_ap_record_t **aps_out) {
isScanning = true;
// Scan for any non-hidden APs on all channels.
wifi_scan_config_t cfg = {
.ssid = NULL,
.bssid = NULL,
.channel = 0,
.scan_type = WIFI_SCAN_TYPE_ACTIVE,
.scan_time = { .active={ 0, 0 } },
};
// Start the scan now.
ESP_LOGI(TAG, "Starting scan...");
esp_err_t res = esp_wifi_scan_start(&cfg, true);
// Whether to call esp_wifi_stop() on finish.
bool stopWhenDone = false;
if (res == ESP_ERR_WIFI_NOT_STARTED) {
// If it complains that the wifi wasn't started, then do so.
ESP_LOGI(TAG, "Starting WiFi for scan");
// Set to station but don't connect.
res = esp_wifi_set_mode(WIFI_MODE_STA);
if (res) goto ohno;
// Start WiFi.
res = esp_wifi_start();
if (res) goto ohno;
stopWhenDone = true;
// Await the STA started bit.
xEventGroupWaitBits(wifiEventGroup, WIFI_STARTED_BIT, pdFALSE, pdFALSE, pdMS_TO_TICKS(2000));
// Try again.
res = esp_wifi_scan_start(&cfg, true);
}
if (res) {
ohno:
ESP_LOGE(TAG, "Error in WiFi scan: %s", esp_err_to_name(res));
isScanning = false;
return 0;
}
// Allocate memory for AP list.
uint16_t num_ap = 0;
esp_wifi_scan_get_ap_num(&num_ap);
wifi_ap_record_t *aps = malloc(sizeof(wifi_ap_record_t) * num_ap);
// Collect APs and report findings.
esp_wifi_scan_get_ap_records(&num_ap, aps);
for (uint16_t i = 0; i < num_ap; i++) {
wifi_desc_record(&aps[i]);
}
// Clean up.
if (aps_out) {
// Output pointer is non-null, return the APs list.
*aps_out = aps;
} else {
// Output pointer is null, free the APs list.
free(aps);
}
if (stopWhenDone) {
// Stop WiFi because it was started only for this scan.
esp_wifi_stop();
}
isScanning = false;
return num_ap;
}
// Get the strength value for a given RSSI.
wifi_strength_t wifi_rssi_to_strength(int8_t rssi) {
if (rssi > WIFI_THRESH_VERY_GOOD) return WIFI_STRENGTH_VERY_GOOD;
else if (rssi > WIFI_THRESH_GOOD) return WIFI_STRENGTH_GOOD;
else if (rssi > WIFI_THRESH_BAD) return WIFI_STRENGTH_BAD;
else return WIFI_STRENGTH_VERY_BAD;
}

View file

@ -1,227 +0,0 @@
#include "wifi_ota.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "string.h"
#include "esp_crt_bundle.h"
#include "nvs.h"
#include "nvs_flash.h"
#include <sys/socket.h>
#include "esp_wifi.h"
#include "bootscreen.h"
#define HASH_LEN 32
static const char *TAG = "OTA update";
extern const uint8_t server_cert_pem_start[] asm("_binary_isrgrootx1_pem_start");
extern const uint8_t server_cert_pem_end[] asm("_binary_isrgrootx1_pem_end");
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
switch (evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADERS_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADERS_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
break;
}
return ESP_OK;
}
static esp_err_t validate_image_header(esp_app_desc_t *new_app_info) {
if (new_app_info == NULL) {
return ESP_ERR_INVALID_ARG;
}
const esp_partition_t *running = esp_ota_get_running_partition();
esp_app_desc_t running_app_info;
if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
}
/*
if (memcmp(new_app_info->version, running_app_info.version, sizeof(new_app_info->version)) == 0) {
ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
return ESP_FAIL;
}
*/
return ESP_OK;
}
static esp_err_t _http_client_init_cb(esp_http_client_handle_t http_client) {
esp_err_t err = ESP_OK;
/* Uncomment to add custom headers to HTTP request */
// err = esp_http_client_set_header(http_client, "Custom-Header", "Value");
return err;
}
static void print_sha256(const uint8_t *image_hash, const char *label) {
char hash_print[HASH_LEN * 2 + 1];
hash_print[HASH_LEN * 2] = 0;
for (int i = 0; i < HASH_LEN; ++i) {
sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
}
ESP_LOGI(TAG, "%s %s", label, hash_print);
}
static void get_sha256_of_partitions(void) {
uint8_t sha_256[HASH_LEN] = { 0 };
esp_partition_t partition;
// get sha256 digest for bootloader
partition.address = ESP_BOOTLOADER_OFFSET;
partition.size = ESP_PARTITION_TABLE_OFFSET;
partition.type = ESP_PARTITION_TYPE_APP;
esp_partition_get_sha256(&partition, sha_256);
print_sha256(sha_256, "SHA-256 for bootloader: ");
// get sha256 digest for running partition
esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
print_sha256(sha_256, "SHA-256 for current firmware: ");
}
void display_ota_state(pax_buf_t* pax_buffer, ILI9341* ili9341, const char* text) {
pax_noclip(pax_buffer);
const pax_font_t* font = pax_get_font("sky mono");
pax_background(pax_buffer, 0xFFFFFF);
pax_vec1_t title_size = pax_text_size(font, 18, "Firmware update");
pax_draw_text(pax_buffer, 0xFF000000, font, 18, (320 / 2) - (title_size.x / 2), 120 - 30, "Firmware update");
pax_vec1_t size = pax_text_size(font, 18, text);
pax_draw_text(pax_buffer, 0xFF000000, font, 18, (320 / 2) - (size.x / 2), 120 + 10, text);
ili9341_write(ili9341, pax_buffer->buf);
}
void ota_update(pax_buf_t* pax_buffer, ILI9341* ili9341) {
esp_wifi_set_ps(WIFI_PS_NONE); // Disable any WiFi power save mode
ESP_LOGI(TAG, "Starting OTA update");
esp_http_client_config_t config = {
.url = "https://ota.bodge.team/mch2022.bin",
.crt_bundle_attach = esp_crt_bundle_attach,
.cert_pem = (char *)server_cert_pem_start,
.event_handler = _http_event_handler,
.keep_alive_enable = true
};
esp_https_ota_config_t ota_config = {
.http_config = &config,
.http_client_init_cb = _http_client_init_cb, // Register a callback to be invoked after esp_http_client is initialized
#ifdef CONFIG_EXAMPLE_ENABLE_PARTIAL_HTTP_DOWNLOAD
.partial_http_download = true,
.max_http_request_size = CONFIG_EXAMPLE_HTTP_REQUEST_SIZE,
#endif
};
//config.skip_cert_common_name_check = true;
ESP_LOGI(TAG, "Attempting to download update from %s", config.url);
display_ota_state(pax_buffer, ili9341, "Starting download...");
esp_https_ota_handle_t https_ota_handle = NULL;
esp_err_t err = esp_https_ota_begin(&ota_config, &https_ota_handle);
if (err != ESP_OK) {
ESP_LOGE(TAG, "ESP HTTPS OTA Begin failed");
display_ota_state(pax_buffer, ili9341, "Failed to start download");
vTaskDelay(5000 / portTICK_PERIOD_MS);
esp_restart();
}
esp_app_desc_t app_desc;
err = esp_https_ota_get_img_desc(https_ota_handle, &app_desc);
if (err != ESP_OK) {
ESP_LOGE(TAG, "esp_https_ota_read_img_desc failed");
esp_https_ota_abort(https_ota_handle);
display_ota_state(pax_buffer, ili9341, "Failed to read image desc");
vTaskDelay(5000 / portTICK_PERIOD_MS);
esp_restart();
}
err = validate_image_header(&app_desc);
if (err != ESP_OK) {
ESP_LOGE(TAG, "image header verification failed");
esp_https_ota_abort(https_ota_handle);
display_ota_state(pax_buffer, ili9341, "Image header verification failed");
vTaskDelay(5000 / portTICK_PERIOD_MS);
esp_restart();
}
esp_err_t ota_finish_err = ESP_OK;
int percent_shown = -1;
while (1) {
err = esp_https_ota_perform(https_ota_handle);
if (err != ESP_ERR_HTTPS_OTA_IN_PROGRESS) {
break;
}
int len_total = esp_https_ota_get_image_size(https_ota_handle);
int len_read = esp_https_ota_get_image_len_read(https_ota_handle);
int percent = (len_read * 100) / len_total;
if (percent != percent_shown) {
ESP_LOGI(TAG, "Downloading %d / %d (%d%%)", len_read, len_total, percent);
percent_shown = percent;
char buffer[128];
snprintf(buffer, sizeof(buffer), "Updating... %d%%", percent);
display_ota_state(pax_buffer, ili9341, buffer);
}
}
if (esp_https_ota_is_complete_data_received(https_ota_handle) != true) {
// the OTA image was not completely received and user can customise the response to this situation.
ESP_LOGE(TAG, "Complete data was not received.");
display_ota_state(pax_buffer, ili9341, "Download failed");
vTaskDelay(5000 / portTICK_PERIOD_MS);
esp_restart();
} else {
ota_finish_err = esp_https_ota_finish(https_ota_handle);
if ((err == ESP_OK) && (ota_finish_err == ESP_OK)) {
ESP_LOGI(TAG, "ESP_HTTPS_OTA upgrade successful. Rebooting ...");
display_ota_state(pax_buffer, ili9341, "Update installed");
vTaskDelay(1000 / portTICK_PERIOD_MS);
esp_restart();
} else {
if (ota_finish_err == ESP_ERR_OTA_VALIDATE_FAILED) {
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
display_ota_state(pax_buffer, ili9341, "Image validation failed");
} else {
display_ota_state(pax_buffer, ili9341, "Update failed");
}
ESP_LOGE(TAG, "ESP_HTTPS_OTA upgrade failed 0x%x", ota_finish_err);
vTaskDelay(5000 / portTICK_PERIOD_MS);
esp_restart();
}
}
esp_https_ota_abort(https_ota_handle);
esp_restart();
while (1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 706 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 468 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 700 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 857 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 725 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

View file

@ -1,31 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 186 KiB