mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-07 19:01:54 -07:00
Merge branch '420' of https://github.com/RogueMaster/flipperzero-firmware-wPlugins into 420
This commit is contained in:
@@ -1,203 +0,0 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <storage/storage.h>
|
||||
#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;
|
||||
FuriString* 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", furi_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, furi_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(FuriString* file_path) {
|
||||
furi_assert(file_path);
|
||||
FURI_LOG_I("CHIP8", "make emulator, file_path=", furi_string_get_cstr(file_path));
|
||||
|
||||
Chip8Emulator* chip8 = malloc(sizeof(Chip8Emulator));
|
||||
chip8->file_path = furi_string_alloc();
|
||||
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);
|
||||
furi_string_free(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");
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <furi.h>
|
||||
#include <storage/storage.h>
|
||||
#include "emulator_core/flipper_chip.h"
|
||||
|
||||
#define CHIP8_SCREEN_W 64
|
||||
#define CHIP8_SCREEN_H 32
|
||||
|
||||
typedef struct Chip8Emulator Chip8Emulator;
|
||||
|
||||
typedef enum {
|
||||
WorkerStateLoadingRom,
|
||||
WorkerStateRomLoaded,
|
||||
WorkerStateRomLoadError,
|
||||
WorkerStateBackPressed,
|
||||
} WorkerState;
|
||||
|
||||
typedef struct {
|
||||
WorkerState worker_state;
|
||||
t_chip8_state* t_chip8_state;
|
||||
} Chip8State;
|
||||
|
||||
Chip8Emulator* chip8_make_emulator(FuriString* file_path);
|
||||
|
||||
void chip8_close_emulator(Chip8Emulator* chip8);
|
||||
void chip8_set_back_pressed(Chip8Emulator* chip8);
|
||||
void chip8_set_up_pressed(Chip8Emulator* chip8);
|
||||
void chip8_set_down_pressed(Chip8Emulator* chip8);
|
||||
void chip8_release_keyboard(Chip8Emulator* chip8);
|
||||
|
||||
Chip8State* chip8_get_state(Chip8Emulator* chip8);
|
||||
|
||||
void chip8_toggle(Chip8Emulator* chip8);
|
||||
|
||||
uint16_t read_rom_data(File* file, uint8_t* data);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,89 +0,0 @@
|
||||
#include "chip8_app_i.h"
|
||||
#include <furi.h>
|
||||
|
||||
static bool chip8_app_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
Chip8App* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool chip8_app_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Chip8App* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void chip8_app_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
Chip8App* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
uint8_t** chip8_backup_screen_alloc() {
|
||||
FURI_LOG_I("chip8", "chip8_backup_screen_alloc start");
|
||||
|
||||
uint8_t** backup_screen = malloc(SCREEN_HEIGHT * sizeof(size_t));
|
||||
for(int i = 0; i < SCREEN_HEIGHT; i++) {
|
||||
backup_screen[i] = malloc(SCREEN_WIDTH * sizeof(uint8_t));
|
||||
for(int j = 0; j < SCREEN_WIDTH; j++) {
|
||||
backup_screen[i][j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FURI_LOG_I("chip8", "chip8_backup_screen_alloc end");
|
||||
return backup_screen;
|
||||
}
|
||||
|
||||
Chip8App* chip8_app_alloc() {
|
||||
Chip8App* app = malloc(sizeof(Chip8App));
|
||||
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&chip8_scene_handlers, app);
|
||||
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, chip8_app_tick_event_callback, 100);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
app->view_dispatcher, chip8_app_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, chip8_app_back_event_callback);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
app->chip8_view = chip8_alloc();
|
||||
app->backup_screen = chip8_backup_screen_alloc();
|
||||
view_dispatcher_add_view(app->view_dispatcher, Chip8WorkView, chip8_get_view(app->chip8_view));
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, Chip8FileSelectView);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void chip8_app_free(Chip8App* app) {
|
||||
FURI_LOG_I("CHIP8", "chip8_app_free started");
|
||||
furi_assert(app);
|
||||
|
||||
view_dispatcher_remove_view(app->view_dispatcher, Chip8FileSelectView);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, Chip8WorkView);
|
||||
chip8_free(app->chip8_view);
|
||||
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t chip8_app(void* p) {
|
||||
Chip8App* chip8_app = chip8_app_alloc();
|
||||
|
||||
view_dispatcher_run(chip8_app->view_dispatcher);
|
||||
chip8_app_free(chip8_app);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct Chip8App Chip8App;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "chip8_app.h"
|
||||
#include "scenes/chip8_scene.h"
|
||||
#include "chip8.h"
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include "views/chip8_view.h"
|
||||
|
||||
#define CHIP8_APP_PATH_FOLDER "/any/chip8"
|
||||
#define CHIP8_APP_EXTENSION ".ch8"
|
||||
|
||||
struct Chip8App {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
DialogsApp* dialogs;
|
||||
|
||||
FuriString* file_name;
|
||||
uint8_t** backup_screen;
|
||||
Chip8View* chip8_view;
|
||||
Chip8Emulator* chip8;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
Chip8FileSelectView,
|
||||
Chip8WorkView,
|
||||
} Chip8AppView;
|
||||
@@ -1,319 +0,0 @@
|
||||
//
|
||||
// Created by dwdraugr on 24.11.2021.
|
||||
//
|
||||
|
||||
#include "flipper_chip.h"
|
||||
#include "flipper_fonts.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
static uint8_t randbyte();
|
||||
static void draw_sprite(t_chip8_state* state, uint8_t x, uint8_t y, uint8_t n);
|
||||
static void error_stop(t_chip8_state* state, uint16_t opcode);
|
||||
|
||||
t_chip8_state* t_chip8_init(void* (*system_malloc)(size_t)) {
|
||||
t_chip8_state* state = system_malloc(sizeof(t_chip8_state));
|
||||
|
||||
state->PC = MEMORY_START_POSITION;
|
||||
state->SP = 0;
|
||||
state->I = 0;
|
||||
state->delay_timer = 0;
|
||||
state->sound_timer = 0;
|
||||
state->go_render = false;
|
||||
state->next_opcode = 0;
|
||||
|
||||
state->memory = system_malloc(MEMORY_SIZE * sizeof(uint8_t));
|
||||
// memset(state->memory, 0, MEMORY_SIZE);
|
||||
state->screen = system_malloc(SCREEN_HEIGHT * sizeof(size_t));
|
||||
for(int i = 0; i < SCREEN_HEIGHT; i++) {
|
||||
state->screen[i] = system_malloc(SCREEN_WIDTH * sizeof(uint8_t));
|
||||
// memset(state->screen[i], 0, SCREEN_WIDTH);
|
||||
}
|
||||
state->V = system_malloc(CPU_REGISTER_NUMBER * sizeof(uint8_t));
|
||||
// memset(state->V, 0, CPU_REGISTER_NUMBER);
|
||||
state->stack = system_malloc(CPU_STACK_DEPTH * sizeof(uint16_t));
|
||||
// memset(state->stack, 0, CPU_STACK_DEPTH * sizeof(short));
|
||||
state->key = system_malloc(KEYS_NUMBER * sizeof(uint8_t));
|
||||
// memset(state->key, 0, KEYS_NUMBER);
|
||||
|
||||
memcpy(state->memory, font_small, FONT_SMALL);
|
||||
srand(time(NULL));
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
bool t_chip8_load_game(t_chip8_state* state, const uint8_t* rom, int rom_size) {
|
||||
if(MEMORY_ROM_SIZE < rom_size) {
|
||||
return false;
|
||||
}
|
||||
memcpy(&state->memory[MEMORY_START_POSITION], rom, rom_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void t_chip8_free_memory(t_chip8_state* state, void (*system_free)(void*)) {
|
||||
system_free(state->memory);
|
||||
for(int i = 0; i < SCREEN_HEIGHT; i++) {
|
||||
system_free(state->screen[i]);
|
||||
}
|
||||
system_free(state->screen);
|
||||
system_free(state->V);
|
||||
system_free(state->key);
|
||||
system_free(state->stack);
|
||||
system_free(state);
|
||||
}
|
||||
|
||||
void t_chip8_execute_next_opcode(t_chip8_state* state) {
|
||||
static bool isWaitInput = false;
|
||||
static uint8_t register_number = 255;
|
||||
|
||||
uint16_t opcode = state->memory[state->PC] << 8 | state->memory[state->PC + 1];
|
||||
uint8_t x = (opcode >> 8) & 0x000F;
|
||||
uint8_t y = (opcode >> 4) & 0x000F;
|
||||
uint8_t n = opcode & 0x000F;
|
||||
uint8_t kk = opcode & 0x00FF;
|
||||
uint16_t nnn = opcode & 0x0FFF;
|
||||
|
||||
// jump to input-wait opcode
|
||||
if(isWaitInput) {
|
||||
opcode = 0xF000;
|
||||
kk = 0x0A;
|
||||
x = register_number;
|
||||
}
|
||||
state->current_opcode = opcode & 0xF000;
|
||||
switch(opcode & 0xF000) {
|
||||
case 0x0000:
|
||||
switch(kk) {
|
||||
case 0x00E0:
|
||||
for(int i = 0; i < SCREEN_HEIGHT; i++) {
|
||||
for(int j = 0; j < SCREEN_WIDTH; j++) {
|
||||
state->screen[i][j] = 0;
|
||||
}
|
||||
}
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x00EE:
|
||||
state->PC = state->stack[--state->SP];
|
||||
break;
|
||||
default:
|
||||
error_stop(state, opcode);
|
||||
}
|
||||
break;
|
||||
case 0x1000:
|
||||
state->PC = nnn;
|
||||
break;
|
||||
case 0x2000:
|
||||
state->stack[state->SP++] = state->PC + 2;
|
||||
state->PC = nnn;
|
||||
break;
|
||||
case 0x3000:
|
||||
state->PC += (state->V[x] == kk) ? 4 : 2;
|
||||
break;
|
||||
case 0x4000:
|
||||
state->PC += (state->V[x] != kk) ? 4 : 2;
|
||||
break;
|
||||
case 0x5000:
|
||||
state->PC += (state->V[x] == state->V[y]) ? 4 : 2;
|
||||
break;
|
||||
case 0x6000:
|
||||
state->V[x] = kk;
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x7000:
|
||||
state->V[x] += kk;
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x8000:
|
||||
switch(n) {
|
||||
case 0x0:
|
||||
state->V[x] = state->V[y];
|
||||
break;
|
||||
case 0x1:
|
||||
state->V[x] |= state->V[y];
|
||||
break;
|
||||
case 0x2:
|
||||
state->V[x] &= state->V[y];
|
||||
break;
|
||||
case 0x3:
|
||||
state->V[x] ^= state->V[y];
|
||||
break;
|
||||
case 0x4:
|
||||
state->V[0xF] = (int)state->V[x] + (int)state->V[y] ? 1 : 0;
|
||||
state->V[x] += state->V[y];
|
||||
break;
|
||||
case 0x5:
|
||||
state->V[0xF] = state->V[x] > state->V[y] ? 1 : 0;
|
||||
state->V[x] -= state->V[y];
|
||||
break;
|
||||
case 0x6:
|
||||
state->V[0xF] = state->V[x] & 0x1;
|
||||
state->V[x] >>= 1;
|
||||
break;
|
||||
case 0x7:
|
||||
state->V[0xF] = state->V[y] > state->V[x] ? 1 : 0;
|
||||
state->V[x] = state->V[y] - state->V[x];
|
||||
break;
|
||||
case 0xE:
|
||||
state->V[0xF] = (state->V[x] >> 7) & 0x1;
|
||||
state->V[x] <<= 1;
|
||||
break;
|
||||
default:
|
||||
error_stop(state, opcode);
|
||||
}
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x9000:
|
||||
switch(n) {
|
||||
case 0x0:
|
||||
state->PC += state->V[x] != state->V[y] ? 4 : 2;
|
||||
break;
|
||||
default:
|
||||
error_stop(state, opcode);
|
||||
}
|
||||
break;
|
||||
case 0xA000:
|
||||
state->I = nnn;
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0xB000:
|
||||
state->PC = nnn + state->V[0];
|
||||
break;
|
||||
case 0xC000:
|
||||
state->V[x] = randbyte() & kk;
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0xD000:
|
||||
draw_sprite(state, state->V[x], state->V[y], n);
|
||||
state->go_render = true;
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0xE000:
|
||||
switch(kk) {
|
||||
case 0x9E:
|
||||
state->PC += state->key[state->V[x]] ? 4 : 2;
|
||||
break;
|
||||
case 0xA1:
|
||||
state->PC += !state->key[state->V[x]] ? 4 : 2;
|
||||
break;
|
||||
default:
|
||||
error_stop(state, opcode);
|
||||
}
|
||||
break;
|
||||
case 0xF000:
|
||||
switch(kk) {
|
||||
case 0x07:
|
||||
state->V[x] = state->delay_timer;
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x0A:
|
||||
for(int i = 0; i < KEYS_NUMBER; i++) {
|
||||
if(state->key[i]) {
|
||||
state->V[x] = i;
|
||||
isWaitInput = false;
|
||||
goto exit_input_wait;
|
||||
}
|
||||
isWaitInput = true;
|
||||
register_number = x;
|
||||
}
|
||||
exit_input_wait:
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x15:
|
||||
state->delay_timer = state->V[x];
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x18:
|
||||
state->sound_timer = state->V[x];
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x1E:
|
||||
state->V[0xF] = state->I + state->V[x] > 0xFFF ? 1 : 0;
|
||||
state->I += state->V[x];
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x29:
|
||||
state->I = FONT_BYTES_PER_CHAR * state->V[x];
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x33:
|
||||
state->memory[state->I] = (state->V[x] % 1000) / 100;
|
||||
state->memory[state->I + 1] = (state->V[x] % 100) / 10;
|
||||
state->memory[state->I + 2] = state->V[x] % 10;
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x55:
|
||||
memcpy(state->memory, state->V, x);
|
||||
state->I += x + 1;
|
||||
state->PC += 2;
|
||||
break;
|
||||
case 0x65:
|
||||
for(int i = 0; i <= x; i++) {
|
||||
state->V[i] = state->memory[state->I + i];
|
||||
}
|
||||
state->I += x + 1;
|
||||
state->PC += 2;
|
||||
break;
|
||||
default:
|
||||
error_stop(state, opcode);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error_stop(state, opcode);
|
||||
}
|
||||
|
||||
state->next_opcode = state->memory[state->PC] << 8 | state->memory[state->PC + 1];
|
||||
state->next_opcode &= 0xf000;
|
||||
}
|
||||
|
||||
void t_chip8_tick(t_chip8_state* state) {
|
||||
if(state->delay_timer > 0) {
|
||||
--state->delay_timer;
|
||||
}
|
||||
if(state->sound_timer > 0) {
|
||||
--state->sound_timer;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t** t_chip8_get_screen(t_chip8_state* state) {
|
||||
return (uint8_t**)state->screen;
|
||||
}
|
||||
|
||||
void t_chip8_set_input(t_chip8_state* state, t_keys key) {
|
||||
state->key[key] = 1;
|
||||
}
|
||||
|
||||
void t_chip8_release_input(t_chip8_state* state) {
|
||||
for(int i = 0; i < KEYS_NUMBER; i++) {
|
||||
state->key[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t randbyte() {
|
||||
return rand() % 256;
|
||||
}
|
||||
|
||||
static void draw_sprite(t_chip8_state* state, uint8_t x, uint8_t y, uint8_t n) {
|
||||
unsigned row = y, col = x;
|
||||
unsigned byte_index;
|
||||
unsigned bit_index;
|
||||
|
||||
state->V[0xF] = 0;
|
||||
for(byte_index = 0; byte_index < n; byte_index++) {
|
||||
uint8_t byte = state->memory[state->I + byte_index];
|
||||
|
||||
for(bit_index = 0; bit_index < 8; bit_index++) {
|
||||
uint8_t bit = (byte >> bit_index) & 0x1;
|
||||
|
||||
uint8_t* pixel_pointer = &state->screen[(row + byte_index) % SCREEN_HEIGHT]
|
||||
[(col + (7 - bit_index)) % SCREEN_WIDTH];
|
||||
|
||||
if(bit == 1 && *pixel_pointer == 1) state->V[0xF] = 1;
|
||||
*pixel_pointer = *pixel_pointer ^ bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void error_stop(t_chip8_state* state, uint16_t opcode) {
|
||||
exit(100);
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
//
|
||||
// Created by dwdraugr on 24.11.2021.
|
||||
//
|
||||
|
||||
#ifndef FLIPPER_CHIP_FLIPPER_CHIP_H
|
||||
#define FLIPPER_CHIP_FLIPPER_CHIP_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define CPU_REGISTER_NUMBER 0x10
|
||||
#define CPU_STACK_DEPTH 0x10
|
||||
|
||||
#define MEMORY_SIZE 0x1000
|
||||
#define MEMORY_START_POSITION 0x200
|
||||
#define MEMORY_ROM_SIZE (MEMORY_SIZE - MEMORY_START_POSITION)
|
||||
|
||||
#define SCREEN_WIDTH 64
|
||||
#define SCREEN_HEIGHT 32
|
||||
#define SCREEN_SIZE (SCREEN_WIDTH * SCREEN_HEIGHT)
|
||||
|
||||
#define KEYS_NUMBER 0x10
|
||||
|
||||
typedef struct s_flipper_state {
|
||||
uint16_t I;
|
||||
uint16_t PC;
|
||||
uint8_t SP;
|
||||
uint8_t* V; // CPU_REGISTER_NUMBER
|
||||
uint16_t* stack; // CPU_STACK_DEPTH
|
||||
uint8_t* memory; // MEMORY_SIZE
|
||||
uint8_t delay_timer;
|
||||
uint8_t sound_timer;
|
||||
uint8_t** screen; // SCREEN_HEIGHT * SCREEN_WIDTH
|
||||
uint8_t* key; // KEYS_NUMBER
|
||||
bool go_render;
|
||||
int current_opcode;
|
||||
int next_opcode;
|
||||
} t_chip8_state;
|
||||
|
||||
// keyboard layout
|
||||
// 1 2 3 C
|
||||
// 4 5 6 D
|
||||
// 7 8 9 E
|
||||
// A 0 B F
|
||||
typedef enum e_keys {
|
||||
k_x,
|
||||
k_1,
|
||||
k_2,
|
||||
k_3,
|
||||
k_q,
|
||||
k_w,
|
||||
k_e,
|
||||
k_a,
|
||||
k_s,
|
||||
k_d,
|
||||
k_z,
|
||||
k_c,
|
||||
k_4,
|
||||
k_r,
|
||||
k_f,
|
||||
k_v,
|
||||
} t_keys;
|
||||
|
||||
t_chip8_state* t_chip8_init(void* (*system_malloc)(size_t));
|
||||
bool t_chip8_load_game(t_chip8_state* state, const uint8_t* rom, int rom_size);
|
||||
void t_chip8_execute_next_opcode(t_chip8_state* state);
|
||||
void t_chip8_tick(t_chip8_state* state);
|
||||
uint8_t** t_chip8_get_screen(t_chip8_state* state);
|
||||
void t_chip8_free_memory(t_chip8_state* state, void (*system_free)(void*));
|
||||
void t_chip8_set_input(t_chip8_state* state, t_keys key);
|
||||
void t_chip8_release_input(t_chip8_state* state);
|
||||
|
||||
#endif //FLIPPER_CHIP_FLIPPER_CHIP_H
|
||||
@@ -1,30 +0,0 @@
|
||||
//
|
||||
// Created by dwdraugr on 24.11.2021.
|
||||
//
|
||||
|
||||
#ifndef FLIPPER_CHIP_FLIPPER_FONTS_H
|
||||
#define FLIPPER_CHIP_FLIPPER_FONTS_H
|
||||
|
||||
#define FONT_BYTES_PER_CHAR 5
|
||||
#define FONT_SMALL (16 * 5)
|
||||
|
||||
unsigned char font_small[FONT_SMALL] = {
|
||||
0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
||||
0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
||||
0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
||||
0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
||||
0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
||||
0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
||||
0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
||||
0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
||||
0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
||||
0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
||||
0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
||||
0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
||||
0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
||||
0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
||||
0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
||||
0xF0, 0x80, 0xF0, 0x80, 0x80 // F
|
||||
};
|
||||
|
||||
#endif //FLIPPER_CHIP_FLIPPER_FONTS_H
|
||||
@@ -1,26 +0,0 @@
|
||||
#include "chip8_scene.h"
|
||||
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const chip8_scene_on_enter_handlers[])(void*) = {
|
||||
#include "chip8_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const chip8_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "chip8_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const chip8_scene_on_exit_handlers[])(void* context) = {
|
||||
#include "chip8_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
const SceneManagerHandlers chip8_scene_handlers = {
|
||||
.on_enter_handlers = chip8_scene_on_enter_handlers,
|
||||
.on_event_handlers = chip8_scene_on_event_handlers,
|
||||
.on_exit_handlers = chip8_scene_on_exit_handlers,
|
||||
.scene_num = Chip8SceneNum,
|
||||
};
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#define ADD_SCENE(prefix, name, id) Chip8Scene##id,
|
||||
typedef enum {
|
||||
#include "chip8_scene_config.h"
|
||||
Chip8SceneNum,
|
||||
} Chip8Scene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers chip8_scene_handlers;
|
||||
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "chip8_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "chip8_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "chip8_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -1,2 +0,0 @@
|
||||
ADD_SCENE(chip8, file_select, FileSelect)
|
||||
ADD_SCENE(chip8, work, Work)
|
||||
@@ -1,45 +0,0 @@
|
||||
#include "../chip8_app_i.h"
|
||||
#include "furi_hal_power.h"
|
||||
|
||||
static bool chip8_file_select(Chip8App* chip8) {
|
||||
furi_assert(chip8);
|
||||
chip8->file_name = furi_string_alloc();
|
||||
furi_string_set(chip8->file_name, CHIP8_APP_PATH_FOLDER);
|
||||
// furi_string_set(file_path, chip8->file_name);
|
||||
|
||||
bool res = dialog_file_browser_show(
|
||||
chip8->dialogs,
|
||||
chip8->file_name,
|
||||
chip8->file_name,
|
||||
CHIP8_APP_EXTENSION,
|
||||
true,
|
||||
&I_unknown_10px,
|
||||
false);
|
||||
|
||||
FURI_LOG_I(
|
||||
"Chip8_file_browser_show", "chip8->file_name: %s", furi_string_get_cstr(chip8->file_name));
|
||||
FURI_LOG_I("Chip8_file_browser_show", "res: %d", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
void chip8_scene_file_select_on_enter(void* context) {
|
||||
Chip8App* chip8 = context;
|
||||
|
||||
if(chip8_file_select(chip8)) {
|
||||
FURI_LOG_I(
|
||||
"Chip8", "chip8_file_select, file_name = %s", furi_string_get_cstr(chip8->file_name));
|
||||
scene_manager_next_scene(chip8->scene_manager, Chip8WorkView);
|
||||
} else {
|
||||
view_dispatcher_stop(chip8->view_dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
bool chip8_scene_file_select_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void chip8_scene_file_select_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#include "../chip8_app_i.h"
|
||||
#include "../views/chip8_view.h"
|
||||
#include "furi_hal.h"
|
||||
|
||||
void chip8_scene_ok_callback(InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
Chip8App* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, type);
|
||||
}
|
||||
|
||||
void chip8_scene_back_callback(Chip8View* view, InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
Chip8App* app = context;
|
||||
chip8_set_back_pressed(app->chip8);
|
||||
chip8_set_state(view, chip8_get_state(app->chip8));
|
||||
// view_dispatcher_send_custom_event(app->view_dispatcher, type);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
|
||||
void chip8_scene_up_callback(InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
Chip8App* app = context;
|
||||
chip8_set_up_pressed(app->chip8);
|
||||
// view_dispatcher_send_custom_event(app->view_dispatcher, type);
|
||||
}
|
||||
|
||||
void chip8_scene_down_callback(InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
Chip8App* app = context;
|
||||
chip8_set_down_pressed(app->chip8);
|
||||
// view_dispatcher_send_custom_event(app->view_dispatcher, type);
|
||||
}
|
||||
|
||||
void chip8_scene_release_callback(InputType type, void* context) {
|
||||
furi_assert(context);
|
||||
Chip8App* app = context;
|
||||
chip8_release_keyboard(app->chip8);
|
||||
// view_dispatcher_send_custom_event(app->view_dispatcher, type);
|
||||
}
|
||||
|
||||
bool chip8_scene_work_on_event(void* context, SceneManagerEvent event) {
|
||||
Chip8App* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
chip8_toggle(app->chip8);
|
||||
consumed = true;
|
||||
} else if(event.type == SceneManagerEventTypeTick) {
|
||||
Chip8State* state = chip8_get_state(app->chip8);
|
||||
|
||||
chip8_set_state(app->chip8_view, state);
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void chip8_scene_work_on_enter(void* context) {
|
||||
Chip8App* app = context;
|
||||
|
||||
chip8_set_file_name(app->chip8_view, app->file_name);
|
||||
|
||||
FuriString* file_tmp;
|
||||
file_tmp = furi_string_alloc();
|
||||
|
||||
furi_string_printf(file_tmp, "%s", furi_string_get_cstr(app->file_name));
|
||||
|
||||
FURI_LOG_I("chip8_scene_work_on_enter", "file_name: %s", furi_string_get_cstr(file_tmp));
|
||||
|
||||
FURI_LOG_I("chip8_scene_work_on_enter", "START SET BACKUP SCREEN");
|
||||
chip8_set_backup_screen(app->chip8_view, app->backup_screen);
|
||||
FURI_LOG_I("chip8_scene_work_on_enter", "END SET BACKUP SCREEN");
|
||||
|
||||
app->chip8 = chip8_make_emulator(file_tmp);
|
||||
|
||||
furi_string_free(file_tmp);
|
||||
|
||||
chip8_set_state(app->chip8_view, chip8_get_state(app->chip8));
|
||||
|
||||
chip8_set_ok_callback(app->chip8_view, chip8_scene_ok_callback, app);
|
||||
chip8_set_back_callback(app->chip8_view, chip8_scene_back_callback, app);
|
||||
chip8_set_up_callback(app->chip8_view, chip8_scene_up_callback, app);
|
||||
chip8_set_down_callback(app->chip8_view, chip8_scene_down_callback, app);
|
||||
chip8_set_release_callback(app->chip8_view, chip8_scene_release_callback, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, Chip8WorkView);
|
||||
}
|
||||
|
||||
void chip8_scene_work_on_exit(void* context) {
|
||||
Chip8App* app = context;
|
||||
chip8_close_emulator(app->chip8);
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
#include <gui/elements.h>
|
||||
#include "chip8_view.h"
|
||||
#include "../chip8.h"
|
||||
#include "../emulator_core/flipper_chip.h"
|
||||
|
||||
struct Chip8View {
|
||||
View* view;
|
||||
Chip8ViewCallback callback;
|
||||
void* context;
|
||||
Chip8ViewKeyBackCallback backCallback;
|
||||
Chip8ViewKeyUpCallback upCallback;
|
||||
Chip8ViewKeyDownCallback downCallback;
|
||||
Chip8ViewReleaseCallback releaseCallback;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
FuriString* file_name;
|
||||
Chip8State state;
|
||||
uint8_t** backup_screen;
|
||||
} Chip8Model;
|
||||
|
||||
static void chip8_draw_callback(Canvas* canvas, void* _model) {
|
||||
Chip8Model* model = _model;
|
||||
|
||||
if(model->state.worker_state == WorkerStateLoadingRom) {
|
||||
canvas_draw_icon(canvas, 4, 22, &I_Clock_18x18);
|
||||
}
|
||||
|
||||
if(model->state.worker_state == WorkerStateRomLoaded) {
|
||||
while(!model->state.t_chip8_state->go_render) {
|
||||
for(int y = 0; y < CHIP8_SCREEN_H; y++) {
|
||||
for(int x = 0; x < CHIP8_SCREEN_W; x++) {
|
||||
if(model->backup_screen[y][x] == 0) {
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
canvas_draw_box(canvas, x * 2, y * 2, 2, 2);
|
||||
//canvas_draw_dot(canvas, x, y);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t** screen = t_chip8_get_screen(model->state.t_chip8_state);
|
||||
|
||||
for(int y = 0; y < CHIP8_SCREEN_H; y++) {
|
||||
for(int x = 0; x < CHIP8_SCREEN_W; x++) {
|
||||
if(screen[y][x] == 0) {
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
} else {
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
}
|
||||
canvas_draw_box(canvas, x * 2, y * 2, 2, 2);
|
||||
model->backup_screen[y][x] = screen[y][x];
|
||||
//canvas_draw_dot(canvas, x, y);
|
||||
}
|
||||
}
|
||||
model->state.t_chip8_state->go_render = false;
|
||||
}
|
||||
|
||||
if(model->state.worker_state == WorkerStateRomLoadError) {
|
||||
canvas_draw_icon(canvas, 4, 22, &I_Error_18x18);
|
||||
}
|
||||
}
|
||||
|
||||
static bool chip8_input_callback(InputEvent* event, void* context) {
|
||||
FURI_LOG_I("Chip8", "received input");
|
||||
furi_assert(context);
|
||||
Chip8View* chip8 = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyOk) {
|
||||
consumed = true;
|
||||
furi_assert(chip8->callback);
|
||||
chip8->callback(InputTypeShort, chip8->context);
|
||||
}
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
consumed = true;
|
||||
furi_assert(chip8->callback);
|
||||
chip8->backCallback(chip8, InputTypeShort, chip8->context);
|
||||
}
|
||||
|
||||
if(event->key == InputKeyUp) {
|
||||
consumed = true;
|
||||
furi_assert(chip8->upCallback);
|
||||
chip8->upCallback(InputTypeShort, chip8->context);
|
||||
}
|
||||
if(event->key == InputKeyDown) {
|
||||
consumed = true;
|
||||
furi_assert(chip8->downCallback);
|
||||
chip8->downCallback(InputTypeShort, chip8->context);
|
||||
}
|
||||
}
|
||||
if(event->type == InputTypeRelease) {
|
||||
chip8->releaseCallback(InputTypeShort, chip8->context);
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
Chip8View* chip8_alloc() {
|
||||
Chip8View* chip8 = malloc(sizeof(Chip8View));
|
||||
|
||||
chip8->view = view_alloc();
|
||||
view_allocate_model(chip8->view, ViewModelTypeLocking, sizeof(Chip8Model));
|
||||
view_set_context(chip8->view, chip8);
|
||||
view_set_draw_callback(chip8->view, chip8_draw_callback);
|
||||
view_set_input_callback(chip8->view, chip8_input_callback);
|
||||
|
||||
return chip8;
|
||||
}
|
||||
|
||||
void chip8_free(Chip8View* chip8) {
|
||||
furi_assert(chip8);
|
||||
view_free(chip8->view);
|
||||
free(chip8);
|
||||
}
|
||||
|
||||
View* chip8_get_view(Chip8View* chip8) {
|
||||
furi_assert(chip8);
|
||||
return chip8->view;
|
||||
}
|
||||
|
||||
void chip8_set_ok_callback(Chip8View* chip8, Chip8ViewCallback callback, void* context) {
|
||||
furi_assert(chip8);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
chip8->view, (Chip8Model * model) {
|
||||
chip8->callback = callback;
|
||||
chip8->context = context;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void chip8_set_back_callback(Chip8View* chip8, Chip8ViewKeyBackCallback callback, void* context) {
|
||||
furi_assert(chip8);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
chip8->view, (Chip8Model * model) {
|
||||
chip8->backCallback = callback;
|
||||
chip8->context = context;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void chip8_set_up_callback(Chip8View* chip8, Chip8ViewKeyUpCallback callback, void* context) {
|
||||
furi_assert(chip8);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
chip8->view, (Chip8Model * model) {
|
||||
chip8->upCallback = callback;
|
||||
chip8->context = context;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void chip8_set_down_callback(Chip8View* chip8, Chip8ViewKeyDownCallback callback, void* context) {
|
||||
furi_assert(chip8);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
chip8->view, (Chip8Model * model) {
|
||||
chip8->downCallback = callback;
|
||||
chip8->context = context;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void chip8_set_file_name(Chip8View* chip8, FuriString* name) {
|
||||
furi_assert(name);
|
||||
with_view_model(
|
||||
chip8->view, (Chip8Model * model) {
|
||||
*model->file_name = *name;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void chip8_set_backup_screen(Chip8View* chip8, uint8_t** screen) {
|
||||
furi_assert(screen);
|
||||
with_view_model(
|
||||
chip8->view, (Chip8Model * model) {
|
||||
model->backup_screen = screen;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void chip8_set_state(Chip8View* chip8, Chip8State* st) {
|
||||
furi_assert(st);
|
||||
with_view_model(
|
||||
chip8->view, (Chip8Model * model) {
|
||||
memcpy(&(model->state), st, sizeof(Chip8State));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
void chip8_set_release_callback(Chip8View* chip8, Chip8ViewReleaseCallback callback, void* context) {
|
||||
furi_assert(chip8);
|
||||
furi_assert(callback);
|
||||
with_view_model(
|
||||
chip8->view, (Chip8Model * model) {
|
||||
chip8->releaseCallback = callback;
|
||||
chip8->context = context;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
#include "../chip8.h"
|
||||
|
||||
typedef struct Chip8View Chip8View;
|
||||
typedef void (*Chip8ViewCallback)(InputType type, void* context);
|
||||
typedef void (*Chip8ViewKeyBackCallback)(Chip8View* view, InputType type, void* context);
|
||||
typedef void (*Chip8ViewKeyUpCallback)(InputType type, void* context);
|
||||
typedef void (*Chip8ViewKeyDownCallback)(InputType type, void* context);
|
||||
typedef void (*Chip8ViewReleaseCallback)(InputType type, void* context);
|
||||
|
||||
Chip8View* chip8_alloc();
|
||||
|
||||
void chip8_free(Chip8View* chip8);
|
||||
|
||||
View* chip8_get_view(Chip8View* chip8);
|
||||
|
||||
void chip8_set_ok_callback(Chip8View* chip8, Chip8ViewCallback callback, void* context);
|
||||
void chip8_set_back_callback(Chip8View* chip8, Chip8ViewKeyBackCallback callback, void* context);
|
||||
void chip8_set_up_callback(Chip8View* chip8, Chip8ViewKeyUpCallback callback, void* context);
|
||||
void chip8_set_down_callback(Chip8View* chip8, Chip8ViewKeyDownCallback callback, void* context);
|
||||
void chip8_set_release_callback(Chip8View* chip8, Chip8ViewReleaseCallback callback, void* context);
|
||||
|
||||
void chip8_set_backup_screen(Chip8View* chip8, uint8_t** screen);
|
||||
|
||||
void chip8_set_file_name(Chip8View* chip8, FuriString* name);
|
||||
|
||||
void chip8_set_state(Chip8View* chip8, Chip8State* st);
|
||||
@@ -39,7 +39,7 @@ static void tama_p1_hal_log(log_level_t level, char* buff, ...) {
|
||||
FuriString* string;
|
||||
va_list args;
|
||||
va_start(args, buff);
|
||||
string_init_vprintf(string, buff, args);
|
||||
furi_string_cat_vprintf(string, buff, args);
|
||||
va_end(args);
|
||||
|
||||
switch(level) {
|
||||
@@ -134,4 +134,4 @@ void tama_p1_hal_init(hal_t* hal) {
|
||||
hal->set_frequency = tama_p1_hal_set_frequency;
|
||||
hal->play_frequency = tama_p1_hal_play_frequency;
|
||||
hal->handler = tama_p1_hal_handler;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
App(
|
||||
appid="zBroken_Tanks",
|
||||
appid="Tanks",
|
||||
name="Tanks",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="tanks_game_app",
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#include <gui/gui.h>
|
||||
#include <input/input.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <lib/toolbox/args.h>
|
||||
#include <lib/subghz/receiver.h>
|
||||
#include <lib/subghz/subghz_keystore.h>
|
||||
@@ -1595,11 +1595,11 @@ int32_t tanks_game_app(void* p) {
|
||||
char arr[2];
|
||||
arr[0] = GoesUp;
|
||||
arr[1] = 0;
|
||||
string_set(goesUp, (char*)&arr);
|
||||
furi_string_set(goesUp, (char*)&arr);
|
||||
|
||||
subghz_tx_rx_worker_write(
|
||||
subghz_txrx,
|
||||
(uint8_t*)string_get_cstr(goesUp),
|
||||
(uint8_t*)furi_string_get_cstr(goesUp),
|
||||
strlen(furi_string_get_cstr(goesUp)));
|
||||
|
||||
} else {
|
||||
@@ -1619,11 +1619,11 @@ int32_t tanks_game_app(void* p) {
|
||||
char arr[2];
|
||||
arr[0] = GoesDown;
|
||||
arr[1] = 0;
|
||||
string_set(goesDown, (char*)&arr);
|
||||
furi_string_set(goesDown, (char*)&arr);
|
||||
|
||||
subghz_tx_rx_worker_write(
|
||||
subghz_txrx,
|
||||
(uint8_t*)string_get_cstr(goesDown),
|
||||
(uint8_t*)furi_string_get_cstr(goesDown),
|
||||
strlen(furi_string_get_cstr(goesDown)));
|
||||
} else {
|
||||
tanks_state->p1->moving = true;
|
||||
@@ -1636,11 +1636,11 @@ int32_t tanks_game_app(void* p) {
|
||||
char arr[2];
|
||||
arr[0] = GoesRight;
|
||||
arr[1] = 0;
|
||||
string_set(goesRight, (char*)&arr);
|
||||
furi_string_set(goesRight, (char*)&arr);
|
||||
|
||||
subghz_tx_rx_worker_write(
|
||||
subghz_txrx,
|
||||
(uint8_t*)string_get_cstr(goesRight),
|
||||
(uint8_t*)furi_string_get_cstr(goesRight),
|
||||
strlen(furi_string_get_cstr(goesRight)));
|
||||
} else {
|
||||
tanks_state->p1->moving = true;
|
||||
@@ -1653,11 +1653,11 @@ int32_t tanks_game_app(void* p) {
|
||||
char arr[2];
|
||||
arr[0] = GoesLeft;
|
||||
arr[1] = 0;
|
||||
string_set(goesLeft, (char*)&arr);
|
||||
furi_string_set(goesLeft, (char*)&arr);
|
||||
|
||||
subghz_tx_rx_worker_write(
|
||||
subghz_txrx,
|
||||
(uint8_t*)string_get_cstr(goesLeft),
|
||||
(uint8_t*)furi_string_get_cstr(goesLeft),
|
||||
strlen(furi_string_get_cstr(goesLeft)));
|
||||
} else {
|
||||
tanks_state->p1->moving = true;
|
||||
@@ -1686,11 +1686,11 @@ int32_t tanks_game_app(void* p) {
|
||||
char arr[2];
|
||||
arr[0] = Shoots;
|
||||
arr[1] = 0;
|
||||
string_set(shoots, (char*)&arr);
|
||||
furi_string_set(shoots, (char*)&arr);
|
||||
|
||||
subghz_tx_rx_worker_write(
|
||||
subghz_txrx,
|
||||
(uint8_t*)string_get_cstr(shoots),
|
||||
(uint8_t*)furi_string_get_cstr(shoots),
|
||||
strlen(furi_string_get_cstr(shoots)));
|
||||
} else {
|
||||
tanks_state->p1->shooting = true;
|
||||
@@ -1748,11 +1748,11 @@ int32_t tanks_game_app(void* p) {
|
||||
|
||||
arr[11 * 16] = 0;
|
||||
|
||||
string_set(serializedData, (char*)&arr);
|
||||
furi_string_set(serializedData, (char*)&arr);
|
||||
|
||||
subghz_tx_rx_worker_write(
|
||||
subghz_txrx,
|
||||
(uint8_t*)string_get_cstr(serializedData),
|
||||
(uint8_t*)furi_string_get_cstr(serializedData),
|
||||
strlen(furi_string_get_cstr(serializedData)));
|
||||
|
||||
tanks_state->sent++;
|
||||
|
||||
Reference in New Issue
Block a user