card-device-firmware/src/cardslot.cpp

126 lines
3.0 KiB
C++

#include "cardslot.h"
#include <cstring>
CardSlot::CardSlot(lib::Flash& flash, uint16_t card_index) :
card_index(card_index)
{
load_data(flash);
}
uint16_t CardSlot::get_image_start_page_index() const
{
return card_index * TOTAL_PAGE_COUNT + 1;
}
void CardSlot::mark_unused(lib::Flash& flash)
{
flash.read_page(card_index * TOTAL_PAGE_COUNT);
flash.page()[0] &= 0xFE;
flash.write_page(card_index * TOTAL_PAGE_COUNT);
}
void CardSlot::set_name(const uint8_t* name, uint8_t name_length)
{
if (name_length > 32)
{
name_length = 32;
}
memcpy(this->name, name, name_length);
status.name_length = name_length;
}
void CardSlot::save_data(lib::Flash& flash)
{
// if we're saving data, the slot is in use
status.in_use = true;
uint32_t raw_status = (status.in_use << 0) | (status.name_length << 1)
| (status.times_erased << (NAME_BITS + 1));
auto& page = flash.page();
page[0] = (raw_status >> 0) & 0xFF;
page[1] = (raw_status >> 8) & 0xFF;
page[2] = (raw_status >> 16) & 0xFF;
page[3] = (raw_status >> 24) & 0xFF;
memcpy(page + 4, name, status.name_length);
flash.write_page(card_index * TOTAL_PAGE_COUNT);
}
void CardSlot::erase(lib::Flash& flash)
{
// 16 pages per sector, one command erases them all
for (int i = 0; i < TOTAL_PAGE_COUNT; i += 16)
{
flash.erase_sector(card_index * TOTAL_PAGE_COUNT + i);
}
}
bool CardSlot::is_used() const { return status.in_use; }
uint32_t CardSlot::times_erased() const { return status.times_erased; }
const uint8_t* CardSlot::get_name() const { return name; }
uint8_t CardSlot::get_name_length() const { return status.name_length; }
bool CardSlot::operator<=(const CardSlot& other) const
{
return status.times_erased <= other.status.times_erased;
}
bool CardSlot::operator>=(const CardSlot& other) const
{
return status.times_erased >= other.status.times_erased;
}
void CardSlot::each_pixel(lib::Flash& flash, void (*fn)(void*, uint8_t),
void* userdata)
{
for (int page_index = 0; page_index < IMAGE_PAGE_COUNT; page_index++)
{
flash.read_page(get_image_start_page_index() + page_index);
const auto& page = flash.page();
for (uint8_t value : page)
{
fn(userdata, value);
}
}
}
void CardSlot::load_data(lib::Flash& flash)
{
flash.read_page(card_index * TOTAL_PAGE_COUNT);
const auto& page = flash.page();
const uint32_t raw_status
= page[0] | (page[1] << 8) | (page[2] << 16) | (page[3] << 24);
status.in_use = raw_status & 0x01;
status.name_length = raw_status & 0x3E;
status.times_erased = raw_status & 0xFFFFFFC0;
memcpy(name, page + 4, status.name_length);
}
int32_t CardSlot::get_unused(lib::Flash& flash)
{
int min_unused = INT32_MAX;
int min_unused_index = -1;
for (int i = 0; i < MAX_CARDS; i++)
{
CardSlot c(flash, i);
if (!c.is_used() && c.times_erased() < min_unused)
{
min_unused = c.times_erased();
min_unused_index = i;
}
}
return min_unused_index;
}