mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-23 05:24:46 -07:00
added tamagotchi save state
https://github.com/DroomOne/flipperzero-tamagotch-p1
This commit is contained in:
@@ -3,15 +3,26 @@ Tama P1 Emulator for Flipper Zero
|
|||||||
|
|
||||||
This is a tama P1 Emulator app for Flipper Zero, based on [TamaLIB](https://github.com/jcrona/tamalib/).
|
This is a tama P1 Emulator app for Flipper Zero, based on [TamaLIB](https://github.com/jcrona/tamalib/).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
How to play
|
How to play
|
||||||
-----------
|
-----------
|
||||||
Create a `tama_p1` folder in your microSD card, and put the ROM as `rom.bin`.
|
Create a `tama_p1` folder in your microSD card, and put the ROM as `rom.bin`.
|
||||||
|
Use a search engine to find the Tamagotchi ROM. There is a file named `a`.
|
||||||
|
Rename this to `rom.bin`.
|
||||||
|
|
||||||
Left button is A, OK is B, and right button is C. Hold the back button to exit.
|
Left button is A, OK is B, and right button is C. Hold the back button to exit.
|
||||||
There is currently no saving, so your progress will be reset when you exit the
|
There is currently no saving, so your progress will be reset when you exit the
|
||||||
app.
|
app.
|
||||||
|
|
||||||
Building
|
Building
|
||||||
--------
|
--------
|
||||||
|
Move this folder into flippers applications/plugins/tama_p1.
|
||||||
|
|
||||||
|
|
||||||
|
Launching the app, directly from console to flipper:
|
||||||
|
`./fbt launch_app APPSRC=applications\plugins\tama_p1`
|
||||||
|
|
||||||
Run the following to compile icons:
|
Run the following to compile icons:
|
||||||
```
|
```
|
||||||
scripts/assets.py icons applications/tama_p1/icons applications/tama_p1/compiled
|
scripts/assets.py icons applications/tama_p1/icons applications/tama_p1/compiled
|
||||||
@@ -20,16 +31,25 @@ scripts/assets.py icons applications/tama_p1/icons applications/tama_p1/compiled
|
|||||||
Note: you may also need to add `-Wno-unused-parameter` to `CCFLAGS` in
|
Note: you may also need to add `-Wno-unused-parameter` to `CCFLAGS` in
|
||||||
`site_cons/cc.scons` to suppress unused parameter errors in TamaLIB.
|
`site_cons/cc.scons` to suppress unused parameter errors in TamaLIB.
|
||||||
|
|
||||||
|
Debugging
|
||||||
|
---------
|
||||||
|
Using the serial script from [FlipperScripts](https://github.com/DroomOne/FlipperScripts/blob/main/serial_logger.py)
|
||||||
|
it is easy to add direct logging after running the appliation:
|
||||||
|
`python .\serial_logger.py`
|
||||||
|
|
||||||
|
`./fbt launch_app APPSRC=applications\plugins\tama_p1; python .\serial_logger.py`
|
||||||
|
|
||||||
|
|
||||||
Implemented
|
Implemented
|
||||||
-----------
|
-----------
|
||||||
- Basic emulation
|
- Basic emulation
|
||||||
- Input
|
- Input
|
||||||
- Sound
|
- Sound
|
||||||
|
- Saving/Loading emaulator state (stored in `/ext/tama_p1/save.bin`)
|
||||||
|
|
||||||
To-do
|
To-do
|
||||||
-----
|
-----
|
||||||
- Saving/loading
|
- Slots
|
||||||
- Multiple slots?
|
|
||||||
- In-game reset
|
- In-game reset
|
||||||
- Test mode?
|
- Test mode?
|
||||||
- Volume adjustment
|
- Volume adjustment
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ static bool_t tama_p1_hal_is_log_enabled(log_level_t level) {
|
|||||||
static void tama_p1_hal_log(log_level_t level, char* buff, ...) {
|
static void tama_p1_hal_log(log_level_t level, char* buff, ...) {
|
||||||
if(!tama_p1_hal_is_log_enabled(level)) return;
|
if(!tama_p1_hal_is_log_enabled(level)) return;
|
||||||
|
|
||||||
FuriString* string = NULL;
|
FuriString* string = furi_string_alloc();
|
||||||
va_list args;
|
va_list args;
|
||||||
va_start(args, buff);
|
va_start(args, buff);
|
||||||
furi_string_cat_vprintf(string, buff, args);
|
furi_string_cat_vprintf(string, buff, args);
|
||||||
@@ -50,7 +50,10 @@ static void tama_p1_hal_log(log_level_t level, char* buff, ...) {
|
|||||||
FURI_LOG_I(TAG_HAL, "%s", furi_string_get_cstr(string));
|
FURI_LOG_I(TAG_HAL, "%s", furi_string_get_cstr(string));
|
||||||
break;
|
break;
|
||||||
case LOG_MEMORY:
|
case LOG_MEMORY:
|
||||||
|
break;
|
||||||
case LOG_CPU:
|
case LOG_CPU:
|
||||||
|
FURI_LOG_D(TAG_HAL, "%s", furi_string_get_cstr(string));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
FURI_LOG_D(TAG_HAL, "%s", furi_string_get_cstr(string));
|
FURI_LOG_D(TAG_HAL, "%s", furi_string_get_cstr(string));
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -9,6 +9,11 @@
|
|||||||
#define TAMA_LCD_ICON_SIZE 14
|
#define TAMA_LCD_ICON_SIZE 14
|
||||||
#define TAMA_LCD_ICON_MARGIN 1
|
#define TAMA_LCD_ICON_MARGIN 1
|
||||||
|
|
||||||
|
#define STATE_FILE_MAGIC "TLST"
|
||||||
|
#define STATE_FILE_VERSION 2
|
||||||
|
#define TAMA_SAVE_PATH EXT_PATH("tama_p1/save.bin")
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
FuriThread* thread;
|
FuriThread* thread;
|
||||||
hal_t hal;
|
hal_t hal;
|
||||||
|
|||||||
@@ -38,26 +38,10 @@ static void tama_p1_draw_callback(Canvas* const canvas, void* cb_ctx) {
|
|||||||
// FURI_LOG_D(TAG, "Drawing frame");
|
// FURI_LOG_D(TAG, "Drawing frame");
|
||||||
// Calculate positioning
|
// Calculate positioning
|
||||||
uint16_t canv_width = canvas_width(canvas);
|
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_width = 32 * TAMA_SCREEN_SCALE_FACTOR;
|
||||||
uint16_t lcd_matrix_scaled_height = 16 * TAMA_SCREEN_SCALE_FACTOR;
|
uint16_t lcd_matrix_top = 0;
|
||||||
uint16_t lcd_matrix_top = (canv_height - lcd_matrix_scaled_height) / 2;
|
|
||||||
uint16_t lcd_matrix_left = (canv_width - lcd_matrix_scaled_width) / 2;
|
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;
|
uint16_t y = lcd_matrix_top;
|
||||||
for(uint8_t row = 0; row < 16; ++row) {
|
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;
|
y += TAMA_SCREEN_SCALE_FACTOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw icons
|
// Draw Icons on bottom
|
||||||
uint8_t lcd_icons = g_ctx->icons;
|
uint8_t lcd_icons = g_ctx->icons;
|
||||||
// Top
|
uint16_t x_ic = 0;
|
||||||
y = lcd_icon_upper_top;
|
y = 64 - TAMA_LCD_ICON_SIZE;
|
||||||
uint16_t x_ic = lcd_icon_upper_left;
|
for(uint8_t i = 0; i < 7; ++i) {
|
||||||
for(uint8_t i = 0; i < 4; ++i) {
|
|
||||||
// canvas_draw_frame(canvas, x_ic, y, TAMA_LCD_ICON_SIZE, TAMA_LCD_ICON_SIZE);
|
|
||||||
if(lcd_icons & 1) {
|
if(lcd_icons & 1) {
|
||||||
canvas_draw_icon(canvas, x_ic, y, icons_list[i]);
|
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;
|
lcd_icons >>= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bottom
|
if (lcd_icons & 7) {
|
||||||
y = lcd_icon_lower_top;
|
canvas_draw_icon(canvas, 128 - TAMA_LCD_ICON_SIZE, 0, icons_list[7]);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,6 +92,228 @@ static void tama_p1_update_timer_callback(FuriMessageQueue* event_queue) {
|
|||||||
furi_message_queue_put(event_queue, &event, 0);
|
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) {
|
static int32_t tama_p1_worker(void* context) {
|
||||||
bool running = true;
|
bool running = true;
|
||||||
FuriMutex* mutex = context;
|
FuriMutex* mutex = context;
|
||||||
@@ -125,6 +321,9 @@ static int32_t tama_p1_worker(void* context) {
|
|||||||
|
|
||||||
cpu_sync_ref_timestamp();
|
cpu_sync_ref_timestamp();
|
||||||
LL_TIM_EnableCounter(TIM2);
|
LL_TIM_EnableCounter(TIM2);
|
||||||
|
|
||||||
|
tama_p1_load_state();
|
||||||
|
|
||||||
while(running) {
|
while(running) {
|
||||||
if(furi_thread_flags_get()) {
|
if(furi_thread_flags_get()) {
|
||||||
running = false;
|
running = false;
|
||||||
@@ -139,6 +338,8 @@ static int32_t tama_p1_worker(void* context) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void tama_p1_init(TamaApp* const ctx) {
|
static void tama_p1_init(TamaApp* const ctx) {
|
||||||
g_ctx = ctx;
|
g_ctx = ctx;
|
||||||
memset(ctx, 0, sizeof(TamaApp));
|
memset(ctx, 0, sizeof(TamaApp));
|
||||||
@@ -270,6 +471,8 @@ int32_t tama_p1_app(void* p) {
|
|||||||
if(event.input.key == InputKeyBack && event.input.type == InputTypeLong) {
|
if(event.input.key == InputKeyBack && event.input.type == InputTypeLong) {
|
||||||
furi_timer_stop(timer);
|
furi_timer_stop(timer);
|
||||||
running = false;
|
running = false;
|
||||||
|
|
||||||
|
tama_p1_save_state();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user