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;
}
}
}
}
}