Update appfs, tests
This commit is contained in:
parent
932246024c
commit
32637a8676
17 changed files with 494 additions and 12931 deletions
|
@ -1,4 +1,3 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(main)
|
||||
|
|
1
factory_test/bootloader_components/appfs
Symbolic link
1
factory_test/bootloader_components/appfs
Symbolic link
|
@ -0,0 +1 @@
|
|||
../components/appfs
|
17
factory_test/bootloader_components/main/CMakeLists.txt
Normal file
17
factory_test/bootloader_components/main/CMakeLists.txt
Normal file
|
@ -0,0 +1,17 @@
|
|||
idf_component_register(SRCS "bootloader_start.c" "appfs_flashfunctions_wrapper.c"
|
||||
REQUIRES bootloader bootloader_support appfs)
|
||||
|
||||
idf_build_get_property(target IDF_TARGET)
|
||||
# Use the linker script files from the actual bootloader
|
||||
set(scripts "${IDF_PATH}/components/bootloader/subproject/main/ld/${target}/bootloader.ld"
|
||||
"${IDF_PATH}/components/bootloader/subproject/main/ld/${target}/bootloader.rom.ld")
|
||||
|
||||
target_linker_script(${COMPONENT_LIB} INTERFACE "${scripts}")
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE
|
||||
"-Wl,--wrap=bootloader_flash_read"
|
||||
"-Wl,--wrap=bootloader_mmap"
|
||||
"-Wl,--wrap=bootloader_munmap"
|
||||
"-Wl,--wrap=bootloader_console_deinit"
|
||||
)
|
||||
|
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
These functions wrap the flash read and mmap functions. The idea is that normally, they will run the real
|
||||
functions. However, after appfs_wrapper_init is called with an appfs file and a flash range, any
|
||||
call to these functions in that range will be redirected to the appfs functions that do the same.
|
||||
The idea is that this changes the 'view' of that flash range from an (for the rest of the bootloader)
|
||||
ununderstandable appfs struct mess, to one that looks the same as it would when the selected file
|
||||
would be directly flashed to the partition. The nice thing here is that we can use the rest of the
|
||||
bootloader verbatim, without having to modify it.
|
||||
|
||||
Not we assume the ovl_start and ovl_end match the position and size of the appfs partition; we use that
|
||||
if we actually boot an app.
|
||||
|
||||
Note that IRAM_ATTR is used here to make sure the functions that are used when/after the app loadable
|
||||
segments are loaded, won't be overwritten. The IRAM_ATTR in the bootloader code dumps the function
|
||||
in the loader segment instead of in random IRAM.
|
||||
*/
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
#include "appfs.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_app_format.h"
|
||||
#include "soc/soc_memory_types.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#include <string.h>
|
||||
|
||||
static const char *TAG="appfs_wrapper";
|
||||
|
||||
static appfs_handle_t file_handle=APPFS_INVALID_FD;
|
||||
static size_t ovl_start, ovl_size;
|
||||
|
||||
void appfs_wrapper_init(appfs_handle_t handle, size_t part_start, size_t part_size) {
|
||||
file_handle=handle;
|
||||
ovl_start=part_start;
|
||||
ovl_size=part_size;
|
||||
}
|
||||
|
||||
void appfs_wrapper_deinit() {
|
||||
file_handle=APPFS_INVALID_FD;
|
||||
}
|
||||
|
||||
//These are the actual functions.
|
||||
esp_err_t __real_bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt);
|
||||
const void *__real_bootloader_mmap(uint32_t src_addr, uint32_t size);
|
||||
void __real_bootloader_munmap(const void *mapping);
|
||||
void __real_bootloader_console_deinit();
|
||||
|
||||
|
||||
static bool was_mmapped_to_appfs=false;
|
||||
|
||||
IRAM_ATTR const void *__wrap_bootloader_mmap(uint32_t src_addr, uint32_t size) {
|
||||
if (file_handle!=APPFS_INVALID_FD && src_addr>=ovl_start && src_addr+size<ovl_start+ovl_size) {
|
||||
ESP_LOGI(TAG, "__wrap_bootloader_mmap: redirecting map to 0x%X", src_addr);
|
||||
uint8_t *f=appfsBlMmap(file_handle);
|
||||
return &f[src_addr-ovl_start];
|
||||
} else {
|
||||
return __real_bootloader_mmap(src_addr, size);
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR void __wrap_bootloader_munmap(const void *mapping) {
|
||||
if (file_handle!=APPFS_INVALID_FD && was_mmapped_to_appfs) {
|
||||
appfsBlMunmap();
|
||||
was_mmapped_to_appfs=false;
|
||||
} else {
|
||||
__real_bootloader_munmap(mapping);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
IRAM_ATTR esp_err_t __wrap_bootloader_flash_read(size_t src_addr, void *dest, size_t size, bool allow_decrypt) {
|
||||
if (file_handle!=APPFS_INVALID_FD && src_addr>=ovl_start && src_addr+size<ovl_start+ovl_size) {
|
||||
uint8_t *f=appfsBlMmap(file_handle);
|
||||
ESP_LOGI(TAG, "__wrap_bootloader_flash_read: 0x%X->0x%X, %d bytes", src_addr, (int)dest, size);
|
||||
memcpy(dest, &f[src_addr-ovl_start], size);
|
||||
appfsBlMunmap();
|
||||
return ESP_OK;
|
||||
} else {
|
||||
return __real_bootloader_flash_read(src_addr, dest, size, allow_decrypt);
|
||||
}
|
||||
}
|
||||
|
||||
IRAM_ATTR static bool should_map(uint32_t load_addr) {
|
||||
return (load_addr >= SOC_IROM_LOW && load_addr < SOC_IROM_HIGH)
|
||||
|| (load_addr >= SOC_DROM_LOW && load_addr < SOC_DROM_HIGH);
|
||||
}
|
||||
|
||||
//Note: when this is called, everything to verify and load the app has already been done *EXCEPT* the MMU
|
||||
//mapping. That is done, but with wrong addresses. We need to re-do that here and then call into
|
||||
//the app.
|
||||
static IRAM_ATTR void mmap_and_start_app() {
|
||||
ESP_LOGI(TAG, "mmap_and_start_app()");
|
||||
//Undo bootloader mapping. If we don't call this, the rest of the code thinks there's still
|
||||
//something mapped. Note that for now the address doesn't matter, we feed it 0.
|
||||
__real_bootloader_munmap(0);
|
||||
//Appfs is not gonna like that its metadata is not mmapped. We call this routine as what it does
|
||||
//'under the hood' is clear the mmu and reset it to mmap only the appfs meta info.
|
||||
appfsBlMunmap();
|
||||
|
||||
//Map the executable file so we can read its header.
|
||||
uint8_t *appBytes=appfsBlMmap(file_handle);
|
||||
const esp_image_header_t *hdr=(const esp_image_header_t*)appBytes;
|
||||
uint32_t entry_addr=hdr->entry_addr;
|
||||
|
||||
AppfsBlRegionToMap mapRegions[8];
|
||||
int noMaps=0;
|
||||
uint8_t *pstart=appBytes+sizeof(esp_image_header_t);
|
||||
uint8_t *p=pstart;
|
||||
for (int i=0; i<hdr->segment_count; i++) {
|
||||
esp_image_segment_header_t *shdr=(esp_image_segment_header_t*)p;
|
||||
p+=sizeof(esp_image_segment_header_t);
|
||||
if (should_map(shdr->load_addr)) {
|
||||
mapRegions[noMaps].fileAddr=p-appBytes;
|
||||
mapRegions[noMaps].mapAddr=shdr->load_addr;
|
||||
mapRegions[noMaps].length=shdr->data_len;
|
||||
noMaps++;
|
||||
ESP_LOGI(TAG, "Segment %d: map to %X size %X", i, shdr->load_addr, shdr->data_len);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Segment %d: ignore (addr %X) size %X", i, shdr->load_addr, shdr->data_len);
|
||||
}
|
||||
int l=(shdr->data_len+3)&(~3);
|
||||
p+=l;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Unmap");
|
||||
appfsBlMunmap();
|
||||
appfsBlMapRegions(file_handle, mapRegions, noMaps);
|
||||
|
||||
ESP_LOGD(TAG, "start: 0x%08x", entry_addr);
|
||||
typedef void (*entry_t)(void);
|
||||
entry_t entry = ((entry_t) entry_addr);
|
||||
(*entry)();
|
||||
}
|
||||
|
||||
|
||||
//Before the app is started, the bootloader manually sets up the cache. We can't easily intercept
|
||||
//that in order to do the transformation from fake partition offsets to appfs file contents,
|
||||
//however the bootloader does have a call that it calls just before it starts up the app. We hook
|
||||
//that here, manually set the cache regions to the actual app.
|
||||
IRAM_ATTR void __wrap_bootloader_console_deinit() {
|
||||
if (file_handle!=APPFS_INVALID_FD) {
|
||||
mmap_and_start_app();
|
||||
}
|
||||
//Actual partition selected. Simply call the actual function.
|
||||
__real_bootloader_console_deinit();
|
||||
}
|
||||
|
||||
|
||||
//These functions are used by appfs to access the flash: these should always use unwrapped calls.
|
||||
IRAM_ATTR const void* appfs_bootloader_mmap(uint32_t src_addr, uint32_t size) {
|
||||
return __real_bootloader_mmap(src_addr, size);
|
||||
}
|
||||
|
||||
IRAM_ATTR void appfs_bootloader_munmap(const void *mapping) {
|
||||
return __real_bootloader_munmap(mapping);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
/*
|
||||
The appfs wrapper layer wraps (using thr gcc linker wrapping function, see the CMakeFiles.txt
|
||||
file in this directory) the calls that the rest of the bootloader uses, and maps accesses to
|
||||
the appfs partition to transparently map to access to the selected appfs file instead.
|
||||
*/
|
||||
|
||||
//Initialize the wrapper. Handle is a handle to the appfs file, part_start and part_size
|
||||
//must refer to the offset and the size of the appfs partition.
|
||||
void appfs_wrapper_init(appfs_handle_t handle, size_t part_start, size_t part_size);
|
||||
|
||||
//Un-initialize the wrapper. Flash access will always access raw flash after this.
|
||||
void appfs_wrapper_deinit();
|
||||
|
||||
#endif
|
138
factory_test/bootloader_components/main/bootloader_start.c
Normal file
138
factory_test/bootloader_components/main/bootloader_start.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_log.h"
|
||||
#include "bootloader_init.h"
|
||||
#include "bootloader_utility.h"
|
||||
#include "bootloader_common.h"
|
||||
#include "appfs.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "appfs_flashfunctions_wrapper.h"
|
||||
|
||||
static const char *TAG="bootloader";
|
||||
|
||||
//Copied from kchal, which we don't want to link inhere.
|
||||
//See 8bkc-hal/kchal.c for explanation of the bits in the store0 register
|
||||
static int appfs_get_new_app() {
|
||||
uint32_t r=REG_READ(RTC_CNTL_STORE0_REG);
|
||||
ESP_LOGI(TAG, "RTC store0 reg: %x", r);
|
||||
if ((r&0xFF000000)!=0xA5000000) return -1;
|
||||
return r&0xff;
|
||||
}
|
||||
|
||||
//Find the position/size of the appfs partition
|
||||
static bool find_appfs_part(size_t *pos, size_t *len) {
|
||||
const esp_partition_info_t *partitions = bootloader_mmap(ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
|
||||
if (!partitions) {
|
||||
ESP_LOGE(TAG, "bootloader_mmap(0x%x, 0x%x) failed", ESP_PARTITION_TABLE_OFFSET, ESP_PARTITION_TABLE_MAX_LEN);
|
||||
return false;
|
||||
}
|
||||
ESP_LOGD(TAG, "mapped partition table 0x%x at 0x%x", ESP_PARTITION_TABLE_OFFSET, (intptr_t)partitions);
|
||||
|
||||
int num_partitions;
|
||||
esp_err_t err = esp_partition_table_verify(partitions, true, &num_partitions);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to verify partition table");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found=false;
|
||||
for (int i = 0; i < num_partitions; i++) {
|
||||
const esp_partition_info_t *partition = &partitions[i];
|
||||
if (partition->type==APPFS_PART_TYPE && partition->subtype==APPFS_PART_SUBTYPE) {
|
||||
*pos=partition->pos.offset;
|
||||
*len=partition->pos.size;
|
||||
found=true;
|
||||
}
|
||||
}
|
||||
|
||||
bootloader_munmap(partitions);
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* We arrive here after the ROM bootloader finished loading this second stage bootloader from flash.
|
||||
* The hardware is mostly uninitialized, flash cache is down and the app CPU is in reset.
|
||||
* We do have a stack, so we can do the initialization in C.
|
||||
*/
|
||||
void __attribute__((noreturn)) call_start_cpu0(void)
|
||||
{
|
||||
// Hardware initialization
|
||||
if (bootloader_init() != ESP_OK) {
|
||||
bootloader_reset();
|
||||
}
|
||||
|
||||
bootloader_state_t bs = {0};
|
||||
if (!bootloader_utility_load_partition_table(&bs)) {
|
||||
ESP_LOGE(TAG, "load partition table error!");
|
||||
bootloader_reset();
|
||||
}
|
||||
|
||||
size_t appfs_pos, appfs_len;
|
||||
if (!find_appfs_part(&appfs_pos, &appfs_len)) {
|
||||
ESP_LOGE(TAG, "No appfs found!");
|
||||
goto error;
|
||||
}
|
||||
|
||||
//We have an appfs
|
||||
ESP_LOGI(TAG, "AppFs found @ offset 0x%X", appfs_pos);
|
||||
esp_err_t err=appfsBlInit(appfs_pos, appfs_len);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "AppFs initialization failed");
|
||||
appfsBlDeinit();
|
||||
goto error;
|
||||
}
|
||||
ESP_LOGI(TAG, "AppFs initialized");
|
||||
|
||||
int app=appfs_get_new_app();
|
||||
appfs_handle_t handle=0;
|
||||
if (app<0) {
|
||||
//Load default app
|
||||
handle=appfsOpen("chooser.app");
|
||||
} else {
|
||||
handle=app;
|
||||
}
|
||||
if (handle==APPFS_INVALID_FD) {
|
||||
ESP_LOGE(TAG, "Couldn't open app (%d)!", app);
|
||||
appfsBlDeinit();
|
||||
goto error;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Wrapping flash functions and booting app...");
|
||||
appfs_wrapper_init(handle, appfs_pos, appfs_len);
|
||||
//Note that the rest of the bootloader code has no clue about appfs, and as such won't try
|
||||
//to boot it. We 'fix' that by chucking the appfs partition (which is now wrapped so the rest
|
||||
//of the bootloader reads from the selected file when it thinks it loads from the app) into
|
||||
//the top OTA slot.
|
||||
bs.ota[0].offset=appfs_pos;
|
||||
bs.ota[0].size=appfs_len;
|
||||
bs.app_count=1;
|
||||
//And bingo bango, we can now boot from appfs as if it is the first ota partition.
|
||||
bootloader_utility_load_boot_image(&bs, 0);
|
||||
//Still here? Must be an error.
|
||||
error:
|
||||
//Try to fallback to factory part
|
||||
bootloader_utility_load_boot_image(&bs, -1);
|
||||
|
||||
ESP_LOGE(TAG, "Bootloader end");
|
||||
bootloader_reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Return global reent struct if any newlib functions are linked to bootloader
|
||||
struct _reent *__getreent(void)
|
||||
{
|
||||
return _GLOBAL_REENT;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,5 +1,6 @@
|
|||
idf_component_register(
|
||||
INCLUDE_DIRS "include"
|
||||
SRCS "appfs.c"
|
||||
REQUIRES spi_flash
|
||||
)
|
||||
|
||||
idf_component_register(SRC_DIRS .
|
||||
REQUIRES log spi_flash bootloader_support
|
||||
INCLUDE_DIRS . )
|
||||
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE -DPROJECT_NAME="${CMAKE_PROJECT_NAME}")
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
Theory of operation:
|
||||
An appfs filesystem is meant to store executable applications (=ESP32 programs) alongside other
|
||||
|
@ -58,13 +49,13 @@ is implemented as a singleton.
|
|||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <alloca.h>
|
||||
#include "esp32/rom/crc.h"
|
||||
#include "esp32/rom/cache.h"
|
||||
#include <rom/crc.h>
|
||||
#include "esp_spi_flash.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_err.h"
|
||||
#include "appfs.h"
|
||||
#include "rom/cache.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
|
||||
|
@ -177,7 +168,9 @@ static esp_err_t findActiveMeta() {
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
IRAM_ATTR
|
||||
#endif
|
||||
static int appfsGetFirstPageFor(const char *filename) {
|
||||
for (int j=0; j<APPFS_PAGES; j++) {
|
||||
if (appfsMeta[appfsActiveMeta].page[j].used==APPFS_USE_DATA && strcmp(appfsMeta[appfsActiveMeta].page[j].name, filename)==0) {
|
||||
|
@ -241,19 +234,34 @@ size_t appfsGetFreeMem() {
|
|||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
|
||||
#include "bootloader_flash.h"
|
||||
/*
|
||||
Note that IRAM_ATTR is used here to make sure the functions that are used when/after the app loadable
|
||||
segments are loaded, won't be overwritten. The IRAM_ATTR in the bootloader code dumps the function
|
||||
in the loader segment instead of in random IRAM.
|
||||
*/
|
||||
|
||||
#include "bootloader_flash_priv.h"
|
||||
#include "soc/soc.h"
|
||||
#include "soc/cpu.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "soc/rtc.h"
|
||||
#include "soc/dport_reg.h"
|
||||
|
||||
//These can be overridden if we need a custom implementation of bootloader_mmap/munmap.
|
||||
IRAM_ATTR __attribute__ ((weak)) const void *appfs_bootloader_mmap(uint32_t src_addr, uint32_t size) {
|
||||
return bootloader_mmap(src_addr, size);
|
||||
}
|
||||
|
||||
IRAM_ATTR __attribute__ ((weak)) void appfs_bootloader_munmap(const void *mapping) {
|
||||
bootloader_munmap(mapping);
|
||||
}
|
||||
|
||||
esp_err_t appfsBlInit(uint32_t offset, uint32_t len) {
|
||||
//Compile-time sanity check on size of structs
|
||||
_Static_assert(sizeof(AppfsHeader)==APPFS_META_DESC_SZ, "sizeof AppfsHeader != 128bytes");
|
||||
_Static_assert(sizeof(AppfsPageInfo)==APPFS_META_DESC_SZ, "sizeof AppfsPageInfo != 128bytes");
|
||||
_Static_assert(sizeof(AppfsMeta)==APPFS_META_SZ, "sizeof AppfsMeta != APPFS_META_SZ");
|
||||
//Map meta page
|
||||
appfsMeta=bootloader_mmap(offset, APPFS_SECTOR_SZ);
|
||||
appfsMeta=appfs_bootloader_mmap(offset, APPFS_SECTOR_SZ);
|
||||
if (!appfsMeta) return ESP_ERR_NOT_FOUND;
|
||||
if (findActiveMeta()!=ESP_OK) {
|
||||
//No valid metadata half-sector found. Initialize the first sector.
|
||||
|
@ -266,15 +274,15 @@ esp_err_t appfsBlInit(uint32_t offset, uint32_t len) {
|
|||
}
|
||||
|
||||
void appfsBlDeinit() {
|
||||
bootloader_munmap(appfsMeta);
|
||||
ESP_LOGI(TAG, "Appfs deinit");
|
||||
appfs_bootloader_munmap(appfsMeta);
|
||||
}
|
||||
|
||||
#define MMU_BLOCK0_VADDR 0x3f400000
|
||||
#define MMU_BLOCK50_VADDR 0x3f720000
|
||||
#define MMU_FLASH_MASK 0xffff0000
|
||||
#define MMU_BLOCK_SIZE 0x00010000
|
||||
|
||||
esp_err_t appfsBlMapRegions(int fd, AppfsBlRegionToMap *regions, int noRegions) {
|
||||
IRAM_ATTR esp_err_t appfsBlMapRegions(int fd, AppfsBlRegionToMap *regions, int noRegions) {
|
||||
if (appfsMeta==NULL) ESP_LOGE(TAG, "EEK! appfsBlMapRegions called without meta mapped");
|
||||
uint8_t pages[255];
|
||||
int pageCt=0;
|
||||
int page=fd;
|
||||
|
@ -283,7 +291,7 @@ esp_err_t appfsBlMapRegions(int fd, AppfsBlRegionToMap *regions, int noRegions)
|
|||
page=appfsMeta[appfsActiveMeta].page[page].next;
|
||||
} while (page!=0);
|
||||
//Okay, we have our info.
|
||||
bootloader_munmap(appfsMeta);
|
||||
appfs_bootloader_munmap(appfsMeta);
|
||||
|
||||
Cache_Read_Disable( 0 );
|
||||
Cache_Flush( 0 );
|
||||
|
@ -314,9 +322,10 @@ esp_err_t appfsBlMapRegions(int fd, AppfsBlRegionToMap *regions, int noRegions)
|
|||
return ESP_OK;
|
||||
}
|
||||
|
||||
void* appfsBlMmap(int fd) {
|
||||
IRAM_ATTR void* appfsBlMmap(int fd) {
|
||||
//We want to mmap() the pages of the file into memory. However, to do that we need to kill the mmap for the
|
||||
//meta info. To do this, we collect the pages before unmapping the meta info.
|
||||
if (appfsMeta==NULL) ESP_LOGE(TAG, "EEK! appfsBlMmap called without meta mapped");
|
||||
uint8_t pages[255];
|
||||
int pageCt=0;
|
||||
int page=fd;
|
||||
|
@ -324,7 +333,7 @@ void* appfsBlMmap(int fd) {
|
|||
pages[pageCt++]=page;
|
||||
page=appfsMeta[appfsActiveMeta].page[page].next;
|
||||
} while (page!=0);
|
||||
ESP_LOGI(TAG, "File %d has %d pages.", fd, pageCt);
|
||||
// ESP_LOGI(TAG, "File %d has %d pages.", fd, pageCt);
|
||||
|
||||
if (pageCt>50) {
|
||||
ESP_LOGE(TAG, "appfsBlMmap: file too big to mmap");
|
||||
|
@ -332,14 +341,14 @@ void* appfsBlMmap(int fd) {
|
|||
}
|
||||
|
||||
//Okay, we have our info.
|
||||
bootloader_munmap(appfsMeta);
|
||||
appfs_bootloader_munmap(appfsMeta);
|
||||
//Bootloader_mmap only allows mapping of one consecutive memory range. We need more than that, so we essentially
|
||||
//replicate the function here.
|
||||
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
for (int i=0; i<pageCt; i++) {
|
||||
ESP_LOGI(TAG, "Mapping flash addr %X to mem addr %X for page %d", appfsPartOffset+((pages[i]+1)*APPFS_SECTOR_SZ), MMU_BLOCK0_VADDR+(i*APPFS_SECTOR_SZ), pages[i]);
|
||||
// ESP_LOGI(TAG, "Mapping flash addr %X to mem addr %X for page %d", appfsPartOffset+((pages[i]+1)*APPFS_SECTOR_SZ), MMU_BLOCK0_VADDR+(i*APPFS_SECTOR_SZ), pages[i]);
|
||||
int e = cache_flash_mmu_set(0, 0, MMU_BLOCK0_VADDR+(i*APPFS_SECTOR_SZ),
|
||||
appfsPartOffset+((pages[i]+1)*APPFS_SECTOR_SZ), 64, 1);
|
||||
if (e != 0) {
|
||||
|
@ -352,13 +361,13 @@ void* appfsBlMmap(int fd) {
|
|||
return (void *)(MMU_BLOCK0_VADDR);
|
||||
}
|
||||
|
||||
void appfsBlMunmap() {
|
||||
IRAM_ATTR void appfsBlMunmap() {
|
||||
/* Full MMU reset */
|
||||
Cache_Read_Disable(0);
|
||||
Cache_Flush(0);
|
||||
mmu_init(0);
|
||||
//Map meta page
|
||||
appfsMeta=bootloader_mmap(appfsPartOffset, APPFS_SECTOR_SZ);
|
||||
appfsMeta=appfs_bootloader_mmap(appfsPartOffset, APPFS_SECTOR_SZ);
|
||||
}
|
||||
|
||||
#else //so if !BOOTLOADER_BUILD
|
||||
|
|
|
@ -1,13 +1,5 @@
|
|||
/*
|
||||
* ----------------------------------------------------------------------------
|
||||
* "THE BEER-WARE LICENSE" (Revision 42):
|
||||
* Jeroen Domburg <jeroen@spritesmods.com> wrote this file. As long as you retain
|
||||
* this notice you can do whatever you want with this stuff. If we meet some day,
|
||||
* and you think this stuff is worth it, you can buy me a beer in return.
|
||||
* ----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#ifndef APPFS_H
|
||||
#define APPFS_H
|
||||
|
||||
#include "esp_err.h"
|
||||
#include <stdint.h>
|
||||
|
@ -230,7 +222,7 @@ void appfsDump();
|
|||
|
||||
|
||||
#ifdef BOOTLOADER_BUILD
|
||||
#include "bootloader_flash.h"
|
||||
#include "bootloader_flash_priv.h"
|
||||
|
||||
/**
|
||||
* @brief Appfs bootloader support: struct to hold a region of a file to map
|
||||
|
@ -287,3 +279,6 @@ esp_err_t appfsBlMapRegions(int fd, AppfsBlRegionToMap *regions, int noRegions);
|
|||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
|
@ -1,9 +0,0 @@
|
|||
#
|
||||
# Component Makefile. By default,
|
||||
# this will take the sources in this directory, compile them and link them into
|
||||
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
|
||||
# please read the SDK documents if you need to do this.
|
||||
#
|
||||
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
|
|
@ -3,7 +3,6 @@
|
|||
#include <esp_log.h>
|
||||
#include <driver/gpio.h>
|
||||
#include "managed_i2c.h"
|
||||
#include "logo.h"
|
||||
#include "sdcard.h"
|
||||
|
||||
static const char *TAG = "hardware";
|
||||
|
@ -114,20 +113,13 @@ esp_err_t hardware_init() {
|
|||
dev_ili9341.spi_speed = 60000000; // 60MHz
|
||||
dev_ili9341.spi_max_transfer_size = SPI_MAX_TRANSFER_SIZE;
|
||||
dev_ili9341.callback = NULL; // Callback for changing LCD mode between ESP32 and FPGA
|
||||
|
||||
|
||||
res = ili9341_init(&dev_ili9341);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Initializing LCD failed");
|
||||
return res;
|
||||
}
|
||||
|
||||
// Hack: show logo while the other hardware components initialize
|
||||
res = ili9341_write(&dev_ili9341, logo);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to write logo to LCD");
|
||||
return res;
|
||||
}
|
||||
|
||||
// BNO055 sensor on system I2C bus
|
||||
|
||||
res = bno055_init(&dev_bno055, I2C_BUS_SYS, BNO055_ADDR, GPIO_INT_BNO055, true);
|
||||
|
@ -135,8 +127,6 @@ esp_err_t hardware_init() {
|
|||
ESP_LOGE(TAG, "Initializing BNO055 failed");
|
||||
return res;
|
||||
}
|
||||
|
||||
//res = mount_sd(SD_CMD, SD_CLK, SD_D0, SD_PWR, "/sd", false, 5);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
12807
factory_test/main/logo.h
12807
factory_test/main/logo.h
File diff suppressed because it is too large
Load diff
|
@ -30,43 +30,47 @@ bno055_vector_t rotation_offset = {.x = 0, .y = 0, .z = 0};
|
|||
|
||||
bno055_vector_t acceleration, magnetism, orientation, rotation, linear_acceleration, gravity;
|
||||
|
||||
uint8_t selected_item = 0;
|
||||
|
||||
void button_handler(uint8_t pin, bool value) {
|
||||
switch(pin) {
|
||||
case PCA9555_PIN_BTN_JOY_LEFT:
|
||||
printf("Joystick horizontal %s\n", value ? "left" : "center");
|
||||
ili9341_set_partial_scanning(ili9341, 60, ILI9341_WIDTH - 61);
|
||||
//ili9341_set_partial_scanning(ili9341, 60, ILI9341_WIDTH - 61);
|
||||
break;
|
||||
case PCA9555_PIN_BTN_JOY_PRESS:
|
||||
printf("Joystick %s\n", value ? "pressed" : "released");
|
||||
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);
|
||||
//ili9341_set_partial_scanning(ili9341, 0, ILI9341_WIDTH / 2 - 1);
|
||||
if (value) selected_item += 1;
|
||||
break;
|
||||
case PCA9555_PIN_BTN_JOY_UP:
|
||||
printf("Joy vertical %s\n", value ? "up" : "center");
|
||||
ili9341_set_partial_scanning(ili9341, ILI9341_WIDTH / 2, ILI9341_WIDTH - 1);
|
||||
//ili9341_set_partial_scanning(ili9341, ILI9341_WIDTH / 2, ILI9341_WIDTH - 1);
|
||||
if (value) selected_item -= 1;
|
||||
break;
|
||||
case PCA9555_PIN_BTN_JOY_RIGHT:
|
||||
printf("Joy horizontal %s\n", value ? "right" : "center");
|
||||
ili9341_set_partial_scanning(ili9341, 0, ILI9341_WIDTH - 1);
|
||||
//ili9341_set_partial_scanning(ili9341, 0, ILI9341_WIDTH - 1);
|
||||
break;
|
||||
case PCA9555_PIN_BTN_HOME:
|
||||
printf("Home button %s\n", value ? "pressed" : "released");
|
||||
ili9341_set_tearing_effect_line(ili9341, true);
|
||||
//ili9341_set_tearing_effect_line(ili9341, true);
|
||||
break;
|
||||
case PCA9555_PIN_BTN_MENU:
|
||||
printf("Menu button %s\n", value ? "pressed" : "released");
|
||||
ili9341_set_tearing_effect_line(ili9341, false);
|
||||
//ili9341_set_tearing_effect_line(ili9341, false);
|
||||
break;
|
||||
case PCA9555_PIN_BTN_START: {
|
||||
printf("Start button %s\n", value ? "pressed" : "released");
|
||||
ili9341_set_idle_mode(ili9341, true);
|
||||
//ili9341_set_idle_mode(ili9341, true);
|
||||
break;
|
||||
}
|
||||
case PCA9555_PIN_BTN_SELECT: {
|
||||
printf("Select button %s\n", value ? "pressed" : "released");
|
||||
ili9341_set_idle_mode(ili9341, false);
|
||||
//ili9341_set_idle_mode(ili9341, false);
|
||||
break;
|
||||
}
|
||||
case PCA9555_PIN_BTN_BACK:
|
||||
|
@ -174,42 +178,78 @@ void bno055_task(BNO055* bno055) {
|
|||
}
|
||||
}
|
||||
|
||||
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_simple_line(buffer, pax_col_rgb(255,0,0), 0, 16, 320, 16);
|
||||
pax_draw_text(buffer, pax_col_rgb(255,255,0), PAX_FONT_DEFAULT, 0.2, 0, 0, "Hello world!");
|
||||
//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");
|
||||
draw_menu_item(buffer, 0, (selected_item == 0), "Test 1");
|
||||
draw_menu_item(buffer, 1, (selected_item == 1), "Hey, this almost looks like");
|
||||
draw_menu_item(buffer, 2, (selected_item == 2), "a menu list?!");
|
||||
draw_menu_item(buffer, 3, (selected_item == 3), "Woooow!");
|
||||
draw_menu_item(buffer, 4, (selected_item == 4), "Blahblah");
|
||||
draw_menu_item(buffer, 5, (selected_item == 5), "8=======D~~~~~~");
|
||||
draw_menu_item(buffer, 6, (selected_item == 6), "Does this fit on the screen or not?");
|
||||
pax_pop_2d(buffer);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t graphics_task(pax_buf_t* buffer, ILI9341* ili9341, uint8_t* framebuffer) {
|
||||
uint64_t millis = esp_timer_get_time() / 1000;
|
||||
pax_background(buffer, 0x000000);
|
||||
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 = millis / 3000.0 * M_PI;//0;//
|
||||
float a1 = fmodf(a0, M_PI * 4) - M_PI * 2;//rotation.y * (M_PI / 180.0);//
|
||||
pax_draw_arc(buffer, color0, 0, 0, 1, a0, a0 + a1);
|
||||
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_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);
|
||||
//driver_framebuffer_print(NULL, "Hello world", 0, 0, 1, 1, 0xFF00FF, &ocra_22pt7b);
|
||||
return ili9341_write(ili9341, framebuffer);
|
||||
}
|
||||
|
||||
|
@ -418,6 +458,9 @@ void appfs_store_app(void) {
|
|||
ESP_LOGE(TAG, "Failed to load application into RAM");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Application size %d", app_size);
|
||||
|
||||
res = appfsCreateFile("gnuboy", app_size, &handle);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to create file on AppFS (%d)", res);
|
||||
|
@ -448,6 +491,7 @@ void appfs_boot_app(int fd) {
|
|||
}
|
||||
|
||||
void appfs_test(bool sdcard_ready) {
|
||||
appfs_store_app();
|
||||
appfsDump();
|
||||
|
||||
// Try booting the app from appfs
|
||||
|
@ -460,7 +504,7 @@ void appfs_test(bool sdcard_ready) {
|
|||
appfs_test(false); // Recursive, but who cares :D
|
||||
}
|
||||
} else {
|
||||
ESP_LOGE(TAG, "booting gnuboy from appfs");
|
||||
ESP_LOGE(TAG, "booting gnuboy from appfs (%d)", fd);
|
||||
appfs_boot_app(fd);
|
||||
}
|
||||
}
|
||||
|
@ -468,18 +512,6 @@ void appfs_test(bool sdcard_ready) {
|
|||
void app_main(void) {
|
||||
esp_err_t res;
|
||||
|
||||
res = hardware_init();
|
||||
if (res != ESP_OK) {
|
||||
printf("Failed to initialize hardware!\n");
|
||||
restart();
|
||||
}
|
||||
|
||||
ili9341 = get_ili9341();
|
||||
ice40 = get_ice40();
|
||||
bno055 = get_bno055();
|
||||
|
||||
print_chip_info();
|
||||
|
||||
uint8_t* framebuffer = heap_caps_malloc(ILI9341_BUFFER_SIZE, MALLOC_CAP_8BIT);
|
||||
if (framebuffer == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to allocate framebuffer");
|
||||
|
@ -489,11 +521,21 @@ void app_main(void) {
|
|||
|
||||
pax_buf_t buffer;
|
||||
pax_buf_init(&buffer, framebuffer, ILI9341_WIDTH, ILI9341_HEIGHT, PAX_BUF_16_565RGB);
|
||||
pax_apply_2d(&buffer, matrix_2d_translate(buffer.width / 2.0, buffer.height / 2.0));
|
||||
pax_apply_2d(&buffer, matrix_2d_scale(50, 50));
|
||||
|
||||
driver_framebuffer_init(framebuffer);
|
||||
|
||||
res = hardware_init();
|
||||
|
||||
if (res != ESP_OK) {
|
||||
printf("Failed to initialize hardware!\n");
|
||||
restart();
|
||||
}
|
||||
|
||||
ili9341 = get_ili9341();
|
||||
ice40 = get_ice40();
|
||||
bno055 = get_bno055();
|
||||
|
||||
//print_chip_info();
|
||||
|
||||
button_init();
|
||||
|
||||
res = appfs_init();
|
||||
|
@ -506,19 +548,22 @@ void app_main(void) {
|
|||
res = mount_sd(SD_CMD, SD_CLK, SD_D0, SD_PWR, "/sd", false, 5);
|
||||
bool sdcard_ready = (res == ESP_OK);
|
||||
|
||||
ili9341_deinit(ili9341);
|
||||
ili9341_select(ili9341, true);
|
||||
|
||||
if (sdcard_ready) {
|
||||
ESP_LOGI(TAG, "SD card mounted");
|
||||
//fpga_test();
|
||||
}
|
||||
|
||||
//appfs_test(sdcard_ready);
|
||||
appfs_test(sdcard_ready);
|
||||
|
||||
//
|
||||
|
||||
while (1) {
|
||||
/*while (1) {
|
||||
bno055_task(bno055);
|
||||
graphics_task(&buffer, ili9341, framebuffer);
|
||||
}
|
||||
}*/
|
||||
/*
|
||||
uint8_t data_out, data_in;
|
||||
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0x9000, 0x4000,
|
||||
otadata, data, ota, 0xd000, 0x2000
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
ota_0, app, ota_0, 0x10000, 1536K
|
||||
ota_1, app, ota_1, , 1536K
|
||||
appfs, 0x43, 3, , 13248K
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0xD000, 0x2000,
|
||||
phy_init, data, phy, 0xF000, 0x1000,
|
||||
factory, app, factory, 0x10000, 512K,
|
||||
appfs, 0x43, 0x3, , 3M,
|
||||
|
|
|
9
factory_test/partitions.csv.bak
Normal file
9
factory_test/partitions.csv.bak
Normal file
|
@ -0,0 +1,9 @@
|
|||
# ESP-IDF Partition Table
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
nvs, data, nvs, 0xA000, 12K,
|
||||
otadata, data, ota, 0xD000, 8K,
|
||||
phy_init, data, phy, 0xF000, 4K,
|
||||
ota_0, 0, ota_0, 0x10000, 1600K,
|
||||
ota_1, 0, ota_1, 0x1A0000, 1600K,
|
||||
appfs, 0x43, 3, 0x330000, 8000K,
|
||||
locfd, data, fat, 0xB00000, 5120K,
|
BIN
factory_test/partitions.ods
Normal file
BIN
factory_test/partitions.ods
Normal file
Binary file not shown.
|
@ -265,7 +265,7 @@ CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
|
|||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x8000
|
||||
CONFIG_PARTITION_TABLE_OFFSET=0x9000
|
||||
CONFIG_PARTITION_TABLE_MD5=y
|
||||
# end of Partition Table
|
||||
|
||||
|
|
Loading…
Reference in a new issue