diff --git a/32blit-pico/blit_launch.cpp b/32blit-pico/blit_launch.cpp index 9f6d2bdca..590b31c66 100644 --- a/32blit-pico/blit_launch.cpp +++ b/32blit-pico/blit_launch.cpp @@ -163,7 +163,7 @@ static uint32_t find_installed_blit(RawMetadata &meta) { return ~0u; } -static bool cleanup_duplicates(RawMetadata &meta, RawTypeMetadata &type_meta, uint32_t new_offset) { +static bool cleanup_duplicates(RawMetadata &meta, uint32_t new_offset) { bool ret = false; for(uint32_t off = 0; off < flash_end;) { auto size = get_installed_file_size(off); @@ -261,7 +261,7 @@ bool launch_file(const char *path) { flash_offset = writer.get_flash_offset(); - cleanup_duplicates(meta, type_meta, flash_offset); + cleanup_duplicates(meta, flash_offset); } else close_file(file); } @@ -456,6 +456,12 @@ bool BlitWriter::write(const uint8_t *buf, uint32_t len) { return true; } +void BlitWriter::cleanup_duplicates() { + auto header = (BlitGameHeader *)(FLASH_BASE + flash_offset); + auto meta = (RawMetadata *)(FLASH_BASE + flash_offset + header->end + 10); + ::cleanup_duplicates(*meta, flash_offset); +} + uint32_t BlitWriter::get_offset() const { return file_offset; } @@ -489,6 +495,11 @@ bool BlitWriter::prepare_write(const uint8_t *buf) { // we can use address translation for this, so flash in any free space flash_offset = find_flash_offset(file_len); } + + if(!flash_offset) { + blit::debugf("Not enough space!"); + return false; + } #endif disable_user_code(); diff --git a/32blit-pico/blit_launch.hpp b/32blit-pico/blit_launch.hpp index 7933e3544..69c203fbc 100644 --- a/32blit-pico/blit_launch.hpp +++ b/32blit-pico/blit_launch.hpp @@ -25,6 +25,8 @@ class BlitWriter final { bool write(const uint8_t *buf, uint32_t len); + void cleanup_duplicates(); + uint32_t get_offset() const; uint32_t get_length() const; uint32_t get_remaining() const; diff --git a/32blit-pico/loader/CMakeLists.txt b/32blit-pico/loader/CMakeLists.txt index 00197c234..473abdc17 100644 --- a/32blit-pico/loader/CMakeLists.txt +++ b/32blit-pico/loader/CMakeLists.txt @@ -10,7 +10,10 @@ else() endif() pico_enable_stdio_uart(blit-loader 1) -pico_enable_stdio_usb(blit-loader 0) +if(NOT BLIT_USB_DRIVER STREQUAL "host") + pico_enable_stdio_usb(blit-loader 1) + target_compile_definitions(blit-loader PRIVATE PICO_STDIO_USB_ENABLE_RESET_VIA_BAUD_RATE=1 PICO_STDIO_USB_RESET_MAGIC_BAUD_RATE=1200 PICO_STDIO_USB_RESET_BOOTSEL_INTERFACE_DISABLE_MASK=0) +endif() pico_add_extra_outputs(blit-loader) diff --git a/32blit-pico/loader/loader.cpp b/32blit-pico/loader/loader.cpp index a8703ab0b..f0c80a063 100644 --- a/32blit-pico/loader/loader.cpp +++ b/32blit-pico/loader/loader.cpp @@ -1,26 +1,76 @@ +#include + #include "32blit.hpp" #include "engine/api_private.hpp" +#include "executable.hpp" + using namespace blit; -void init() { +const char *get_category(const uint8_t *ptr) { + // check headers + auto header = (const BlitGameHeader *)ptr; + + if(header->magic != blit_game_magic) + return nullptr; + + auto metadata_ptr = ptr + header->end; + + if(memcmp(metadata_ptr, "BLITMETA", 8) != 0) + return nullptr; + + // skip straight to the type block + metadata_ptr += 10 + sizeof(RawMetadata); + + if(memcmp(metadata_ptr, "BLITTYPE", 8) != 0) + return nullptr; + + // get the category from the type block + auto type_meta = (const RawTypeMetadata *)(metadata_ptr + 8); + + return type_meta->category; +} + +static bool try_launch(bool launcher) { bool done = false; - // launch the first thing we find - // TODO: find launcher - api.list_installed_games([&done](const uint8_t *ptr, uint32_t block, uint32_t size){ + + api.list_installed_games([&done, launcher](const uint8_t *ptr, uint32_t block, uint32_t size){ if(!done) { + + if(launcher) { + // check category + auto category = get_category(ptr); + + if(!category || strcmp(category, "launcher") != 0) + return; + } + auto path = "flash:/" + std::to_string(block) + ".blit"; done = api.launch(path.c_str()); } }); + return done; +} + +void init() { + bool done = false; + + // try to find and launch a launcher + done = try_launch(true); + if(!done) { // fall back to launcher in storage // TODO: auto-update if(file_exists("launcher.blit")) { - api.launch("launcher.blit"); + done = api.launch("launcher.blit"); } } + + if(!done) { + // as a last resort launch the first thing we find + try_launch(false); + } } void render(uint32_t time) { diff --git a/32blit-pico/usb.cpp b/32blit-pico/usb.cpp index 12057373f..d8233742e 100644 --- a/32blit-pico/usb.cpp +++ b/32blit-pico/usb.cpp @@ -150,8 +150,10 @@ class CDCProgCommand final : public CDCCommand { // got full page or final part of file auto buf_off = buf.get_offset(); if(buf_off == FLASH_PAGE_SIZE || buf_off == writer.get_remaining()) { - if(!writer.write(buf.get_data(), buf_off)) + if(!writer.write(buf.get_data(), buf_off)) { + cdc_command_progress(nullptr, 0, 0); // clear progress return Status::Error; + } cdc_command_progress(nullptr, writer.get_offset(), writer.get_length()); @@ -162,6 +164,8 @@ class CDCProgCommand final : public CDCCommand { if(writer.get_remaining() == 0) { cdc_command_progress(nullptr, 0, 0); // clear progress + writer.cleanup_duplicates(); + // send response auto block = writer.get_flash_offset() >> 16; uint8_t res_data[]{'3', '2', 'B', 'L', '_', '_', 'O', 'K', uint8_t(block), uint8_t(block >> 8)}; @@ -257,6 +261,7 @@ class CDCSaveCommand final : public CDCCommand { auto written = blit::api.write_file(file, file_offset, read, (const char *)buf.get_data()); if(written != read) { blit::api.close_file(file); + cdc_command_progress(nullptr, 0, 0); // clear progress return Status::Error; }