added tamagotchi save state

https://github.com/DroomOne/flipperzero-tamagotch-p1
This commit is contained in:
jbohack
2023-01-17 09:16:21 -05:00
parent a095cc894f
commit 440f119669
4 changed files with 270 additions and 39 deletions

View File

@@ -38,26 +38,10 @@ static void tama_p1_draw_callback(Canvas* const canvas, void* cb_ctx) {
// FURI_LOG_D(TAG, "Drawing frame");
// Calculate positioning
uint16_t canv_width = canvas_width(canvas);
uint16_t canv_height = canvas_height(canvas);
uint16_t lcd_matrix_scaled_width = 32 * TAMA_SCREEN_SCALE_FACTOR;
uint16_t lcd_matrix_scaled_height = 16 * TAMA_SCREEN_SCALE_FACTOR;
uint16_t lcd_matrix_top = (canv_height - lcd_matrix_scaled_height) / 2;
uint16_t lcd_matrix_top = 0;
uint16_t lcd_matrix_left = (canv_width - lcd_matrix_scaled_width) / 2;
uint16_t lcd_icon_upper_top = lcd_matrix_top - TAMA_LCD_ICON_SIZE - TAMA_LCD_ICON_MARGIN;
uint16_t lcd_icon_upper_left = lcd_matrix_left;
uint16_t lcd_icon_lower_top =
lcd_matrix_top + lcd_matrix_scaled_height + TAMA_LCD_ICON_MARGIN;
uint16_t lcd_icon_lower_left = lcd_matrix_left;
uint16_t lcd_icon_spacing_horiz =
(lcd_matrix_scaled_width - (4 * TAMA_LCD_ICON_SIZE)) / 3 + TAMA_LCD_ICON_SIZE;
// Draw pixels
// canvas_draw_frame(
// canvas,
// lcd_matrix_left,
// lcd_matrix_top,
// lcd_matrix_scaled_width,
// lcd_matrix_scaled_height);
uint16_t y = lcd_matrix_top;
for(uint8_t row = 0; row < 16; ++row) {
@@ -74,30 +58,20 @@ static void tama_p1_draw_callback(Canvas* const canvas, void* cb_ctx) {
y += TAMA_SCREEN_SCALE_FACTOR;
}
// Draw icons
// Draw Icons on bottom
uint8_t lcd_icons = g_ctx->icons;
// Top
y = lcd_icon_upper_top;
uint16_t x_ic = lcd_icon_upper_left;
for(uint8_t i = 0; i < 4; ++i) {
// canvas_draw_frame(canvas, x_ic, y, TAMA_LCD_ICON_SIZE, TAMA_LCD_ICON_SIZE);
uint16_t x_ic = 0;
y = 64 - TAMA_LCD_ICON_SIZE;
for(uint8_t i = 0; i < 7; ++i) {
if(lcd_icons & 1) {
canvas_draw_icon(canvas, x_ic, y, icons_list[i]);
}
x_ic += lcd_icon_spacing_horiz;
x_ic += TAMA_LCD_ICON_SIZE + 4;
lcd_icons >>= 1;
}
// Bottom
y = lcd_icon_lower_top;
x_ic = lcd_icon_lower_left;
for(uint8_t i = 4; i < 8; ++i) {
// canvas_draw_frame(canvas, x_ic, y, TAMA_LCD_ICON_SIZE, TAMA_LCD_ICON_SIZE);
if(lcd_icons & 1) {
canvas_draw_icon(canvas, x_ic, y, icons_list[i]);
}
x_ic += lcd_icon_spacing_horiz;
lcd_icons >>= 1;
if (lcd_icons & 7) {
canvas_draw_icon(canvas, 128 - TAMA_LCD_ICON_SIZE, 0, icons_list[7]);
}
}
@@ -118,6 +92,228 @@ static void tama_p1_update_timer_callback(FuriMessageQueue* event_queue) {
furi_message_queue_put(event_queue, &event, 0);
}
static void tama_p1_load_state() {
state_t *state;
uint8_t buf[4];
bool error = false;
state = tamalib_get_state();
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
if(storage_file_open(file, TAMA_SAVE_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) {
storage_file_read(file, &buf, 4);
if (buf[0] != (uint8_t) STATE_FILE_MAGIC[0] || buf[1] != (uint8_t) STATE_FILE_MAGIC[1] ||
buf[2] != (uint8_t) STATE_FILE_MAGIC[2] || buf[3] != (uint8_t) STATE_FILE_MAGIC[3]) {
FURI_LOG_E(TAG, "FATAL: Wrong state file magic in \"%s\" !\n", TAMA_SAVE_PATH);
error = true;
}
storage_file_read(file, &buf, 1);
if (buf[0] != STATE_FILE_VERSION) {
FURI_LOG_E(TAG, "FATAL: Unsupported version");
error = true;
}
if (!error) {
FURI_LOG_D(TAG, "Reading save.bin");
storage_file_read(file, &buf, 2);
*(state->pc) = buf[0] | ((buf[1] & 0x1F) << 8);
storage_file_read(file, &buf, 2);
*(state->x) = buf[0] | ((buf[1] & 0xF) << 8);
storage_file_read(file, &buf, 2);
*(state->y) = buf[0] | ((buf[1] & 0xF) << 8);
storage_file_read(file, &buf, 1);
*(state->a) = buf[0] & 0xF;
storage_file_read(file, &buf, 1);
*(state->b) = buf[0] & 0xF;
storage_file_read(file, &buf, 1);
*(state->np) = buf[0] & 0x1F;
storage_file_read(file, &buf, 1);
*(state->sp) = buf[0];
storage_file_read(file, &buf, 1);
*(state->flags) = buf[0] & 0xF;
storage_file_read(file, &buf, 4);
*(state->tick_counter) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
storage_file_read(file, &buf, 4);
*(state->clk_timer_timestamp) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
storage_file_read(file, &buf, 4);
*(state->prog_timer_timestamp) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
storage_file_read(file, &buf, 1);
*(state->prog_timer_enabled) = buf[0] & 0x1;
storage_file_read(file, &buf, 1);
*(state->prog_timer_data) = buf[0];
storage_file_read(file, &buf, 1);
*(state->prog_timer_rld) = buf[0];
storage_file_read(file, &buf, 4);
*(state->call_depth) = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
FURI_LOG_D(TAG, "Restoring Interupts");
for (uint32_t i = 0; i < INT_SLOT_NUM; i++) {
storage_file_read(file, &buf, 1);
state->interrupts[i].factor_flag_reg = buf[0] & 0xF;
storage_file_read(file, &buf, 1);
state->interrupts[i].mask_reg = buf[0] & 0xF;
storage_file_read(file, &buf, 1);
state->interrupts[i].triggered = buf[0] & 0x1;
}
/* First 640 half bytes correspond to the RAM */
FURI_LOG_D(TAG, "Restoring RAM");
for (uint32_t i = 0; i < MEM_RAM_SIZE; i++) {
storage_file_read(file, &buf, 1);
SET_RAM_MEMORY(state->memory, i + MEM_RAM_ADDR, buf[0] & 0xF);
}
/* I/Os are from 0xF00 to 0xF7F */
FURI_LOG_D(TAG, "Restoring I/O");
for (uint32_t i = 0; i < MEM_IO_SIZE; i++) {
storage_file_read(file, &buf, 1);
SET_IO_MEMORY(state->memory, i + MEM_IO_ADDR, buf[0] & 0xF);
}
FURI_LOG_D(TAG, "Refreshing Hardware");
tamalib_refresh_hw();
}
}
storage_file_close(file);
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
}
static void tama_p1_save_state() {
// Saving state
FURI_LOG_D(TAG, "Saving Gamestate");
uint8_t buf[4];
state_t *state;
uint32_t offset = 0;
state = tamalib_get_state();
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
if(storage_file_open(file, TAMA_SAVE_PATH, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
buf[0] = (uint8_t) STATE_FILE_MAGIC[0];
buf[1] = (uint8_t) STATE_FILE_MAGIC[1];
buf[2] = (uint8_t) STATE_FILE_MAGIC[2];
buf[3] = (uint8_t) STATE_FILE_MAGIC[3];
offset += storage_file_write(file, &buf, sizeof(buf));
buf[0] = STATE_FILE_VERSION & 0xFF;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->pc) & 0xFF;
buf[1] = (*(state->pc) >> 8) & 0x1F;
offset += storage_file_write(file, &buf, 2);
buf[0] = *(state->x) & 0xFF;
buf[1] = (*(state->x) >> 8) & 0xF;
offset += storage_file_write(file, &buf, 2);
buf[0] = *(state->y) & 0xFF;
buf[1] = (*(state->y) >> 8) & 0xF;
offset += storage_file_write(file, &buf, 2);
buf[0] = *(state->a) & 0xF;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->b) & 0xF;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->np) & 0x1F;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->sp) & 0xFF;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->flags) & 0xF;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->tick_counter) & 0xFF;
buf[1] = (*(state->tick_counter) >> 8) & 0xFF;
buf[2] = (*(state->tick_counter) >> 16) & 0xFF;
buf[3] = (*(state->tick_counter) >> 24) & 0xFF;
offset += storage_file_write(file, &buf, sizeof(buf));
buf[0] = *(state->clk_timer_timestamp) & 0xFF;
buf[1] = (*(state->clk_timer_timestamp) >> 8) & 0xFF;
buf[2] = (*(state->clk_timer_timestamp) >> 16) & 0xFF;
buf[3] = (*(state->clk_timer_timestamp) >> 24) & 0xFF;
offset += storage_file_write(file, &buf, sizeof(buf));
buf[0] = *(state->prog_timer_timestamp) & 0xFF;
buf[1] = (*(state->prog_timer_timestamp) >> 8) & 0xFF;
buf[2] = (*(state->prog_timer_timestamp) >> 16) & 0xFF;
buf[3] = (*(state->prog_timer_timestamp) >> 24) & 0xFF;
offset += storage_file_write(file, &buf, sizeof(buf));
buf[0] = *(state->prog_timer_enabled) & 0x1;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->prog_timer_data) & 0xFF;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->prog_timer_rld) & 0xFF;
offset += storage_file_write(file, &buf, 1);
buf[0] = *(state->call_depth) & 0xFF;
buf[1] = (*(state->call_depth) >> 8) & 0xFF;
buf[2] = (*(state->call_depth) >> 16) & 0xFF;
buf[3] = (*(state->call_depth) >> 24) & 0xFF;
offset += storage_file_write(file, &buf, sizeof(buf));
for (uint32_t i = 0; i < INT_SLOT_NUM; i++) {
buf[0] = state->interrupts[i].factor_flag_reg & 0xF;
offset += storage_file_write(file, &buf, 1);
buf[0] = state->interrupts[i].mask_reg & 0xF;
offset += storage_file_write(file, &buf, 1);
buf[0] = state->interrupts[i].triggered & 0x1;
offset += storage_file_write(file, &buf, 1);
}
/* First 640 half bytes correspond to the RAM */
for (uint32_t i = 0; i < MEM_RAM_SIZE; i++) {
buf[0] = GET_RAM_MEMORY(state->memory, i + MEM_RAM_ADDR) & 0xF;
offset += storage_file_write(file, &buf, 1);
}
/* I/Os are from 0xF00 to 0xF7F */
for (uint32_t i = 0; i < MEM_IO_SIZE; i++) {
buf[0] = GET_IO_MEMORY(state->memory, i + MEM_IO_ADDR) & 0xF;
offset += storage_file_write(file, &buf, 1);
}
}
storage_file_close(file);
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
FURI_LOG_D(TAG, "Finished Writing %lu", offset);
}
static int32_t tama_p1_worker(void* context) {
bool running = true;
FuriMutex* mutex = context;
@@ -125,6 +321,9 @@ static int32_t tama_p1_worker(void* context) {
cpu_sync_ref_timestamp();
LL_TIM_EnableCounter(TIM2);
tama_p1_load_state();
while(running) {
if(furi_thread_flags_get()) {
running = false;
@@ -138,6 +337,8 @@ static int32_t tama_p1_worker(void* context) {
furi_mutex_release(mutex);
return 0;
}
static void tama_p1_init(TamaApp* const ctx) {
g_ctx = ctx;
@@ -270,6 +471,8 @@ int32_t tama_p1_app(void* p) {
if(event.input.key == InputKeyBack && event.input.type == InputTypeLong) {
furi_timer_stop(timer);
running = false;
tama_p1_save_state();
}
}