260 lines
5.8 KiB
C++
260 lines
5.8 KiB
C++
#include "cardslot.h"
|
|
#include "devicelib.h"
|
|
#include "menu.h"
|
|
|
|
#include <hardware/clocks.h>
|
|
#include <pico/binary_info.h>
|
|
#include <pico/bootrom.h>
|
|
#include <pico/stdlib.h>
|
|
#include <tusb.h>
|
|
|
|
using namespace lib;
|
|
|
|
namespace
|
|
{
|
|
|
|
Display display(DISPLAY_SCK, DISPLAY_TX, DISPLAY_CS, DISPLAY_DC,
|
|
100 * 1000 * 1000);
|
|
Flash flash(FLASH_SCK, FLASH_TX, FLASH_RX, FLASH_CS, 25 * 1000 * 1000);
|
|
|
|
enum class RX
|
|
{
|
|
WAITING,
|
|
GETTING_CMC,
|
|
GETTING_COLORS,
|
|
GETTING_NAME_LENGTH,
|
|
GETTING_NAME,
|
|
GETTING_IMAGE
|
|
};
|
|
|
|
struct
|
|
{
|
|
struct
|
|
{
|
|
uint8_t buffer[32];
|
|
uint8_t size;
|
|
uint8_t written;
|
|
} name;
|
|
|
|
uint8_t cmc;
|
|
uint8_t colors;
|
|
|
|
struct
|
|
{
|
|
size_t written = 0;
|
|
uint16_t page_index = 0;
|
|
} image;
|
|
|
|
RX state = RX::WAITING;
|
|
|
|
int32_t card_index = 0;
|
|
} rx;
|
|
|
|
volatile uint8_t debug_requested = false;
|
|
|
|
constexpr int MS_BUTTON_TIMEOUT = 500;
|
|
|
|
}
|
|
|
|
int main()
|
|
{
|
|
gpio_set_function(FLASH_IO_2, GPIO_FUNC_SIO);
|
|
gpio_set_function(FLASH_IO_3, GPIO_FUNC_SIO);
|
|
|
|
gpio_set_dir(FLASH_IO_2, GPIO_OUT);
|
|
gpio_set_dir(FLASH_IO_3, GPIO_OUT);
|
|
|
|
gpio_put(FLASH_IO_2, 1);
|
|
gpio_put(FLASH_IO_3, 1);
|
|
|
|
gpio_set_function(BUTTON_LEFT, GPIO_FUNC_SIO);
|
|
gpio_set_function(BUTTON_MIDDLE, GPIO_FUNC_SIO);
|
|
gpio_set_function(BUTTON_RIGHT, GPIO_FUNC_SIO);
|
|
|
|
gpio_set_dir(BUTTON_LEFT, GPIO_IN);
|
|
gpio_set_dir(BUTTON_MIDDLE, GPIO_IN);
|
|
gpio_set_dir(BUTTON_RIGHT, GPIO_IN);
|
|
|
|
gpio_pull_up(BUTTON_LEFT);
|
|
gpio_pull_up(BUTTON_MIDDLE);
|
|
gpio_pull_up(BUTTON_RIGHT);
|
|
|
|
tusb_rhport_init_t dev_init
|
|
= { .role = TUSB_ROLE_DEVICE, .speed = TUSB_SPEED_AUTO };
|
|
tud_init(0);
|
|
|
|
uint16_t card_index = 0;
|
|
absolute_time_t last_press = get_absolute_time();
|
|
absolute_time_t previous_time = last_press;
|
|
|
|
menus::push_menu<menus::ManaMenu>(display, flash);
|
|
|
|
while (true)
|
|
{
|
|
absolute_time_t current = get_absolute_time();
|
|
float dt = absolute_time_diff_us(previous_time, current) / 1000000.0f;
|
|
|
|
if (!gpio_get(BUTTON_LEFT)
|
|
&& absolute_time_diff_us(last_press, current)
|
|
> 1000 * MS_BUTTON_TIMEOUT)
|
|
{
|
|
menus::get_current_menu()->onLeftPressed();
|
|
|
|
last_press = current;
|
|
}
|
|
|
|
if (!gpio_get(BUTTON_MIDDLE)
|
|
&& absolute_time_diff_us(last_press, current)
|
|
> 1000 * MS_BUTTON_TIMEOUT)
|
|
{
|
|
menus::get_current_menu()->onMenuPressed();
|
|
|
|
last_press = current;
|
|
}
|
|
|
|
if (!gpio_get(BUTTON_RIGHT)
|
|
&& absolute_time_diff_us(last_press, current)
|
|
> 1000 * MS_BUTTON_TIMEOUT)
|
|
{
|
|
menus::get_current_menu()->onRightPressed();
|
|
|
|
last_press = current;
|
|
}
|
|
|
|
tud_task();
|
|
menus::get_current_menu()->onTick(dt);
|
|
|
|
previous_time = current;
|
|
|
|
if (debug_requested > 0 && tud_vendor_write_available() > 0)
|
|
{
|
|
flash.read_page((debug_requested - 1) * CardSlot::TOTAL_PAGE_COUNT);
|
|
tud_vendor_write(flash.page(), Flash::Page::SIZE);
|
|
tud_vendor_write_flush();
|
|
sleep_ms(500);
|
|
debug_requested -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
void tud_vendor_rx_cb(uint8_t itf, const uint8_t* buffer, uint16_t bufsize)
|
|
{
|
|
for (size_t read = 0; read < bufsize;)
|
|
{
|
|
if (rx.state == RX::WAITING)
|
|
{
|
|
// special command to mark all as unused
|
|
if (buffer[0] == 0x42)
|
|
{
|
|
for (int i = 0; i < CardSlot::MAX_CARDS; i++)
|
|
{
|
|
CardSlot slot(flash, i);
|
|
slot.mark_unused(flash);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// special command to debug flash
|
|
if (buffer[0] == 0x69)
|
|
{
|
|
debug_requested = CardSlot::MAX_CARDS;
|
|
|
|
return;
|
|
}
|
|
|
|
// special command to reset to bootsel
|
|
if (buffer[0] == 0x99)
|
|
{
|
|
rom_reset_usb_boot(0, 0);
|
|
}
|
|
|
|
rx.state = RX::GETTING_CMC;
|
|
|
|
rx.card_index = CardSlot::get_unused(flash);
|
|
}
|
|
else if (rx.state == RX::GETTING_CMC)
|
|
{
|
|
rx.state = RX::GETTING_COLORS;
|
|
|
|
rx.cmc = buffer[read] > 20 ? 20 : buffer[read];
|
|
|
|
read += 1;
|
|
}
|
|
else if (rx.state == RX::GETTING_COLORS)
|
|
{
|
|
rx.state = RX::GETTING_NAME_LENGTH;
|
|
|
|
rx.colors = buffer[read] & 0b11111;
|
|
|
|
read += 1;
|
|
}
|
|
else if (rx.state == RX::GETTING_NAME_LENGTH)
|
|
{
|
|
rx.state = RX::GETTING_NAME;
|
|
|
|
rx.name.size = buffer[read] > 32 ? 32 : buffer[read];
|
|
rx.name.written = 0;
|
|
|
|
read += 1;
|
|
}
|
|
else if (rx.state == RX::GETTING_NAME)
|
|
{
|
|
size_t copy_size = bufsize - read < rx.name.size - rx.name.written
|
|
? bufsize - read
|
|
: rx.name.size - rx.name.written;
|
|
|
|
memcpy(rx.name.buffer + rx.name.written, buffer + read, copy_size);
|
|
read += copy_size;
|
|
rx.name.written += copy_size;
|
|
|
|
if (rx.name.written == rx.name.size)
|
|
{
|
|
rx.state = RX::GETTING_IMAGE;
|
|
|
|
rx.image.written = 0;
|
|
rx.image.page_index
|
|
= CardSlot(flash, rx.card_index).get_image_start_page_index();
|
|
|
|
if (rx.card_index >= 0)
|
|
{
|
|
CardSlot slot(flash, rx.card_index);
|
|
slot.erase(flash);
|
|
slot.set_name(rx.name.buffer, rx.name.size);
|
|
slot.set_cmc(rx.cmc);
|
|
slot.set_colors(rx.colors);
|
|
slot.save_data(flash);
|
|
}
|
|
}
|
|
}
|
|
else if (rx.state == RX::GETTING_IMAGE)
|
|
{
|
|
size_t copy_size = bufsize - read < Flash::Page::SIZE - rx.image.written
|
|
? bufsize - read
|
|
: Flash::Page::SIZE - rx.image.written;
|
|
|
|
memcpy(flash.page() + rx.image.written, buffer + read, copy_size);
|
|
read += copy_size;
|
|
|
|
rx.image.written += copy_size;
|
|
|
|
if (rx.image.written == 256)
|
|
{
|
|
if (rx.card_index >= 0)
|
|
{
|
|
flash.write_page(rx.image.page_index);
|
|
}
|
|
rx.image.page_index += 1;
|
|
rx.image.written = 0;
|
|
|
|
if (rx.image.page_index
|
|
- CardSlot(flash, rx.card_index).get_image_start_page_index()
|
|
== CardSlot::IMAGE_PAGE_COUNT)
|
|
{
|
|
rx.state = RX::WAITING;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|