This commit is contained in:
RogueMaster
2022-10-13 21:46:26 -04:00
19 changed files with 16 additions and 1243 deletions
-203
View File
@@ -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");
}
-44
View File
@@ -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
-89
View File
@@ -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;
}
-11
View File
@@ -1,11 +0,0 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
typedef struct Chip8App Chip8App;
#ifdef __cplusplus
}
#endif
-33
View File
@@ -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);
+2 -2
View File
@@ -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",
+13 -13
View File
@@ -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++;