#include #include #include #include #include #include #include "chip8.h" #include "emulator_core/flipper_chip.h" #define TAG "Chip8Emulator" #define WORKER_TAG TAG "Worker" #define FILE_BUFFER_LEN 16 typedef enum { WorkerEvtToggle = (1 << 1), WorkerEvtEnd = (1 << 2), } WorkerEvtFlags; struct Chip8Emulator { Chip8State st; string_t file_path; FuriThread* thread; }; static int32_t chip8_worker(void* context) { Chip8Emulator* chip8 = context; FURI_LOG_I(WORKER_TAG, "Start furi record open"); Storage* furi_storage_record = furi_record_open(RECORD_STORAGE); FURI_LOG_I(WORKER_TAG, "furi record opened"); FURI_LOG_I(WORKER_TAG, "Start storage file alloc"); File* rom_file = storage_file_alloc(furi_storage_record); FURI_LOG_I( WORKER_TAG, "Start storage file open, path = %s", string_get_cstr(chip8->file_path)); uint8_t* rom_data = malloc(4096); FURI_LOG_I(WORKER_TAG, "4096 array gotten"); while(1) { if(chip8->st.worker_state == WorkerStateBackPressed) { FURI_LOG_I(WORKER_TAG, "WorkerStateBackPressed"); break; } if(chip8->st.worker_state == WorkerStateLoadingRom) { bool is_file_opened = storage_file_open( rom_file, string_get_cstr(chip8->file_path), FSAM_READ, FSOM_OPEN_EXISTING); if(!is_file_opened) { FURI_LOG_I(WORKER_TAG, "Cannot open storage"); storage_file_close(rom_file); storage_file_free(rom_file); chip8->st.worker_state = WorkerStateRomLoadError; return 0; } FURI_LOG_I(WORKER_TAG, "File was opened, try read this"); int rom_len = read_rom_data(rom_file, rom_data); FURI_LOG_I(WORKER_TAG, "Rom data finished reading"); FURI_LOG_I(WORKER_TAG, "Load chip8 core data"); t_chip8_load_game(chip8->st.t_chip8_state, rom_data, rom_len); FURI_LOG_I(WORKER_TAG, "chip8 core data loaded"); FURI_LOG_I(WORKER_TAG, "Wipe screen start"); for(int i = 0; i < CHIP8_SCREEN_H; i++) { FURI_LOG_I(WORKER_TAG, "Wipe screen line %d", i); for(int j = 0; j < CHIP8_SCREEN_W; j++) { chip8->st.t_chip8_state->screen[i][j] = 0; } furi_delay_ms(15); } FURI_LOG_I(WORKER_TAG, "Wipe screen end"); chip8->st.worker_state = WorkerStateRomLoaded; } if(chip8->st.worker_state == WorkerStateRomLoaded) { if(chip8->st.t_chip8_state->go_render) { continue; } t_chip8_execute_next_opcode(chip8->st.t_chip8_state); FURI_LOG_I( "chip8_executing", "current: 0x%X next: 0x%X", chip8->st.t_chip8_state->current_opcode, chip8->st.t_chip8_state->next_opcode); furi_delay_ms(2); //t_chip8_tick(chip8->st.t_chip8_state); } } FURI_LOG_I("CHIP8", "Prepare to ending app"); storage_file_close(rom_file); storage_file_free(rom_file); t_chip8_free_memory(chip8->st.t_chip8_state, free); FURI_LOG_I("CHIP8", "End ending"); return 0; } Chip8Emulator* chip8_make_emulator(string_t file_path) { furi_assert(file_path); FURI_LOG_I("CHIP8", "make emulator, file_path=", string_get_cstr(file_path)); Chip8Emulator* chip8 = malloc(sizeof(Chip8Emulator)); string_init(chip8->file_path); string_set(chip8->file_path, file_path); chip8->st.worker_state = WorkerStateLoadingRom; chip8->st.t_chip8_state = t_chip8_init(malloc); // FURI_LOG_I(WORKER_TAG, "Start wipe screen"); // furi_delay_ms(1500); // for (int i = 0; i < CHIP8_SCREEN_H; i++) // { // FURI_LOG_I(WORKER_TAG, "Start wipe line %d", i); // for (int j = 0; j < CHIP8_SCREEN_W; j++) // { // chip8->st.t_chip8_state->screen[i][j] = 0; // } // } // FURI_LOG_I(WORKER_TAG, "End wipe screen"); chip8->thread = furi_thread_alloc(); furi_thread_set_name(chip8->thread, "Chip8Worker"); furi_thread_set_stack_size(chip8->thread, 4096); furi_thread_set_context(chip8->thread, chip8); furi_thread_set_callback(chip8->thread, chip8_worker); furi_thread_start(chip8->thread); return chip8; } void chip8_close_emulator(Chip8Emulator* chip8) { FURI_LOG_I("chip_8_close_emulator", "start"); furi_assert(chip8); furi_thread_flags_set(furi_thread_get_id(chip8->thread), WorkerEvtEnd); furi_thread_join(chip8->thread); furi_thread_free(chip8->thread); string_clear(chip8->file_path); free(chip8); FURI_LOG_I("chip_8_close_emulator", "end"); } void chip8_toggle(Chip8Emulator* chip8) { furi_assert(chip8); furi_thread_flags_set(furi_thread_get_id(chip8->thread), WorkerEvtToggle); } Chip8State* chip8_get_state(Chip8Emulator* chip8) { furi_assert(chip8); return &(chip8->st); } uint16_t read_rom_data(File* file, uint8_t* data) { furi_assert(file); furi_assert(data); const uint8_t buffer_size = 32; uint16_t file_pointer = 0; uint8_t buff[buffer_size]; while(1) { uint16_t bytes_were_read = storage_file_read(file, buff, buffer_size); if(bytes_were_read == 0) { break; } for(uint16_t i = 0; i < bytes_were_read; i++) { data[file_pointer] = buff[i]; file_pointer++; } } return file_pointer; } void chip8_set_back_pressed(Chip8Emulator* chip8) { chip8->st.worker_state = WorkerStateBackPressed; chip8->st.t_chip8_state->go_render = true; FURI_LOG_I(WORKER_TAG, "SET BACK PRESSED. EMULATION IS STOPPED"); } void chip8_set_up_pressed(Chip8Emulator* chip8) { chip8->st.t_chip8_state->go_render = true; t_chip8_set_input(chip8->st.t_chip8_state, k_1); FURI_LOG_I(WORKER_TAG, "UP PRESSED"); } void chip8_set_down_pressed(Chip8Emulator* chip8) { chip8->st.t_chip8_state->go_render = true; t_chip8_set_input(chip8->st.t_chip8_state, k_4); FURI_LOG_I(WORKER_TAG, "DOWN PRESSED"); } void chip8_release_keyboard(Chip8Emulator* chip8) { chip8->st.t_chip8_state->go_render = true; t_chip8_release_input(chip8->st.t_chip8_state); FURI_LOG_I(WORKER_TAG, "chip8_release_keyboard Release input"); }