A bit of refactoring
This commit is contained in:
parent
c5a4be6479
commit
748ca757b9
11 changed files with 615 additions and 659 deletions
|
@ -1 +1 @@
|
||||||
Subproject commit fc1f1f634420f0b5baffb07bdef422e2280d207f
|
Subproject commit 8659d4201508875a46102a083efda191afeca0a3
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9a42035f026f928e272f8e8647880475c84881c9
|
Subproject commit 1c2b5241dd00d2fddb45d20f3c4a426fa379fa95
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7929cf7d34a60d5c8c91d06ac727f825aa310852
|
Subproject commit 2d5e8168d8604867c0323d320f94ca2c6fa2976d
|
|
@ -1,4 +1,4 @@
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS "main.c"
|
SRCS "main.c" "menu.c" "fpga_test.c"
|
||||||
INCLUDE_DIRS "."
|
INCLUDE_DIRS "." "include"
|
||||||
)
|
)
|
||||||
|
|
166
main/fpga_test.c
Normal file
166
main/fpga_test.c
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
#include "fpga_test.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <esp_log.h>
|
||||||
|
#include <freertos/FreeRTOS.h>
|
||||||
|
#include <freertos/queue.h>
|
||||||
|
#include "fpga.h"
|
||||||
|
#include "ili9341.h"
|
||||||
|
#include "ice40.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "button_message.h"
|
||||||
|
|
||||||
|
static const char *TAG = "fpga_test";
|
||||||
|
|
||||||
|
esp_err_t load_file_into_psram(ICE40* ice40, FILE* fd) {
|
||||||
|
fseek(fd, 0, SEEK_SET);
|
||||||
|
const uint8_t write_cmd = 0x02;
|
||||||
|
uint32_t amount_read;
|
||||||
|
uint32_t position = 0;
|
||||||
|
uint8_t* tx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
||||||
|
if (tx_buffer == NULL) return ESP_FAIL;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
tx_buffer[0] = write_cmd;
|
||||||
|
tx_buffer[1] = (position >> 16);
|
||||||
|
tx_buffer[2] = (position >> 8) & 0xFF;
|
||||||
|
tx_buffer[3] = position & 0xFF;
|
||||||
|
amount_read = fread(&tx_buffer[4], 1, SPI_MAX_TRANSFER_SIZE - 4, fd);
|
||||||
|
if (amount_read < 1) break;
|
||||||
|
ESP_LOGI(TAG, "Writing PSRAM @ %u (%u bytes)", position, amount_read);
|
||||||
|
esp_err_t res = ice40_transaction(ice40, tx_buffer, amount_read + 4, NULL, 0);
|
||||||
|
if (res != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Write transaction failed @ %u", position);
|
||||||
|
free(tx_buffer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
position += amount_read;
|
||||||
|
};
|
||||||
|
free(tx_buffer);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t load_buffer_into_psram(ICE40* ice40, uint8_t* buffer, uint32_t buffer_length) {
|
||||||
|
const uint8_t write_cmd = 0x02;
|
||||||
|
uint32_t position = 0;
|
||||||
|
uint8_t* tx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
||||||
|
if (tx_buffer == NULL) return ESP_FAIL;
|
||||||
|
while(1) {
|
||||||
|
tx_buffer[0] = write_cmd;
|
||||||
|
tx_buffer[1] = (position >> 16);
|
||||||
|
tx_buffer[2] = (position >> 8) & 0xFF;
|
||||||
|
tx_buffer[3] = position & 0xFF;
|
||||||
|
uint32_t length = buffer_length - position;
|
||||||
|
if (length > SPI_MAX_TRANSFER_SIZE - 4) length = SPI_MAX_TRANSFER_SIZE - 4;
|
||||||
|
memcpy(&tx_buffer[4], &buffer[position], length);
|
||||||
|
if (length == 0) break;
|
||||||
|
ESP_LOGI(TAG, "Writing PSRAM @ %u (%u bytes)", position, length);
|
||||||
|
esp_err_t res = ice40_transaction(ice40, tx_buffer, length + 4, NULL, 0);
|
||||||
|
if (res != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Write transaction failed @ %u", position);
|
||||||
|
free(tx_buffer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
position += length;
|
||||||
|
};
|
||||||
|
free(tx_buffer);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t verify_file_in_psram(ICE40* ice40, FILE* fd) {
|
||||||
|
fseek(fd, 0, SEEK_SET);
|
||||||
|
const uint8_t read_cmd = 0x03;
|
||||||
|
uint32_t amount_read;
|
||||||
|
uint32_t position = 0;
|
||||||
|
uint8_t* tx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
||||||
|
if (tx_buffer == NULL) return ESP_FAIL;
|
||||||
|
memset(tx_buffer, 0, SPI_MAX_TRANSFER_SIZE);
|
||||||
|
uint8_t* verify_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
||||||
|
if (verify_buffer == NULL) return ESP_FAIL;
|
||||||
|
uint8_t* rx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
||||||
|
if (rx_buffer == NULL) return ESP_FAIL;
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
tx_buffer[0] = read_cmd;
|
||||||
|
tx_buffer[1] = (position >> 16);
|
||||||
|
tx_buffer[2] = (position >> 8) & 0xFF;
|
||||||
|
tx_buffer[3] = position & 0xFF;
|
||||||
|
amount_read = fread(&verify_buffer[4], 1, SPI_MAX_TRANSFER_SIZE - 4, fd);
|
||||||
|
if (amount_read < 1) break;
|
||||||
|
ESP_LOGI(TAG, "Reading PSRAM @ %u (%u bytes)", position, amount_read);
|
||||||
|
esp_err_t res = ice40_transaction(ice40, tx_buffer, amount_read + 4, rx_buffer, amount_read + 4);
|
||||||
|
if (res != ESP_OK) {
|
||||||
|
ESP_LOGE(TAG, "Read transaction failed @ %u", position);
|
||||||
|
free(tx_buffer);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
position += amount_read;
|
||||||
|
ESP_LOGI(TAG, "Verifying PSRAM @ %u (%u bytes)", position, amount_read);
|
||||||
|
for (uint32_t i = 4; i < amount_read; i++) {
|
||||||
|
if (rx_buffer[i] != verify_buffer[i]) {
|
||||||
|
ESP_LOGE(TAG, "Verifying PSRAM @ %u failed: %02X != %02X", position + i, rx_buffer[i], verify_buffer[i]);
|
||||||
|
free(tx_buffer);
|
||||||
|
free(rx_buffer);
|
||||||
|
free(verify_buffer);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
free(tx_buffer);
|
||||||
|
free(rx_buffer);
|
||||||
|
free(verify_buffer);
|
||||||
|
ESP_LOGI(TAG, "PSRAM contents verified!");
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fpga_test(ILI9341* ili9341, ICE40* ice40, xQueueHandle buttonQueue) {
|
||||||
|
esp_err_t res;
|
||||||
|
bool reload_fpga = false;
|
||||||
|
do {
|
||||||
|
printf("Start FPGA test...\n");
|
||||||
|
reload_fpga = false;
|
||||||
|
printf("LCD deinit...\n");
|
||||||
|
ili9341_deinit(ili9341);
|
||||||
|
printf("LCD deselect...\n");
|
||||||
|
ili9341_select(ili9341, false);
|
||||||
|
printf("Wait...\n");
|
||||||
|
vTaskDelay(200 / portTICK_PERIOD_MS);
|
||||||
|
printf("LCD select...\n");
|
||||||
|
ili9341_select(ili9341, true);
|
||||||
|
|
||||||
|
printf("FPGA load...\n");
|
||||||
|
res = ice40_load_bitstream(ice40, proto2_bin, proto2_bin_len);
|
||||||
|
if (res != ESP_OK) {
|
||||||
|
printf("Failed to load app bitstream into FPGA (%d)\n", res);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
printf("Bitstream loaded succesfully!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool waitForChoice = true;
|
||||||
|
while (waitForChoice) {
|
||||||
|
button_message_t buttonMessage = {0};
|
||||||
|
printf("Waiting for button press...\n");
|
||||||
|
if (xQueueReceive(buttonQueue, &buttonMessage, portMAX_DELAY) == pdTRUE) {
|
||||||
|
printf("Button: %u, %u\n", buttonMessage.button, buttonMessage.state);
|
||||||
|
if (buttonMessage.state) {
|
||||||
|
switch(buttonMessage.button) {
|
||||||
|
case PCA9555_PIN_BTN_HOME:
|
||||||
|
case PCA9555_PIN_BTN_MENU:
|
||||||
|
case PCA9555_PIN_BTN_BACK:
|
||||||
|
waitForChoice = false;
|
||||||
|
break;
|
||||||
|
case PCA9555_PIN_BTN_ACCEPT:
|
||||||
|
reload_fpga = true;
|
||||||
|
waitForChoice = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ice40_disable(ice40);
|
||||||
|
ili9341_init(ili9341);
|
||||||
|
} while (reload_fpga);
|
||||||
|
}
|
6
main/include/button_message.h
Normal file
6
main/include/button_message.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef struct _button_message {
|
||||||
|
uint8_t button;
|
||||||
|
bool state;
|
||||||
|
} button_message_t;
|
8
main/include/fpga_test.h
Normal file
8
main/include/fpga_test.h
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "rp2040.h"
|
||||||
|
#include "ili9341.h"
|
||||||
|
#include "ice40.h"
|
||||||
|
|
||||||
|
void fpga_test(ILI9341* ili9341, ICE40* ice40, xQueueHandle buttonQueue);
|
46
main/include/menu.h
Normal file
46
main/include/menu.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
#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;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
} menu_t;
|
||||||
|
|
||||||
|
menu_t* menu_alloc(const char* aTitle);
|
||||||
|
void menu_free(menu_t* aMenu);
|
||||||
|
bool menu_insert_item(menu_t* aMenu, const char* aLabel, menu_callback_t aCallback, void* aCallbackArgs, size_t aPosition);
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif //__cplusplus
|
808
main/main.c
808
main/main.c
|
@ -3,6 +3,7 @@
|
||||||
#include <sdkconfig.h>
|
#include <sdkconfig.h>
|
||||||
#include <freertos/FreeRTOS.h>
|
#include <freertos/FreeRTOS.h>
|
||||||
#include <freertos/task.h>
|
#include <freertos/task.h>
|
||||||
|
#include <freertos/queue.h>
|
||||||
#include <esp_system.h>
|
#include <esp_system.h>
|
||||||
//#include <esp_spi_flash.h>
|
//#include <esp_spi_flash.h>
|
||||||
#include <esp_err.h>
|
#include <esp_err.h>
|
||||||
|
@ -20,7 +21,10 @@
|
||||||
|
|
||||||
#include "rp2040.h"
|
#include "rp2040.h"
|
||||||
|
|
||||||
#include "fpga.h"
|
#include "fpga_test.h"
|
||||||
|
|
||||||
|
#include "menu.h"
|
||||||
|
#include "button_message.h"
|
||||||
|
|
||||||
static const char *TAG = "main";
|
static const char *TAG = "main";
|
||||||
|
|
||||||
|
@ -30,107 +34,27 @@ ILI9341* ili9341 = NULL;
|
||||||
ICE40* ice40 = NULL;
|
ICE40* ice40 = NULL;
|
||||||
BNO055* bno055 = NULL;
|
BNO055* bno055 = NULL;
|
||||||
RP2040* rp2040 = NULL;
|
RP2040* rp2040 = NULL;
|
||||||
|
|
||||||
uint8_t* framebuffer = NULL;
|
uint8_t* framebuffer = NULL;
|
||||||
pax_buf_t* pax_buffer = NULL;
|
pax_buf_t* pax_buffer = NULL;
|
||||||
|
xQueueHandle buttonQueue;
|
||||||
bno055_vector_t rotation_offset = {.x = 0, .y = 0, .z = 0};
|
|
||||||
|
|
||||||
bno055_vector_t acceleration, magnetism, orientation, rotation, linear_acceleration, gravity;
|
|
||||||
|
|
||||||
typedef enum action {
|
typedef enum action {
|
||||||
ACTION_NONE,
|
ACTION_NONE,
|
||||||
|
ACTION_APPFS,
|
||||||
ACTION_INSTALLER,
|
ACTION_INSTALLER,
|
||||||
ACTION_FPGA
|
ACTION_FPGA
|
||||||
} menu_action_t;
|
} menu_action_t;
|
||||||
|
|
||||||
typedef struct _menu_item {
|
typedef struct _menu_args {
|
||||||
const char* name;
|
|
||||||
appfs_handle_t fd;
|
appfs_handle_t fd;
|
||||||
menu_action_t action;
|
menu_action_t action;
|
||||||
struct _menu_item* next;
|
} menu_args_t;
|
||||||
} menu_item_t;
|
|
||||||
|
|
||||||
uint8_t selected_item = 0;
|
|
||||||
uint8_t amount_of_items = 0;
|
|
||||||
bool start_selected = false;
|
|
||||||
menu_item_t* first_menu_item = NULL;
|
|
||||||
|
|
||||||
bool reset_to_menu = false;
|
|
||||||
bool reload_fpga = false;
|
|
||||||
|
|
||||||
const char installer_name[] = "Install app...";
|
|
||||||
const char fpga_name[] = "Test FPGA";
|
|
||||||
|
|
||||||
void button_handler(uint8_t pin, bool value) {
|
void button_handler(uint8_t pin, bool value) {
|
||||||
switch(pin) {
|
button_message_t message;
|
||||||
case PCA9555_PIN_BTN_JOY_LEFT:
|
message.button = pin;
|
||||||
printf("Joystick horizontal %s\n", value ? "left" : "center");
|
message.state = value;
|
||||||
if (value) {
|
xQueueSend(buttonQueue, &message, portMAX_DELAY);
|
||||||
for (uint8_t led = 0; led < 5; led++) {
|
|
||||||
rp2040_set_led_value(rp2040, led, 0, 255, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PCA9555_PIN_BTN_JOY_PRESS:
|
|
||||||
printf("Joystick %s\n", value ? "pressed" : "released");
|
|
||||||
if (value) {
|
|
||||||
for (uint8_t led = 0; led < 5; led++) {
|
|
||||||
rp2040_set_led_value(rp2040, led, 0, 0, 255);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PCA9555_PIN_BTN_JOY_DOWN:
|
|
||||||
printf("Joystick vertical %s\n", value ? "down" : "center");
|
|
||||||
//ili9341_set_partial_scanning(ili9341, 0, ILI9341_WIDTH / 2 - 1);
|
|
||||||
if (value && (!start_selected)) {
|
|
||||||
if (selected_item < amount_of_items - 1) {
|
|
||||||
selected_item += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PCA9555_PIN_BTN_JOY_UP:
|
|
||||||
printf("Joy vertical %s\n", value ? "up" : "center");
|
|
||||||
if (value && (!start_selected)) {
|
|
||||||
if (selected_item > 0) {
|
|
||||||
selected_item -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PCA9555_PIN_BTN_JOY_RIGHT:
|
|
||||||
printf("Joy horizontal %s\n", value ? "right" : "center");
|
|
||||||
if (value) {
|
|
||||||
for (uint8_t led = 0; led < 5; led++) {
|
|
||||||
rp2040_set_led_value(rp2040, led, 255, 0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case PCA9555_PIN_BTN_HOME:
|
|
||||||
printf("Home button %s\n", value ? "pressed" : "released");
|
|
||||||
break;
|
|
||||||
case PCA9555_PIN_BTN_MENU:
|
|
||||||
printf("Menu button %s\n", value ? "pressed" : "released");
|
|
||||||
if (value) reset_to_menu = true;
|
|
||||||
break;
|
|
||||||
case PCA9555_PIN_BTN_START: {
|
|
||||||
printf("Start button %s\n", value ? "pressed" : "released");
|
|
||||||
if (value) reload_fpga = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PCA9555_PIN_BTN_SELECT: {
|
|
||||||
printf("Select button %s\n", value ? "pressed" : "released");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PCA9555_PIN_BTN_BACK:
|
|
||||||
printf("Back button %s\n", value ? "pressed" : "released");
|
|
||||||
break;
|
|
||||||
case PCA9555_PIN_BTN_ACCEPT:
|
|
||||||
printf("Accept button %s\n", value ? "pressed" : "released");
|
|
||||||
if (value) start_selected = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("Unknown button %d %s\n", pin, value ? "pressed" : "released");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void button_init() {
|
void button_init() {
|
||||||
|
@ -158,145 +82,28 @@ void restart() {
|
||||||
esp_restart();
|
esp_restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
void bno055_task(BNO055* bno055) {
|
void message_render(pax_buf_t *aBuffer, char* message, float aPosX, float aPosY, float aWidth, float aHeight) {
|
||||||
esp_err_t res;
|
pax_col_t fgColor = 0xFFFF0000;
|
||||||
|
pax_col_t bgColor = 0xFFFFD4D4;
|
||||||
|
pax_clip(aBuffer, aPosX, aPosY, aWidth, aHeight);
|
||||||
|
pax_simple_rect(aBuffer, bgColor, aPosX, aPosY, aWidth, aHeight);
|
||||||
|
pax_outline_rect(aBuffer, fgColor, aPosX, aPosY, aWidth, aHeight);
|
||||||
|
pax_clip(aBuffer, aPosX + 1, aPosY + 1, aWidth - 2, aHeight - 2);
|
||||||
|
pax_draw_text(aBuffer, fgColor, NULL, 18, aPosX + 1, aPosY + 1, message);
|
||||||
|
pax_noclip(aBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
res = bno055_get_vector(bno055, BNO055_VECTOR_ACCELEROMETER, &acceleration);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Acceleration failed to read %d\n", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = bno055_get_vector(bno055, BNO055_VECTOR_MAGNETOMETER, &magnetism);
|
esp_err_t graphics_task(pax_buf_t* buffer, ILI9341* ili9341, uint8_t* framebuffer, menu_t* menu, char* message) {
|
||||||
if (res != ESP_OK) {
|
pax_background(pax_buffer, 0xCCCCCC);
|
||||||
ESP_LOGE(TAG, "Magnetic field to read %d\n", res);
|
if (menu != NULL) {
|
||||||
return;
|
menu_render(pax_buffer, menu, 10, 10, 320-20, 240-20);
|
||||||
}
|
|
||||||
|
|
||||||
res = bno055_get_vector(bno055, BNO055_VECTOR_GYROSCOPE, &orientation);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Orientation failed to read %d\n", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = bno055_get_vector(bno055, BNO055_VECTOR_EULER, &rotation);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Rotation failed to read %d\n", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = bno055_get_vector(bno055, BNO055_VECTOR_LINEARACCEL, &linear_acceleration);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Linear acceleration failed to read %d\n", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = bno055_get_vector(bno055, BNO055_VECTOR_GRAVITY, &gravity);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Gravity failed to read %d\n", res);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*if (calibrate) {
|
if (message != NULL) {
|
||||||
rotation_offset.x = rotation.x;
|
message_render(pax_buffer, message, 20, 110, 320-40, 20);
|
||||||
rotation_offset.y = rotation.y;
|
|
||||||
rotation_offset.z = rotation.z;
|
|
||||||
calibrate = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rotation.x -= rotation_offset.x;
|
|
||||||
rotation.y -= rotation_offset.y;
|
|
||||||
rotation.z -= rotation_offset.z;
|
|
||||||
|
|
||||||
if (rotation.x < 0) rotation.x = 360.0 - rotation.x;
|
|
||||||
if (rotation.y < 0) rotation.y = 360.0 - rotation.y;
|
|
||||||
if (rotation.z < 0) rotation.z = 360.0 - rotation.z;*/
|
|
||||||
|
|
||||||
/*printf("\n\n");
|
|
||||||
printf("Acceleration (m/s²) x = %5.8f y = %5.8f z = %5.8f\n", acceleration.x, acceleration.y, acceleration.z);
|
|
||||||
printf("Magnetic field (uT) x = %5.8f y = %5.8f z = %5.8f\n", magnetism.x, magnetism.y, magnetism.z);
|
|
||||||
printf("Orientation (dps) x = %5.8f y = %5.8f z = %5.8f\n", orientation.x, orientation.y, orientation.z);
|
|
||||||
printf("Rotation (degrees) x = %5.8f y = %5.8f z = %5.8f\n", rotation.x, rotation.y, rotation.z);
|
|
||||||
printf("Linear acceleration (m/s²) x = %5.8f y = %5.8f z = %5.8f\n", linear_acceleration.x, linear_acceleration.y, linear_acceleration.z);
|
|
||||||
printf("Gravity (m/s²) x = %5.8f y = %5.8f z = %5.8f\n", gravity.x, gravity.y, gravity.z);*/
|
|
||||||
|
|
||||||
if (display_bno_value) {
|
|
||||||
printf("Magnetic (uT) x: %5.4f y: %5.4f z: %5.4f Rotation (deg): x: %5.4f y: %5.4f z: %5.4f \n", magnetism.x, magnetism.y, magnetism.z, rotation.x, rotation.y, rotation.z);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_cursor(pax_buf_t* buffer, float x, float y) {
|
|
||||||
uint64_t millis = esp_timer_get_time() / 1000;
|
|
||||||
pax_col_t color = pax_col_hsv(millis * 255 / 8000, 255, 255);
|
|
||||||
pax_push_2d(buffer);
|
|
||||||
pax_apply_2d(buffer, matrix_2d_translate(x, y));
|
|
||||||
pax_apply_2d(buffer, matrix_2d_scale(10, 10));
|
|
||||||
pax_draw_tri(buffer, color, -1, -1, -1, 1, 1, 0);
|
|
||||||
pax_pop_2d(buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_menu_item(pax_buf_t* buffer, uint8_t position, bool selected, char* text) {
|
|
||||||
float y = 24 + position * 20;
|
|
||||||
if (selected) draw_cursor(buffer, 15, y + 9);
|
|
||||||
pax_draw_text(buffer, pax_col_rgb(0,0,0), PAX_FONT_DEFAULT, 18, 24, y, text);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t draw_menu(pax_buf_t* buffer) {
|
|
||||||
pax_push_2d(buffer);
|
|
||||||
//pax_apply_2d(buffer, matrix_2d_translate(0, 0));
|
|
||||||
//pax_apply_2d(buffer, matrix_2d_scale(1, 1));
|
|
||||||
pax_simple_line(buffer, pax_col_rgb(0,0,0), 0, 20, 320, 20);
|
|
||||||
pax_draw_text(buffer, pax_col_rgb(0,0,0), PAX_FONT_DEFAULT, 18, 0, 0, "Launcher");
|
|
||||||
menu_item_t* item = first_menu_item;
|
|
||||||
for (uint8_t index = 0; index < amount_of_items; index++) {
|
|
||||||
if (item != NULL) {
|
|
||||||
draw_menu_item(buffer, index, (selected_item == index), item->name);
|
|
||||||
}
|
|
||||||
item = item->next;
|
|
||||||
}
|
|
||||||
pax_pop_2d(buffer);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
pax_col_t regenboogkots(pax_col_t tint, int x, int y, float u, float v, void *args) {
|
|
||||||
return pax_col_hsv(x / 50.0 * 255.0 + y / 150.0 * 255.0, 255, 255);
|
|
||||||
}
|
|
||||||
|
|
||||||
pax_shader_t kots = {
|
|
||||||
.callback = regenboogkots
|
|
||||||
};
|
|
||||||
|
|
||||||
esp_err_t graphics_task(pax_buf_t* buffer, ILI9341* ili9341, uint8_t* framebuffer) {
|
|
||||||
pax_background(buffer, 0xFFFFFF);
|
|
||||||
//pax_shade_rect(buffer, 0, &kots, NULL, 0, 0, 320, 240);
|
|
||||||
pax_push_2d(buffer);
|
|
||||||
pax_apply_2d(buffer, matrix_2d_translate(buffer->width / 2.0, buffer->height / 2.0 + 10));
|
|
||||||
pax_apply_2d(buffer, matrix_2d_scale(50, 50));
|
|
||||||
uint64_t millis = esp_timer_get_time() / 1000;
|
|
||||||
pax_col_t color0 = pax_col_hsv(millis * 255 / 8000, 255, 255);
|
|
||||||
//pax_col_t color1 = pax_col_hsv(millis * 255 / 8000 + 127, 255, 255);
|
|
||||||
float a0 = rotation.y * (M_PI / 360.0);//millis / 3000.0 * M_PI;//0;//
|
|
||||||
//printf("%f from %f\n", a0, rotation.y);
|
|
||||||
//float a1 = fmodf(a0, M_PI * 4) - M_PI * 2;////
|
|
||||||
//pax_draw_arc(buffer, color0, 0, 0, 2, a0 + M_PI, a0);
|
|
||||||
/*pax_push_2d(buffer);
|
|
||||||
pax_apply_2d(buffer, matrix_2d_rotate(a0));
|
|
||||||
pax_push_2d(buffer);
|
|
||||||
pax_apply_2d(buffer, matrix_2d_translate(1, 0));
|
|
||||||
pax_draw_rect(buffer, color1, -0.25, -0.25, 0.5, 0.5);
|
|
||||||
pax_pop_2d(buffer);
|
|
||||||
pax_apply_2d(buffer, matrix_2d_rotate(a1));
|
|
||||||
pax_push_2d(buffer);
|
|
||||||
pax_apply_2d(buffer, matrix_2d_translate(1, 0));
|
|
||||||
pax_apply_2d(buffer, matrix_2d_rotate(-a0 - a1 + M_PI * 0.5));
|
|
||||||
pax_draw_tri(buffer, color1, 0.25, 0, -0.125, 0.2165, -0.125, -0.2165);
|
|
||||||
pax_pop_2d(buffer);
|
|
||||||
pax_pop_2d(buffer);*/
|
|
||||||
pax_pop_2d(buffer);
|
|
||||||
|
|
||||||
draw_menu(buffer);
|
|
||||||
|
|
||||||
//driver_framebuffer_print(NULL, "Hello world", 0, 0, 1, 1, 0xFF00FF, &ocra_22pt7b);
|
|
||||||
return ili9341_write(ili9341, framebuffer);
|
return ili9341_write(ili9341, framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,21 +113,8 @@ esp_err_t draw_message(char* message) {
|
||||||
return ili9341_write(ili9341, framebuffer);
|
return ili9341_write(ili9341, framebuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_chip_info(void) {
|
esp_err_t appfs_init(void) {
|
||||||
esp_chip_info_t chip_info;
|
return appfsInit(APPFS_PART_TYPE, APPFS_PART_SUBTYPE);
|
||||||
esp_chip_info(&chip_info);
|
|
||||||
printf("This is %s chip with %d CPU core(s), WiFi%s%s, ",
|
|
||||||
CONFIG_IDF_TARGET,
|
|
||||||
chip_info.cores,
|
|
||||||
(chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
|
|
||||||
(chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "");
|
|
||||||
|
|
||||||
printf("silicon revision %d, ", chip_info.revision);
|
|
||||||
|
|
||||||
printf("%dMB %s flash\n", spi_flash_get_chip_size() / (1024 * 1024),
|
|
||||||
(chip_info.features & CHIP_FEATURE_EMB_FLASH) ? "embedded" : "external");
|
|
||||||
|
|
||||||
printf("Minimum free heap size: %d bytes\n", esp_get_minimum_free_heap_size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* load_file_to_ram(FILE* fd, size_t* fsize) {
|
uint8_t* load_file_to_ram(FILE* fd, size_t* fsize) {
|
||||||
|
@ -333,206 +127,23 @@ uint8_t* load_file_to_ram(FILE* fd, size_t* fsize) {
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t load_file_into_psram(FILE* fd) {
|
|
||||||
fseek(fd, 0, SEEK_SET);
|
|
||||||
const uint8_t write_cmd = 0x02;
|
|
||||||
uint32_t amount_read;
|
|
||||||
uint32_t position = 0;
|
|
||||||
uint8_t* tx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
|
||||||
if (tx_buffer == NULL) return ESP_FAIL;
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
tx_buffer[0] = write_cmd;
|
|
||||||
tx_buffer[1] = (position >> 16);
|
|
||||||
tx_buffer[2] = (position >> 8) & 0xFF;
|
|
||||||
tx_buffer[3] = position & 0xFF;
|
|
||||||
amount_read = fread(&tx_buffer[4], 1, SPI_MAX_TRANSFER_SIZE - 4, fd);
|
|
||||||
if (amount_read < 1) break;
|
|
||||||
ESP_LOGI(TAG, "Writing PSRAM @ %u (%u bytes)", position, amount_read);
|
|
||||||
esp_err_t res = ice40_transaction(ice40, tx_buffer, amount_read + 4, NULL, 0);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Write transaction failed @ %u", position);
|
|
||||||
free(tx_buffer);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
position += amount_read;
|
|
||||||
};
|
|
||||||
free(tx_buffer);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t load_buffer_into_psram(uint8_t* buffer, uint32_t buffer_length) {
|
|
||||||
const uint8_t write_cmd = 0x02;
|
|
||||||
uint32_t position = 0;
|
|
||||||
uint8_t* tx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
|
||||||
if (tx_buffer == NULL) return ESP_FAIL;
|
|
||||||
while(1) {
|
|
||||||
tx_buffer[0] = write_cmd;
|
|
||||||
tx_buffer[1] = (position >> 16);
|
|
||||||
tx_buffer[2] = (position >> 8) & 0xFF;
|
|
||||||
tx_buffer[3] = position & 0xFF;
|
|
||||||
uint32_t length = buffer_length - position;
|
|
||||||
if (length > SPI_MAX_TRANSFER_SIZE - 4) length = SPI_MAX_TRANSFER_SIZE - 4;
|
|
||||||
memcpy(&tx_buffer[4], &buffer[position], length);
|
|
||||||
if (length == 0) break;
|
|
||||||
ESP_LOGI(TAG, "Writing PSRAM @ %u (%u bytes)", position, length);
|
|
||||||
esp_err_t res = ice40_transaction(ice40, tx_buffer, length + 4, NULL, 0);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Write transaction failed @ %u", position);
|
|
||||||
free(tx_buffer);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
position += length;
|
|
||||||
};
|
|
||||||
free(tx_buffer);
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t verify_file_in_psram(FILE* fd) {
|
|
||||||
fseek(fd, 0, SEEK_SET);
|
|
||||||
const uint8_t read_cmd = 0x03;
|
|
||||||
uint32_t amount_read;
|
|
||||||
uint32_t position = 0;
|
|
||||||
uint8_t* tx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
|
||||||
if (tx_buffer == NULL) return ESP_FAIL;
|
|
||||||
memset(tx_buffer, 0, SPI_MAX_TRANSFER_SIZE);
|
|
||||||
uint8_t* verify_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
|
||||||
if (verify_buffer == NULL) return ESP_FAIL;
|
|
||||||
uint8_t* rx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
|
||||||
if (rx_buffer == NULL) return ESP_FAIL;
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
tx_buffer[0] = read_cmd;
|
|
||||||
tx_buffer[1] = (position >> 16);
|
|
||||||
tx_buffer[2] = (position >> 8) & 0xFF;
|
|
||||||
tx_buffer[3] = position & 0xFF;
|
|
||||||
amount_read = fread(&verify_buffer[4], 1, SPI_MAX_TRANSFER_SIZE - 4, fd);
|
|
||||||
if (amount_read < 1) break;
|
|
||||||
ESP_LOGI(TAG, "Reading PSRAM @ %u (%u bytes)", position, amount_read);
|
|
||||||
esp_err_t res = ice40_transaction(ice40, tx_buffer, amount_read + 4, rx_buffer, amount_read + 4);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Read transaction failed @ %u", position);
|
|
||||||
free(tx_buffer);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
position += amount_read;
|
|
||||||
ESP_LOGI(TAG, "Verifying PSRAM @ %u (%u bytes)", position, amount_read);
|
|
||||||
for (uint32_t i = 4; i < amount_read; i++) {
|
|
||||||
if (rx_buffer[i] != verify_buffer[i]) {
|
|
||||||
ESP_LOGE(TAG, "Verifying PSRAM @ %u failed: %02X != %02X", position + i, rx_buffer[i], verify_buffer[i]);
|
|
||||||
free(tx_buffer);
|
|
||||||
free(rx_buffer);
|
|
||||||
free(verify_buffer);
|
|
||||||
return ESP_FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
free(tx_buffer);
|
|
||||||
free(rx_buffer);
|
|
||||||
free(verify_buffer);
|
|
||||||
ESP_LOGI(TAG, "PSRAM contents verified!");
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void fpga_test(void) {
|
|
||||||
esp_err_t res;
|
|
||||||
/*draw_message("Loading passthrough...");
|
|
||||||
FILE* fpga_passthrough = fopen("/sd/pt.bin", "rb");
|
|
||||||
if (fpga_passthrough == NULL) {
|
|
||||||
ESP_LOGE(TAG, "Failed to open passthrough firmware (pt.bin) from the SD card");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_message("Loading RAM...");
|
|
||||||
ESP_LOGI(TAG, "Loading passthrough bitstream into RAM buffer...");
|
|
||||||
size_t fpga_passthrough_bitstream_length;
|
|
||||||
uint8_t* fpga_passthrough_bitstream = load_file_to_ram(fpga_passthrough, &fpga_passthrough_bitstream_length);
|
|
||||||
fclose(fpga_passthrough);
|
|
||||||
ESP_LOGI(TAG, "Loading passthrough bitstream into FPGA...");
|
|
||||||
res = ice40_load_bitstream(ice40, fpga_passthrough_bitstream, fpga_passthrough_bitstream_length);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Failed to load passthrough bitstream into FPGA (%d)", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
free(fpga_passthrough_bitstream);
|
|
||||||
|
|
||||||
FILE* ram_contents = fopen("/sd/ram.bin", "rb");
|
|
||||||
if (ram_contents == NULL) {
|
|
||||||
ESP_LOGE(TAG, "Failed to open ram.bin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = load_file_into_psram(ram_contents);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Failed to load RAM contents into PSRAM (%d)", res);
|
|
||||||
fclose(ram_contents);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = verify_file_in_psram(ram_contents);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Failed to verify PSRAM contents (%d)", res);
|
|
||||||
fclose(ram_contents);
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//draw_message("Loading app...");
|
|
||||||
/*FILE* fpga_app = fopen("/sd/app.bin", "rb");
|
|
||||||
if (fpga_app == NULL) {
|
|
||||||
ESP_LOGE(TAG, "Failed to open app.bin");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Loading app bitstream into RAM buffer...");
|
|
||||||
size_t fpga_app_bitstream_length;
|
|
||||||
uint8_t* fpga_app_bitstream = load_file_to_ram(fpga_app, &fpga_app_bitstream_length);
|
|
||||||
fclose(fpga_app);*/
|
|
||||||
|
|
||||||
do {
|
|
||||||
reload_fpga = false;
|
|
||||||
ili9341_deinit(ili9341);
|
|
||||||
ili9341_select(ili9341, false);
|
|
||||||
vTaskDelay(200 / portTICK_PERIOD_MS);
|
|
||||||
ili9341_select(ili9341, true);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Loading app bitstream into FPGA...");
|
|
||||||
//res = ice40_load_bitstream(ice40, fpga_app_bitstream, fpga_app_bitstream_length);
|
|
||||||
res = ice40_load_bitstream(ice40, proto2_bin, proto2_bin_len);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Failed to load app bitstream into FPGA (%d)", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//free(fpga_app_bitstream);
|
|
||||||
|
|
||||||
reset_to_menu = false;
|
|
||||||
|
|
||||||
while (!reset_to_menu) {
|
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
|
||||||
if (reload_fpga) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ice40_disable(ice40);
|
|
||||||
ili9341_init(ili9341);
|
|
||||||
} while (reload_fpga);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t appfs_init(void) {
|
|
||||||
return appfsInit(APPFS_PART_TYPE, APPFS_PART_SUBTYPE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void appfs_store_app(void) {
|
void appfs_store_app(void) {
|
||||||
|
draw_message("Installing app...");
|
||||||
esp_err_t res;
|
esp_err_t res;
|
||||||
appfs_handle_t handle;
|
appfs_handle_t handle;
|
||||||
FILE* app_fd = fopen("/sd/gnuboy.bin", "rb");
|
FILE* app_fd = fopen("/sd/gnuboy.bin", "rb");
|
||||||
if (app_fd == NULL) {
|
if (app_fd == NULL) {
|
||||||
|
draw_message("Failed to open gnuboy.bin");
|
||||||
ESP_LOGE(TAG, "Failed to open gnuboy.bin");
|
ESP_LOGE(TAG, "Failed to open gnuboy.bin");
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
size_t app_size;
|
size_t app_size;
|
||||||
uint8_t* app = load_file_to_ram(app_fd, &app_size);
|
uint8_t* app = load_file_to_ram(app_fd, &app_size);
|
||||||
if (app == NULL) {
|
if (app == NULL) {
|
||||||
|
draw_message("Failed to load app to RAM");
|
||||||
ESP_LOGE(TAG, "Failed to load application into RAM");
|
ESP_LOGE(TAG, "Failed to load application into RAM");
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,18 +151,24 @@ void appfs_store_app(void) {
|
||||||
|
|
||||||
res = appfsCreateFile("gnuboy", app_size, &handle);
|
res = appfsCreateFile("gnuboy", app_size, &handle);
|
||||||
if (res != ESP_OK) {
|
if (res != ESP_OK) {
|
||||||
|
draw_message("Failed to create on AppFS");
|
||||||
ESP_LOGE(TAG, "Failed to create file on AppFS (%d)", res);
|
ESP_LOGE(TAG, "Failed to create file on AppFS (%d)", res);
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
free(app);
|
free(app);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res = appfsWrite(handle, 0, app, app_size);
|
res = appfsWrite(handle, 0, app, app_size);
|
||||||
if (res != ESP_OK) {
|
if (res != ESP_OK) {
|
||||||
|
draw_message("Failed to write to AppFS");
|
||||||
ESP_LOGE(TAG, "Failed to write to file on AppFS (%d)", res);
|
ESP_LOGE(TAG, "Failed to write to file on AppFS (%d)", res);
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
free(app);
|
free(app);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
free(app);
|
free(app);
|
||||||
ESP_LOGI(TAG, "Application is now stored in AppFS");
|
ESP_LOGI(TAG, "Application is now stored in AppFS");
|
||||||
|
draw_message("App installed!");
|
||||||
|
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -571,11 +188,13 @@ void appfs_test(bool sdcard_ready) {
|
||||||
appfs_handle_t fd = appfsOpen("gnuboy");
|
appfs_handle_t fd = appfsOpen("gnuboy");
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
ESP_LOGW(TAG, "gnuboy not found in appfs");
|
ESP_LOGW(TAG, "gnuboy not found in appfs");
|
||||||
if (sdcard_ready) {
|
draw_message("gnuboy not found in fs!");
|
||||||
|
/*if (sdcard_ready) {
|
||||||
appfs_store_app();
|
appfs_store_app();
|
||||||
appfs_test(false); // Recursive, but who cares :D
|
appfs_test(false); // Recursive, but who cares :D
|
||||||
}
|
}*/
|
||||||
} else {
|
} else {
|
||||||
|
draw_message("Booting gnuboy...");
|
||||||
ESP_LOGE(TAG, "booting gnuboy from appfs (%d)", fd);
|
ESP_LOGE(TAG, "booting gnuboy from appfs (%d)", fd);
|
||||||
appfs_boot_app(fd);
|
appfs_boot_app(fd);
|
||||||
}
|
}
|
||||||
|
@ -584,6 +203,14 @@ void appfs_test(bool sdcard_ready) {
|
||||||
void app_main(void) {
|
void app_main(void) {
|
||||||
esp_err_t res;
|
esp_err_t res;
|
||||||
|
|
||||||
|
buttonQueue = xQueueCreate(10, sizeof(button_message_t));
|
||||||
|
|
||||||
|
if (buttonQueue == NULL) {
|
||||||
|
ESP_LOGE(TAG, "Failed to allocate queue");
|
||||||
|
restart();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
framebuffer = heap_caps_malloc(ILI9341_BUFFER_SIZE, MALLOC_CAP_8BIT);
|
framebuffer = heap_caps_malloc(ILI9341_BUFFER_SIZE, MALLOC_CAP_8BIT);
|
||||||
if (framebuffer == NULL) {
|
if (framebuffer == NULL) {
|
||||||
ESP_LOGE(TAG, "Failed to allocate framebuffer");
|
ESP_LOGE(TAG, "Failed to allocate framebuffer");
|
||||||
|
@ -612,15 +239,13 @@ void app_main(void) {
|
||||||
ice40 = get_ice40();
|
ice40 = get_ice40();
|
||||||
bno055 = get_bno055();
|
bno055 = get_bno055();
|
||||||
rp2040 = get_rp2040();
|
rp2040 = get_rp2040();
|
||||||
|
|
||||||
//print_chip_info();
|
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Button init...");
|
||||||
|
|
||||||
draw_message("Button init...");
|
|
||||||
button_init();
|
button_init();
|
||||||
|
|
||||||
rp2040_set_led_mode(rp2040, true, true);
|
rp2040_set_led_mode(rp2040, true, true);
|
||||||
|
|
||||||
draw_message("AppFS init...");
|
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "AppFS init...");
|
||||||
res = appfs_init();
|
res = appfs_init();
|
||||||
if (res != ESP_OK) {
|
if (res != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "AppFS init failed: %d", res);
|
ESP_LOGE(TAG, "AppFS init failed: %d", res);
|
||||||
|
@ -628,244 +253,121 @@ void app_main(void) {
|
||||||
}
|
}
|
||||||
ESP_LOGI(TAG, "AppFS initialized");
|
ESP_LOGI(TAG, "AppFS initialized");
|
||||||
|
|
||||||
draw_message("Mount SD card...");
|
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "Mount SD card...");
|
||||||
res = mount_sd(SD_CMD, SD_CLK, SD_D0, SD_PWR, "/sd", false, 5);
|
res = mount_sd(SD_CMD, SD_CLK, SD_D0, SD_PWR, "/sd", false, 5);
|
||||||
bool sdcard_ready = (res == ESP_OK);
|
bool sdcard_ready = (res == ESP_OK);
|
||||||
|
|
||||||
|
if (sdcard_ready) {
|
||||||
|
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "SD card mounted");
|
||||||
|
} else {
|
||||||
|
graphics_task(pax_buffer, ili9341, framebuffer, NULL, "No SD card");
|
||||||
|
}
|
||||||
|
|
||||||
|
menu_t* menu = menu_alloc("Launcher");
|
||||||
|
|
||||||
/*if (sdcard_ready) {
|
|
||||||
ESP_LOGI(TAG, "SD card mounted");
|
|
||||||
//draw_message("AppFS test...");
|
|
||||||
//appfs_test(sdcard_ready);
|
|
||||||
draw_message("FPGA init...");
|
|
||||||
fpga_test();
|
|
||||||
ESP_LOGW(TAG, "End of main function, goodbye!");
|
|
||||||
return;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
menu_item_t* current_menu_item = NULL;
|
|
||||||
appfs_handle_t current_fd = APPFS_INVALID_FD;
|
appfs_handle_t current_fd = APPFS_INVALID_FD;
|
||||||
|
|
||||||
amount_of_items = 0;
|
while (1) {
|
||||||
selected_item = 0;
|
|
||||||
|
|
||||||
do {
|
|
||||||
current_fd = appfsNextEntry(current_fd);
|
current_fd = appfsNextEntry(current_fd);
|
||||||
if (current_fd != APPFS_INVALID_FD) {
|
if (current_fd == APPFS_INVALID_FD) break;
|
||||||
menu_item_t* next_menu_item = malloc(sizeof(menu_item_t));
|
|
||||||
if (current_menu_item != NULL) {
|
const char* name = NULL;
|
||||||
current_menu_item->next = next_menu_item;
|
appfsEntryInfo(current_fd, &name, NULL);
|
||||||
} else {
|
menu_args_t* args = malloc(sizeof(menu_args_t));
|
||||||
first_menu_item = next_menu_item;
|
args->fd = current_fd;
|
||||||
}
|
args->action = ACTION_APPFS;
|
||||||
current_menu_item = next_menu_item;
|
menu_insert_item(menu, name, NULL, (void*) args, -1);
|
||||||
appfsEntryInfo(current_fd, ¤t_menu_item->name, NULL);
|
|
||||||
current_menu_item->fd = current_fd;
|
|
||||||
current_menu_item->action = ACTION_NONE;
|
|
||||||
current_menu_item->next = NULL;
|
|
||||||
printf("Building menu list %u: %s\r\n", amount_of_items, current_menu_item->name);
|
|
||||||
amount_of_items++;
|
|
||||||
}
|
|
||||||
} while (current_fd != APPFS_INVALID_FD);
|
|
||||||
printf("Building menu list done, %u items\r\n", amount_of_items);
|
|
||||||
|
|
||||||
menu_item_t* next_menu_item;
|
|
||||||
|
|
||||||
/*next_menu_item = malloc(sizeof(menu_item_t));
|
|
||||||
if (current_menu_item != NULL) {
|
|
||||||
current_menu_item->next = next_menu_item;
|
|
||||||
} else {
|
|
||||||
first_menu_item = next_menu_item;
|
|
||||||
}
|
}
|
||||||
current_menu_item = next_menu_item;
|
|
||||||
current_menu_item->fd = APPFS_INVALID_FD;
|
|
||||||
current_menu_item->action = ACTION_INSTALLER;
|
|
||||||
current_menu_item->name = installer_name;
|
|
||||||
current_menu_item->next = NULL;
|
|
||||||
amount_of_items++;*/
|
|
||||||
|
|
||||||
next_menu_item = malloc(sizeof(menu_item_t));
|
|
||||||
if (current_menu_item != NULL) {
|
|
||||||
current_menu_item->next = next_menu_item;
|
|
||||||
} else {
|
|
||||||
first_menu_item = next_menu_item;
|
|
||||||
}
|
|
||||||
current_menu_item = next_menu_item;
|
|
||||||
current_menu_item->fd = APPFS_INVALID_FD;
|
|
||||||
current_menu_item->action = ACTION_FPGA;
|
|
||||||
current_menu_item->name = fpga_name;
|
|
||||||
current_menu_item->next = NULL;
|
|
||||||
amount_of_items++;
|
|
||||||
|
|
||||||
|
|
||||||
|
menu_args_t* fpga_args = malloc(sizeof(menu_args_t));
|
||||||
|
fpga_args->action = ACTION_FPGA;
|
||||||
|
menu_insert_item(menu, "FPGA test", NULL, fpga_args, -1);
|
||||||
|
menu_args_t* install_args = malloc(sizeof(menu_args_t));
|
||||||
|
install_args->action = ACTION_INSTALLER;
|
||||||
|
menu_insert_item(menu, "Install app...", NULL, install_args, -1);
|
||||||
|
|
||||||
|
bool render = true;
|
||||||
|
menu_args_t* menuAction = NULL;
|
||||||
while (1) {
|
while (1) {
|
||||||
//bno055_task(bno055);
|
button_message_t buttonMessage = {0};
|
||||||
graphics_task(pax_buffer, ili9341, framebuffer);
|
if (xQueueReceive(buttonQueue, &buttonMessage, 16 / portTICK_PERIOD_MS) == pdTRUE) {
|
||||||
//printf("Selected: %u of %u\r\n", selected_item + 1, amount_of_items);
|
uint8_t pin = buttonMessage.button;
|
||||||
if (start_selected) {
|
bool value = buttonMessage.state;
|
||||||
current_menu_item = first_menu_item;
|
switch(pin) {
|
||||||
for (uint8_t index = 0; index < selected_item; index++) {
|
case PCA9555_PIN_BTN_JOY_LEFT:
|
||||||
current_menu_item = current_menu_item->next;
|
printf("Joystick horizontal %s\n", value ? "left" : "center");
|
||||||
}
|
break;
|
||||||
if (current_menu_item->action == ACTION_INSTALLER) {
|
case PCA9555_PIN_BTN_JOY_PRESS:
|
||||||
draw_message("Not yet implemented");
|
printf("Joystick %s\n", value ? "pressed" : "released");
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
break;
|
||||||
start_selected = false;
|
case PCA9555_PIN_BTN_JOY_DOWN:
|
||||||
} else if (current_menu_item->action == ACTION_FPGA) {
|
printf("Joystick vertical %s\n", value ? "down" : "center");
|
||||||
fpga_test();
|
if (value) {
|
||||||
start_selected = false;
|
menu_navigate_next(menu);
|
||||||
} else {
|
render = true;
|
||||||
draw_message("Starting app...");
|
}
|
||||||
appfs_boot_app(current_menu_item->fd);
|
break;
|
||||||
|
case PCA9555_PIN_BTN_JOY_UP:
|
||||||
|
printf("Joystick vertical %s\n", value ? "up" : "center");
|
||||||
|
if (value) {
|
||||||
|
menu_navigate_previous(menu);
|
||||||
|
render = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PCA9555_PIN_BTN_JOY_RIGHT:
|
||||||
|
printf("Joystick horizontal %s\n", value ? "right" : "center");
|
||||||
|
break;
|
||||||
|
case PCA9555_PIN_BTN_HOME:
|
||||||
|
printf("Home button %s\n", value ? "pressed" : "released");
|
||||||
|
break;
|
||||||
|
case PCA9555_PIN_BTN_MENU:
|
||||||
|
printf("Menu button %s\n", value ? "pressed" : "released");
|
||||||
|
//if (value) reset_to_menu = true;
|
||||||
|
break;
|
||||||
|
case PCA9555_PIN_BTN_START: {
|
||||||
|
printf("Start button %s\n", value ? "pressed" : "released");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PCA9555_PIN_BTN_SELECT: {
|
||||||
|
printf("Select button %s\n", value ? "pressed" : "released");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PCA9555_PIN_BTN_BACK:
|
||||||
|
printf("Back button %s\n", value ? "pressed" : "released");
|
||||||
|
break;
|
||||||
|
case PCA9555_PIN_BTN_ACCEPT:
|
||||||
|
printf("Accept button %s\n", value ? "pressed" : "released");
|
||||||
|
if (value) {
|
||||||
|
menuAction = menu_get_callback_args(menu, menu_get_position(menu));
|
||||||
|
printf("Position: %u\n", menu_get_position(menu));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknown button %d %s\n", pin, value ? "pressed" : "released");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/*
|
|
||||||
uint8_t data_out, data_in;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
I2C_REGISTER_FW_VER,
|
|
||||||
I2C_REGISTER_GPIO_DIR,
|
|
||||||
I2C_REGISTER_GPIO_IN,
|
|
||||||
I2C_REGISTER_GPIO_OUT,
|
|
||||||
I2C_REGISTER_LCD_MODE,
|
|
||||||
I2C_REGISTER_LCD_BACKLIGHT,
|
|
||||||
};
|
|
||||||
|
|
||||||
data_out = 1 << 2; // Proto 0 pin is output
|
if (render) {
|
||||||
res = i2c_write_reg_n(I2C_BUS_EXT, 0x17, I2C_REGISTER_GPIO_DIR, &data_out, 1);
|
graphics_task(pax_buffer, ili9341, framebuffer, menu, NULL);
|
||||||
if (res != ESP_OK) {
|
render = false;
|
||||||
ESP_LOGE(TAG, "Failed to set GPIO direction on Pico: %d", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool blink_state = false;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
data_out = blink_state << 2;
|
|
||||||
res = i2c_write_reg_n(I2C_BUS_EXT, 0x17, I2C_REGISTER_GPIO_OUT, &data_out, 1);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Failed to set GPIO value on Pico: %d", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
blink_state = !blink_state;
|
|
||||||
|
|
||||||
res = i2c_read_reg(I2C_BUS_EXT, 0x17, I2C_REGISTER_GPIO_IN, &data_in, 1);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Failed to read GPIO value from Pico %d", res);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
printf("GPIO status: %02x\n", data_in);
|
|
||||||
}
|
|
||||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// FPGA RAM passthrough test
|
|
||||||
|
|
||||||
res = ice40_load_bitstream(ice40, proto2_bin, proto2_bin_len);
|
|
||||||
if (res != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Failed to program the FPGA (%d)", res);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t* tx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
|
||||||
uint8_t* rx_buffer = malloc(SPI_MAX_TRANSFER_SIZE);
|
|
||||||
|
|
||||||
const uint8_t write_cmd = 0x02;
|
|
||||||
const uint8_t read_cmd = 0x03;
|
|
||||||
|
|
||||||
uint32_t size_of_ram = 8388608;
|
|
||||||
uint32_t position = 0;
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Writing to PSRAM...");
|
|
||||||
int64_t tx_start_time = esp_timer_get_time();
|
|
||||||
while (position < size_of_ram) {
|
|
||||||
// First 4 bytes of the transmit buffer are used for CMD and 24-bit address
|
|
||||||
tx_buffer[0] = write_cmd;
|
|
||||||
tx_buffer[1] = (position >> 16);
|
|
||||||
tx_buffer[2] = (position >> 8) & 0xFF;
|
|
||||||
tx_buffer[3] = position & 0xFF;
|
|
||||||
|
|
||||||
uint32_t remaining = size_of_ram - position;
|
|
||||||
uint32_t data_length = SPI_MAX_TRANSFER_SIZE - 4;
|
|
||||||
if (data_length > remaining) data_length = remaining;
|
|
||||||
|
|
||||||
//
|
|
||||||
for (uint32_t index = 0; index < data_length; index++) {
|
|
||||||
tx_buffer[index + 4] = ((position + (index)) & 0xFF); // Generate a test pattern
|
|
||||||
}
|
|
||||||
if (ice40_transaction(ice40, tx_buffer, data_length + 4, rx_buffer, data_length + 4) != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Write transaction failed @ %u", remaining);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
position += data_length;
|
if (menuAction != NULL) {
|
||||||
}
|
graphics_task(pax_buffer, ili9341, framebuffer, menu, "Please wait...");
|
||||||
int64_t tx_done_time = esp_timer_get_time();
|
if (menuAction->action == ACTION_APPFS) {
|
||||||
printf("Write took %lld microseconds\r\n", tx_done_time - tx_start_time);
|
appfs_boot_app(menuAction->fd);
|
||||||
uint64_t result = (((size_of_ram) / (tx_done_time - tx_start_time))*1000*1000)/1024;
|
} else if (menuAction->action == ACTION_FPGA) {
|
||||||
printf("%u bytes in %lld microseconds = %llu kB/s\r\n", size_of_ram, tx_done_time - tx_start_time, result);
|
graphics_task(pax_buffer, ili9341, framebuffer, menu, "FPGA TEST");
|
||||||
|
fpga_test(ili9341, ice40, buttonQueue);
|
||||||
position = 0; // Reset position
|
}else if (menuAction->action == ACTION_INSTALLER) {
|
||||||
memset(tx_buffer, 0, SPI_MAX_TRANSFER_SIZE); // Clear TX buffer
|
graphics_task(pax_buffer, ili9341, framebuffer, menu, "INSTALLER");
|
||||||
|
appfs_store_app();
|
||||||
ESP_LOGI(TAG, "Verifying PSRAM contents...");
|
|
||||||
int64_t rx_start_time = esp_timer_get_time();
|
|
||||||
while (position < size_of_ram) {
|
|
||||||
tx_buffer[0] = read_cmd;
|
|
||||||
tx_buffer[1] = (position >> 16);
|
|
||||||
tx_buffer[2] = (position >> 8) & 0xFF;
|
|
||||||
tx_buffer[3] = position & 0xFF;
|
|
||||||
|
|
||||||
uint32_t remaining = size_of_ram - position;
|
|
||||||
uint32_t data_length = SPI_MAX_TRANSFER_SIZE - 4;
|
|
||||||
if (data_length > remaining) data_length = remaining;
|
|
||||||
|
|
||||||
if (ice40_transaction(ice40, tx_buffer, data_length + 4, rx_buffer, data_length + 4) != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "Transaction failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t index = 0; index < data_length; index++) {
|
|
||||||
if (rx_buffer[index + 4] != ((position + (index)) & 0xFF)) { // Verify the test pattern
|
|
||||||
ESP_LOGE(TAG, "Verification failed @ %u + %u: %u != %u", position, index, rx_buffer[index + 4], (position + (index)) & 0xFF);
|
|
||||||
}
|
}
|
||||||
|
menuAction = NULL;
|
||||||
|
render = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
position += data_length;
|
|
||||||
}
|
}
|
||||||
int64_t rx_done_time = esp_timer_get_time();
|
|
||||||
printf("Read took %lld microseconds\r\n", rx_done_time - rx_start_time);
|
|
||||||
result = (((size_of_ram) / (rx_done_time - rx_start_time))*1000*1000)/1024;
|
|
||||||
printf("%u bytes in %lld microseconds = %llu kB/s\r\n", size_of_ram, rx_done_time - rx_start_time, result);*/
|
|
||||||
|
|
||||||
free(framebuffer);
|
free(framebuffer);
|
||||||
//ESP_LOGW(TAG, "End of main function, goodbye!");
|
|
||||||
|
|
||||||
rp2040_set_led_mode(rp2040, true, true);
|
|
||||||
|
|
||||||
for (uint8_t led = 0; led < 5; led++) {
|
|
||||||
rp2040_set_led_value(rp2040, led, 0, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8_t value = 0; value < 255; value++) {
|
|
||||||
rp2040_set_lcd_backlight(rp2040, 254 - value);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8_t value = 0; value < 255; value++) {
|
|
||||||
rp2040_set_lcd_backlight(rp2040, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
for (uint8_t led = 0; led < 5; led++) {
|
|
||||||
rp2040_set_led_value(rp2040, led, 255, 0, 0 );
|
|
||||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
|
||||||
rp2040_set_led_value(rp2040, led, 0, 255, 0 );
|
|
||||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
|
||||||
rp2040_set_led_value(rp2040, led, 0, 0, 255);
|
|
||||||
vTaskDelay(50 / portTICK_PERIOD_MS);
|
|
||||||
rp2040_set_led_value(rp2040, led, 0, 0, 0 );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
228
main/menu.c
Normal file
228
main/menu.c
Normal file
|
@ -0,0 +1,228 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "pax_gfx.h"
|
||||||
|
#include "menu.h"
|
||||||
|
|
||||||
|
menu_t* menu_alloc(const char* aTitle) {
|
||||||
|
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;
|
||||||
|
return menu;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _menu_free_item(menu_item_t* aMenuItem) {
|
||||||
|
free(aMenuItem->label);
|
||||||
|
if (aMenuItem->callbackArgs != NULL) {
|
||||||
|
free(aMenuItem->callbackArgs);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 NULL;
|
||||||
|
}
|
||||||
|
memcpy(newItem->label, aLabel, labelSize);
|
||||||
|
newItem->callback = aCallback;
|
||||||
|
newItem->callbackArgs = aCallbackArgs;
|
||||||
|
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_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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
size_t itemOffset = 0;
|
||||||
|
pax_col_t fgColor = 0xFF000000;
|
||||||
|
pax_col_t bgColor = 0xFFFFFFFF;
|
||||||
|
pax_col_t borderColor = 0xFF000000;
|
||||||
|
pax_col_t titleColor = 0xFFFFFFFF;
|
||||||
|
float scroll = 0;
|
||||||
|
float entry_height = 18 + 2;
|
||||||
|
size_t maxItems = aBuffer->height / entry_height;
|
||||||
|
|
||||||
|
size_t entry_offset = scroll / entry_height;
|
||||||
|
scroll -= entry_offset * entry_height;
|
||||||
|
|
||||||
|
float posY = aPosY;
|
||||||
|
|
||||||
|
pax_clip(aBuffer, aPosX, aPosY, aWidth, aHeight);
|
||||||
|
pax_simple_rect(aBuffer, bgColor, aPosX, aPosY, aWidth, aHeight);
|
||||||
|
|
||||||
|
if (maxItems > 1) {
|
||||||
|
maxItems--;
|
||||||
|
pax_simple_rect(aBuffer, borderColor, aPosX, posY, aWidth, entry_height);
|
||||||
|
pax_simple_line(aBuffer, titleColor, aPosX + 1, aPosY + entry_height, aPosX + aWidth - 2, aPosY + entry_height - 1);
|
||||||
|
pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 2, entry_height - 2);
|
||||||
|
pax_draw_text(aBuffer, titleColor, NULL, entry_height - 2, aPosX + 1, posY + 1, aMenu->title);
|
||||||
|
posY += entry_height;
|
||||||
|
}
|
||||||
|
pax_clip(aBuffer, aPosX, posY, aWidth, aHeight);
|
||||||
|
pax_outline_rect(aBuffer, borderColor, aPosX, aPosY, aWidth, aHeight);
|
||||||
|
|
||||||
|
|
||||||
|
posY -= scroll;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (index == aMenu->position) {
|
||||||
|
pax_clip(aBuffer, aPosX, posY, aWidth, entry_height);
|
||||||
|
pax_simple_rect(aBuffer, fgColor, aPosX + 1, posY, aWidth - 2, entry_height);
|
||||||
|
pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 2, entry_height - 2);
|
||||||
|
pax_draw_text(aBuffer, bgColor, NULL, entry_height - 2, aPosX + 1, posY + 1, item->label);
|
||||||
|
} else {
|
||||||
|
pax_clip(aBuffer, aPosX, posY, aWidth, entry_height);
|
||||||
|
pax_simple_rect(aBuffer, bgColor, aPosX + 1, posY, aWidth - 2, entry_height);
|
||||||
|
pax_clip(aBuffer, aPosX + 1, posY + 1, aWidth - 2, entry_height - 2);
|
||||||
|
pax_draw_text(aBuffer, fgColor, NULL, entry_height - 2, aPosX + 1, posY + 1, item->label);
|
||||||
|
}
|
||||||
|
posY += entry_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
pax_noclip(aBuffer);
|
||||||
|
}
|
2
qemu.sh
2
qemu.sh
|
@ -16,7 +16,7 @@ dd if=/dev/zero bs=1M count=16 of=flash.bin
|
||||||
dd if=bootloader/bootloader.bin bs=1 seek=$((0x1000)) of=flash.bin conv=notrunc
|
dd if=bootloader/bootloader.bin bs=1 seek=$((0x1000)) of=flash.bin conv=notrunc
|
||||||
|
|
||||||
# Copy the partition table into the file
|
# Copy the partition table into the file
|
||||||
dd if=partition_table/partition-table.bin bs=1 seek=$((0x8000)) of=flash.bin conv=notrunc
|
dd if=partition_table/partition-table.bin bs=1 seek=$((0x9000)) of=flash.bin conv=notrunc
|
||||||
|
|
||||||
# Copy the firmware into the file
|
# Copy the firmware into the file
|
||||||
dd if=main.bin bs=1 seek=$((0x10000)) of=flash.bin conv=notrunc
|
dd if=main.bin bs=1 seek=$((0x10000)) of=flash.bin conv=notrunc
|
||||||
|
|
Loading…
Reference in a new issue