start to replay

This commit is contained in:
Mitchell Marino 2025-03-28 14:00:40 -05:00
parent 5329e3594e
commit 0bde53743e
4 changed files with 83 additions and 28 deletions

View File

@ -8,7 +8,7 @@ enum state_t {
STATE_PLAYBACK = 2, STATE_PLAYBACK = 2,
}; };
static std::vector<EventCB> event_cbs; static std::vector<void(*)(const char*, const char*)> replay_fns;
static bool should_close_recording_stream; static bool should_close_recording_stream;
static FILE* recording_stream; static FILE* recording_stream;
@ -17,6 +17,9 @@ TaskHandle_t flush_file_task_handle;
static bool should_close_playback_stream; static bool should_close_playback_stream;
static FILE* playback_stream; static FILE* playback_stream;
static uint32_t playback_start_time;
TaskHandle_t playback_task_handle;
static volatile state_t state = STATE_IDLE; static volatile state_t state = STATE_IDLE;
@ -37,12 +40,64 @@ static void flush_file_task(void* arg) {
vTaskDelete(NULL); vTaskDelete(NULL);
} }
void register_event_cb(const char* name, void (*replay_callback)(uint32_t, const char*)) { static void playback_task(void* arg) {
EventCB event = { const size_t size = 16*1024;
.name = name, char* buf = (char*) malloc(size*sizeof(char));
.replay_callback = replay_callback,
}; while (state == STATE_PLAYBACK && playback_stream != nullptr) {
event_cbs.push_back(event); fgets(buf, size, playback_stream);
// look for a comma, indicating the end of the "ticks" part
size_t comma_pos = 0;
for (int i = 0; i < 11; i++) {
if (buf[i] == ',') {
comma_pos = i;
break;
}
}
if (comma_pos == 0) {
ESP_LOGE("playback", "Failed to find comma in playback line");
continue;
}
buf[comma_pos] = '\0';
uint32_t tick = atoi(buf);
// now look for the colon to indicate the end of the event name
size_t colon_pos = 0;
int i = comma_pos + 1; // start looking right after the comma
while (i < size) {
if (buf[i] == ':') {
colon_pos = i;
break;
}
}
if (colon_pos == 0) {
ESP_LOGE("playback", "Failed to find colon in playback line");
continue;
}
buf[colon_pos] = '\0';
char* event_name = buf + (comma_pos + 1);
char* arg = buf + (colon_pos + 1);
int32_t ticks_to_wait = ((int32_t) tick) - (int32_t)(xTaskGetTickCount() - playback_start_time);
if (ticks_to_wait < 0) {
ESP_LOGW("playback", "Playback is behind by %ld ticks!", ticks_to_wait);
}
if (ticks_to_wait > 0) {
vTaskDelay(ticks_to_wait);
}
for (const auto& fn : replay_fns) {
(fn)(event_name, arg);
}
}
}
void register_event_cb(void (*replay_callback)(const char*, const char*)) {
replay_fns.push_back(replay_callback);
} }
void event_occured(const char* name, const char* arg) { void event_occured(const char* name, const char* arg) {
@ -102,8 +157,13 @@ bool stop_recording() {
} }
bool start_playback() { bool start_playback() {
// TODO: impl if (state != STATE_IDLE) return false;
return false; if (playback_stream == nullptr) return false;
state = STATE_PLAYBACK;
playback_start_time = xTaskGetTickCount();
xTaskCreate(playback_task, "playback", 2048, NULL, 2, &playback_task_handle);
return true;
} }
bool stop_playback() { bool stop_playback() {

View File

@ -4,20 +4,9 @@
#include <stdint.h> #include <stdint.h>
#include "esp_vfs_fat.h" #include "esp_vfs_fat.h"
/// @brief An event that represents the physical bomb state moving. /// @brief Registers function to be called on replay.
struct EventCB { /// @param replay_callback A function to call to playback the event.
// The name of the event. void register_replay_fn(void (*replay_fn)(const char*, const char*));
// This should not contain whitespace or the characters ':', ','
const char* name;
// An optional callback function for recreating the state.
// Arguments are "ticks" and the serialized argument
void (*replay_callback)(uint32_t, const char*);
};
/// @brief Registers a callback for a certain event to be called on replay.
/// @param name The name of the event to respond to.
/// @param replay_callback A function to call to playback this state transition.
void register_event_cb(const char* name, void (*replay_callback)(uint32_t, const char*));
// TODO: add one for generically responding to all events. // TODO: add one for generically responding to all events.

View File

@ -17,6 +17,10 @@ static lv_style_t style_screen;
SemaphoreHandle_t xGuiSemaphore; SemaphoreHandle_t xGuiSemaphore;
static void replay_handler(const char* event, const char* arg) {
}
static bool notify_lvgl_flush_ready( static bool notify_lvgl_flush_ready(
esp_lcd_panel_io_handle_t panel_io, esp_lcd_panel_io_handle_t panel_io,
esp_lcd_panel_io_event_data_t *edata, esp_lcd_panel_io_event_data_t *edata,
@ -224,5 +228,7 @@ void init_tft() {
initialize_display(); initialize_display();
xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 5, NULL, 1); xTaskCreatePinnedToCore(guiTask, "gui", 4096*2, NULL, 5, NULL, 1);
register_replay_fn(replay_handler);
ESP_LOGI(TAG, "TFT initialized!"); ESP_LOGI(TAG, "TFT initialized!");
} }

View File

@ -36,6 +36,10 @@ extern "C" void app_main(void) {
init_wires(); init_wires();
vTaskDelay(pdMS_TO_TICKS(1000)); vTaskDelay(pdMS_TO_TICKS(1000));
clean_bomb();
step0();
// set_recording_source(stdout, false); // set_recording_source(stdout, false);
FILE* record_file = fopen(MOUNT_POINT "/record.txt", "w"); FILE* record_file = fopen(MOUNT_POINT "/record.txt", "w");
if (record_file == nullptr) { if (record_file == nullptr) {
@ -44,10 +48,6 @@ extern "C" void app_main(void) {
set_recording_source(record_file, true); set_recording_source(record_file, true);
start_recording(); start_recording();
clean_bomb();
step0();
set_game_time(initial_game_time); set_game_time(initial_game_time);
start_game_timer(); start_game_timer();
total_strikes = 0; total_strikes = 0;
@ -55,7 +55,6 @@ extern "C" void app_main(void) {
current_step = 1; current_step = 1;
if (skip_to_step <= 1) step1(); if (skip_to_step <= 1) step1();
step_finish_times[current_step-1] = get_game_time(); step_finish_times[current_step-1] = get_game_time();
stop_recording();
clean_bomb(); clean_bomb();
current_step = 2; current_step = 2;
if (skip_to_step <= 2) step2(); if (skip_to_step <= 2) step2();
@ -84,5 +83,6 @@ extern "C" void app_main(void) {
play_clip_wav(MOUNT_POINT "/diffuse.wav", true, false, 3, 0); play_clip_wav(MOUNT_POINT "/diffuse.wav", true, false, 3, 0);
display_game_results(); display_game_results();
stop_recording();
} }