Rename plugins to external

This commit is contained in:
Willy-JL
2023-03-17 22:50:23 +00:00
parent b3c64d0428
commit b34a4f2468
1706 changed files with 15 additions and 15 deletions

View File

@@ -0,0 +1,14 @@
App(
appid="Brainfuck",
name="Brainfuck",
apptype=FlipperAppType.EXTERNAL,
entry_point="brainfuck_app",
requires=[
"storage",
"gui",
],
stack_size=8 * 1024,
fap_icon="bfico.png",
fap_category="Misc",
fap_icon_assets="icons",
)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,149 @@
#include "brainfuck_i.h"
/*
Due to the lack of documentation on the flipper i copied the picopass app,
ripped its insides out and used its hollow corpse to build this app inside of.
i dont know how this stuff works and after 6 hours of trying to learn it, i dont care
*/
bool brainfuck_custom_event_callback(void* context, uint32_t event) {
furi_assert(context);
BFApp* brainfuck = context;
return scene_manager_handle_custom_event(brainfuck->scene_manager, event);
}
bool brainfuck_back_event_callback(void* context) {
furi_assert(context);
BFApp* brainfuck = context;
return scene_manager_handle_back_event(brainfuck->scene_manager);
}
BFApp* brainfuck_alloc() {
BFApp* brainfuck = malloc(sizeof(BFApp));
brainfuck->dataSize = 0;
brainfuck->view_dispatcher = view_dispatcher_alloc();
brainfuck->scene_manager = scene_manager_alloc(&brainfuck_scene_handlers, brainfuck);
view_dispatcher_enable_queue(brainfuck->view_dispatcher);
view_dispatcher_set_event_callback_context(brainfuck->view_dispatcher, brainfuck);
view_dispatcher_set_custom_event_callback(
brainfuck->view_dispatcher, brainfuck_custom_event_callback);
view_dispatcher_set_navigation_event_callback(
brainfuck->view_dispatcher, brainfuck_back_event_callback);
// Open GUI record
brainfuck->gui = furi_record_open(RECORD_GUI);
view_dispatcher_attach_to_gui(
brainfuck->view_dispatcher, brainfuck->gui, ViewDispatcherTypeFullscreen);
// Open Notification record
brainfuck->notifications = furi_record_open(RECORD_NOTIFICATION);
// Submenu
brainfuck->submenu = submenu_alloc();
view_dispatcher_add_view(
brainfuck->view_dispatcher, brainfuckViewMenu, submenu_get_view(brainfuck->submenu));
// Popup
brainfuck->popup = popup_alloc();
view_dispatcher_add_view(
brainfuck->view_dispatcher, brainfuckViewPopup, popup_get_view(brainfuck->popup));
// Text Input
brainfuck->text_input = text_input_alloc();
view_dispatcher_add_view(
brainfuck->view_dispatcher,
brainfuckViewTextInput,
text_input_get_view(brainfuck->text_input));
// Textbox
brainfuck->text_box = text_box_alloc();
view_dispatcher_add_view(
brainfuck->view_dispatcher, brainfuckViewTextBox, text_box_get_view(brainfuck->text_box));
brainfuck->text_box_store = furi_string_alloc();
// Dev environment
brainfuck->BF_dev_env = bf_dev_env_alloc(brainfuck);
view_dispatcher_add_view(
brainfuck->view_dispatcher, brainfuckViewDev, bf_dev_env_get_view(brainfuck->BF_dev_env));
// File path
brainfuck->BF_file_path = furi_string_alloc();
return brainfuck;
}
void brainfuck_free(BFApp* brainfuck) {
furi_assert(brainfuck);
// Submenu
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewMenu);
submenu_free(brainfuck->submenu);
// Popup
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewPopup);
popup_free(brainfuck->popup);
// TextInput
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewTextInput);
text_input_free(brainfuck->text_input);
// TextBox
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewTextBox);
text_box_free(brainfuck->text_box);
furi_string_free(brainfuck->text_box_store);
//dev env
view_dispatcher_remove_view(brainfuck->view_dispatcher, brainfuckViewDev);
bf_dev_env_free(brainfuck->BF_dev_env);
// View Dispatcher
view_dispatcher_free(brainfuck->view_dispatcher);
// Scene Manager
scene_manager_free(brainfuck->scene_manager);
// GUI
furi_record_close(RECORD_GUI);
brainfuck->gui = NULL;
// Notifications
furi_record_close(RECORD_NOTIFICATION);
brainfuck->notifications = NULL;
free(brainfuck);
}
void brainfuck_show_loading_popup(void* context, bool show) {
BFApp* brainfuck = context;
TaskHandle_t timer_task = xTaskGetHandle(configTIMER_SERVICE_TASK_NAME);
if(show) {
// Raise timer priority so that animations can play
vTaskPrioritySet(timer_task, configMAX_PRIORITIES - 1);
view_dispatcher_switch_to_view(brainfuck->view_dispatcher, brainfuckViewLoading);
} else {
// Restore default timer priority
vTaskPrioritySet(timer_task, configTIMER_TASK_PRIORITY);
}
}
int32_t brainfuck_app(void* p) {
UNUSED(p);
BFApp* brainfuck = brainfuck_alloc();
if(!brainfuck) {
return 0;
}
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_simply_mkdir(storage, "/ext/brainfuck");
scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneStart);
view_dispatcher_run(brainfuck->view_dispatcher);
brainfuck_free(brainfuck);
return 0;
}

View File

@@ -0,0 +1,3 @@
#pragma once
typedef struct BFApp BFApp;

View File

@@ -0,0 +1,89 @@
#pragma once
typedef struct BFDevEnv BFDevEnv;
typedef struct BFExecEnv BFExecEnv;
typedef unsigned char byte;
#include "brainfuck.h"
#include "worker.h"
#include <furi.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/scene_manager.h>
#include <notification/notification_messages.h>
#include <gui/modules/submenu.h>
#include <gui/modules/popup.h>
#include <gui/modules/loading.h>
#include <gui/modules/text_input.h>
#include <gui/modules/widget.h>
#include <gui/modules/text_box.h>
#include <dialogs/dialogs.h>
#include <input/input.h>
#include "scenes/brainfuck_scene.h"
#include "views/bf_dev_env.h"
#include <storage/storage.h>
#include <lib/toolbox/path.h>
#include <Brainfuck_icons.h>
#include <storage/storage.h>
#include <stream/stream.h>
#include <stream/buffered_file_stream.h>
#include <toolbox/stream/file_stream.h>
#include <notification/notification_messages.h>
#include <notification/notification_app.h>
#define BF_INST_BUFFER_SIZE 2048
#define BF_OUTPUT_SIZE 512
#define BF_STACK_INITIAL_SIZE 128
#define BF_INPUT_BUFFER_SIZE 64
#define BF_STACK_STEP_SIZE 32
enum brainfuckCustomEvent {
// Reserve first 100 events for button types and indexes, starting from 0
brainfuckCustomEventReserved = 100,
brainfuckCustomEventViewExit,
brainfuckCustomEventWorkerExit,
brainfuckCustomEventByteInputDone,
brainfuckCustomEventTextInputDone,
};
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
struct BFApp {
ViewDispatcher* view_dispatcher;
Gui* gui;
NotificationApp* notifications;
SceneManager* scene_manager;
Submenu* submenu;
Popup* popup;
TextInput* text_input;
TextBox* text_box;
FuriString* text_box_store;
FuriString* BF_file_path;
BFDevEnv* BF_dev_env;
int dataSize;
char dataBuffer[BF_INST_BUFFER_SIZE];
char inputBuffer[BF_INPUT_BUFFER_SIZE];
};
typedef enum {
brainfuckViewMenu,
brainfuckViewPopup,
brainfuckViewLoading,
brainfuckViewTextInput,
brainfuckViewTextBox,
brainfuckViewWidget,
brainfuckViewDev,
brainfuckViewExec,
} brainfuckView;

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,30 @@
#include "brainfuck_scene.h"
// Generate scene on_enter handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
void (*const brainfuck_on_enter_handlers[])(void*) = {
#include "brainfuck_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_event handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
bool (*const brainfuck_on_event_handlers[])(void* context, SceneManagerEvent event) = {
#include "brainfuck_scene_config.h"
};
#undef ADD_SCENE
// Generate scene on_exit handlers array
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
void (*const brainfuck_on_exit_handlers[])(void* context) = {
#include "brainfuck_scene_config.h"
};
#undef ADD_SCENE
// Initialize scene handlers configuration structure
const SceneManagerHandlers brainfuck_scene_handlers = {
.on_enter_handlers = brainfuck_on_enter_handlers,
.on_event_handlers = brainfuck_on_event_handlers,
.on_exit_handlers = brainfuck_on_exit_handlers,
.scene_num = brainfuckSceneNum,
};

View File

@@ -0,0 +1,29 @@
#pragma once
#include <gui/scene_manager.h>
// Generate scene id and total number
#define ADD_SCENE(prefix, name, id) brainfuckScene##id,
typedef enum {
#include "brainfuck_scene_config.h"
brainfuckSceneNum,
} brainfuckScene;
#undef ADD_SCENE
extern const SceneManagerHandlers brainfuck_scene_handlers;
// Generate scene on_enter handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
#include "brainfuck_scene_config.h"
#undef ADD_SCENE
// Generate scene on_event handlers declaration
#define ADD_SCENE(prefix, name, id) \
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
#include "brainfuck_scene_config.h"
#undef ADD_SCENE
// Generate scene on_exit handlers declaration
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
#include "brainfuck_scene_config.h"
#undef ADD_SCENE

View File

@@ -0,0 +1,6 @@
ADD_SCENE(brainfuck, start, Start)
ADD_SCENE(brainfuck, file_select, FileSelect)
ADD_SCENE(brainfuck, file_create, FileCreate)
ADD_SCENE(brainfuck, dev_env, DevEnv)
ADD_SCENE(brainfuck, exec_env, ExecEnv)
ADD_SCENE(brainfuck, set_input, SetInput)

View File

@@ -0,0 +1,16 @@
#include "../brainfuck_i.h"
void brainfuck_scene_dev_env_on_enter(void* context) {
BFApp* app = context;
view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewDev);
}
bool brainfuck_scene_dev_env_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void brainfuck_scene_dev_env_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,16 @@
#include "../brainfuck_i.h"
void brainfuck_scene_exec_env_on_enter(void* context) {
BFApp* app = context;
view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextBox);
}
bool brainfuck_scene_exec_env_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void brainfuck_scene_exec_env_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,50 @@
#include "../brainfuck_i.h"
void file_name_text_input_callback(void* context) {
BFApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, brainfuckCustomEventTextInputDone);
}
char tmpName[64] = {};
byte empty[1] = {0x00};
void brainfuck_scene_file_create_on_enter(void* context) {
BFApp* app = context;
TextInput* text_input = app->text_input;
text_input_set_header_text(text_input, "New script name");
text_input_set_result_callback(
text_input, file_name_text_input_callback, app, tmpName, 64, true);
view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextInput);
}
bool brainfuck_scene_file_create_on_event(void* context, SceneManagerEvent event) {
BFApp* app = context;
UNUSED(app);
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == brainfuckCustomEventTextInputDone) {
furi_string_cat_printf(app->BF_file_path, "/ext/brainfuck/%s.b", tmpName);
//remove old file
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_simply_remove(storage, furi_string_get_cstr(app->BF_file_path));
//save new file
Stream* stream = buffered_file_stream_alloc(storage);
buffered_file_stream_open(
stream, furi_string_get_cstr(app->BF_file_path), FSAM_WRITE, FSOM_CREATE_ALWAYS);
stream_write(stream, (const uint8_t*)empty, 1);
buffered_file_stream_close(stream);
//scene_manager_next_scene(app->scene_manager, brainfuckSceneFileSelect);
scene_manager_next_scene(app->scene_manager, brainfuckSceneDevEnv);
}
}
return consumed;
}
void brainfuck_scene_file_create_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,34 @@
#include "../brainfuck_i.h"
void brainfuck_scene_file_select_on_enter(void* context) {
BFApp* app = context;
DialogsApp* dialogs = furi_record_open("dialogs");
FuriString* path;
path = furi_string_alloc();
furi_string_set(path, "/ext/brainfuck");
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, ".b", &I_bfico);
browser_options.base_path = "/ext/brainfuck";
browser_options.hide_ext = false;
bool selected = dialog_file_browser_show(dialogs, path, path, &browser_options);
if(selected) {
furi_string_set(app->BF_file_path, path);
scene_manager_next_scene(app->scene_manager, brainfuckSceneDevEnv);
} else {
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, brainfuckSceneStart);
}
}
bool brainfuck_scene_file_select_on_event(void* context, SceneManagerEvent event) {
UNUSED(context);
UNUSED(event);
return false;
}
void brainfuck_scene_file_select_on_exit(void* context) {
UNUSED(context);
}

View File

@@ -0,0 +1,35 @@
#include "../brainfuck_i.h"
void set_input_text_input_callback(void* context) {
BFApp* app = context;
view_dispatcher_send_custom_event(app->view_dispatcher, brainfuckCustomEventTextInputDone);
}
void brainfuck_scene_set_input_on_enter(void* context) {
BFApp* app = context;
TextInput* text_input = app->text_input;
text_input_set_header_text(text_input, "Edit input buffer");
text_input_set_result_callback(
text_input, set_input_text_input_callback, app, app->inputBuffer, 64, true);
view_dispatcher_switch_to_view(app->view_dispatcher, brainfuckViewTextInput);
}
bool brainfuck_scene_set_input_on_event(void* context, SceneManagerEvent event) {
BFApp* app = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == brainfuckCustomEventTextInputDone) {
scene_manager_search_and_switch_to_previous_scene(
app->scene_manager, brainfuckSceneDevEnv);
}
}
return consumed;
}
void brainfuck_scene_set_input_on_exit(void* context) {
BFApp* app = context;
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, brainfuckSceneDevEnv);
}

View File

@@ -0,0 +1,55 @@
#include "../brainfuck_i.h"
enum SubmenuIndex {
SubmenuIndexNew,
SubmenuIndexOpen,
SubmenuIndexAbout,
};
void brainfuck_scene_start_submenu_callback(void* context, uint32_t index) {
BFApp* brainfuck = context;
view_dispatcher_send_custom_event(brainfuck->view_dispatcher, index);
}
void brainfuck_scene_start_on_enter(void* context) {
BFApp* brainfuck = context;
Submenu* submenu = brainfuck->submenu;
submenu_add_item(
submenu, "New", SubmenuIndexNew, brainfuck_scene_start_submenu_callback, brainfuck);
submenu_add_item(
submenu, "Open", SubmenuIndexOpen, brainfuck_scene_start_submenu_callback, brainfuck);
submenu_add_item(
submenu, "About", SubmenuIndexAbout, brainfuck_scene_start_submenu_callback, brainfuck);
submenu_set_selected_item(
submenu, scene_manager_get_scene_state(brainfuck->scene_manager, brainfuckSceneStart));
view_dispatcher_switch_to_view(brainfuck->view_dispatcher, brainfuckViewMenu);
}
bool brainfuck_scene_start_on_event(void* context, SceneManagerEvent event) {
BFApp* brainfuck = context;
bool consumed = false;
if(event.type == SceneManagerEventTypeCustom) {
if(event.event == SubmenuIndexNew) {
scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneFileCreate);
consumed = true;
} else if(event.event == SubmenuIndexOpen) {
scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneFileSelect);
consumed = true;
} else if(event.event == SubmenuIndexAbout) {
text_box_set_text(
brainfuck->text_box,
"FlipperBrainfuck\n\nAn F0 brainfuck intepretor\nBy github.com/Nymda");
scene_manager_next_scene(brainfuck->scene_manager, brainfuckSceneExecEnv);
consumed = true;
}
scene_manager_set_scene_state(brainfuck->scene_manager, brainfuckSceneStart, event.event);
}
return consumed;
}
void brainfuck_scene_start_on_exit(void* context) {
BFApp* brainfuck = context;
submenu_reset(brainfuck->submenu);
}

View File

@@ -0,0 +1,423 @@
#include "bf_dev_env.h"
#include <gui/elements.h>
typedef struct BFDevEnv {
View* view;
DevEnvOkCallback callback;
void* context;
BFApp* appDev;
} BFDevEnv;
typedef struct {
uint32_t row;
uint32_t col;
} BFDevEnvModel;
typedef struct {
int up;
int down;
int left;
int right;
} bMapping;
static bool bf_dev_process_up(BFDevEnv* devEnv);
static bool bf_dev_process_down(BFDevEnv* devEnv);
static bool bf_dev_process_left(BFDevEnv* devEnv);
static bool bf_dev_process_right(BFDevEnv* devEnv);
static bool bf_dev_process_ok(BFDevEnv* devEnv, InputEvent* event);
BFApp* appDev;
FuriThread* workerThread;
char bfChars[9] = {'<', '>', '[', ']', '+', '-', '.', ',', 0x00};
int selectedButton = 0;
int saveNotifyCountdown = 0;
int execCountdown = 0;
char dspLine0[25] = {0x00};
char dspLine1[25] = {0x00};
char dspLine2[25] = {0x00};
static bMapping buttonMappings[12] = {
{8, 8, 7, 1}, //0
{8, 8, 0, 2}, //1
{9, 9, 1, 3}, //2
{9, 9, 2, 4}, //3
{10, 10, 3, 5}, //4
{10, 10, 4, 6}, //5
{11, 11, 5, 7}, //6
{11, 11, 6, 0}, //7
{0, 0, 11, 9}, //8
{3, 3, 8, 10}, //9
{5, 5, 9, 11}, //10
{6, 6, 10, 8} //11
};
#define BT_X 14
#define BT_Y 14
static void bf_dev_draw_button(Canvas* canvas, int x, int y, bool selected, const char* lbl) {
UNUSED(lbl);
if(selected) {
canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3);
canvas_invert_color(canvas);
canvas_set_font(canvas, FontBatteryPercent);
canvas_draw_str_aligned(
canvas, x + (BT_X / 2), y + (BT_Y / 2) - 1, AlignCenter, AlignCenter, lbl);
canvas_invert_color(canvas);
} else {
canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3);
canvas_invert_color(canvas);
canvas_draw_rbox(canvas, x + 2, y - 1, BT_X - 2, BT_Y - 1, 3);
canvas_invert_color(canvas);
canvas_draw_rframe(canvas, x, y, BT_X, BT_Y, 3);
canvas_set_font(canvas, FontBatteryPercent);
canvas_draw_str_aligned(
canvas, x + (BT_X / 2), y + (BT_Y / 2) - 1, AlignCenter, AlignCenter, lbl);
}
}
void bf_save_changes() {
//remove old file
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_simply_remove(storage, furi_string_get_cstr(appDev->BF_file_path));
//save new file
Stream* stream = buffered_file_stream_alloc(storage);
buffered_file_stream_open(
stream, furi_string_get_cstr(appDev->BF_file_path), FSAM_WRITE, FSOM_CREATE_ALWAYS);
stream_write(stream, (const uint8_t*)appDev->dataBuffer, appDev->dataSize);
buffered_file_stream_close(stream);
}
static void bf_dev_draw_callback(Canvas* canvas, void* _model) {
UNUSED(_model);
if(saveNotifyCountdown > 0) {
canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "SAVED");
saveNotifyCountdown--;
return;
}
bf_dev_draw_button(canvas, 1, 36, (selectedButton == 0), "+"); //T 0
bf_dev_draw_button(canvas, 17, 36, (selectedButton == 1), "-"); //T 1
bf_dev_draw_button(canvas, 33, 36, (selectedButton == 2), "<"); //T 2
bf_dev_draw_button(canvas, 49, 36, (selectedButton == 3), ">"); //T 3
bf_dev_draw_button(canvas, 65, 36, (selectedButton == 4), "["); //B 0
bf_dev_draw_button(canvas, 81, 36, (selectedButton == 5), "]"); //B 1
bf_dev_draw_button(canvas, 97, 36, (selectedButton == 6), "."); //B 2
bf_dev_draw_button(canvas, 113, 36, (selectedButton == 7), ","); //B 3
//backspace, input, run, save
canvas_draw_icon(
canvas,
1,
52,
(selectedButton == 8) ? &I_KeyBackspaceSelected_24x11 : &I_KeyBackspace_24x11);
canvas_draw_icon(
canvas, 45, 52, (selectedButton == 9) ? &I_KeyInputSelected_30x11 : &I_KeyInput_30x11);
canvas_draw_icon(
canvas, 77, 52, (selectedButton == 10) ? &I_KeyRunSelected_24x11 : &I_KeyRun_24x11);
canvas_draw_icon(
canvas, 103, 52, (selectedButton == 11) ? &I_KeySaveSelected_24x11 : &I_KeySave_24x11);
if(saveNotifyCountdown > 0) {
canvas_draw_icon(canvas, 98, 54, &I_ButtonRightSmall_3x5);
saveNotifyCountdown--;
}
//textbox
//grossly overcomplicated. not fixing it.
canvas_draw_rframe(canvas, 1, 1, 126, 33, 2);
canvas_set_font(canvas, FontBatteryPercent);
int dbOffset = 0;
if(appDev->dataSize > 72) {
dbOffset = (appDev->dataSize - 72);
}
memset(dspLine0, 0x00, 25);
memset(dspLine1, 0x00, 25);
memset(dspLine2, 0x00, 25);
int tpM = 0;
int tp0 = 0;
int tp1 = 0;
int tp2 = 0;
for(int p = dbOffset; p < appDev->dataSize; p++) {
if(tpM < 24 * 1) {
dspLine0[tp0] = appDev->dataBuffer[p];
tp0++;
} else if(tpM < 24 * 2) {
dspLine1[tp1] = appDev->dataBuffer[p];
tp1++;
} else if(tpM < 24 * 3) {
dspLine2[tp2] = appDev->dataBuffer[p];
tp2++;
}
tpM++;
}
canvas_draw_str_aligned(canvas, 3, 8, AlignLeft, AlignCenter, dspLine0);
canvas_draw_str_aligned(canvas, 3, 17, AlignLeft, AlignCenter, dspLine1);
canvas_draw_str_aligned(canvas, 3, 26, AlignLeft, AlignCenter, dspLine2);
}
static bool bf_dev_input_callback(InputEvent* event, void* context) {
furi_assert(context);
BFDevEnv* devEnv = context;
bool consumed = false;
if(event->type == InputTypeShort) {
if(event->key == InputKeyRight) {
consumed = bf_dev_process_right(devEnv);
} else if(event->key == InputKeyLeft) {
consumed = bf_dev_process_left(devEnv);
} else if(event->key == InputKeyUp) {
consumed = bf_dev_process_up(devEnv);
} else if(event->key == InputKeyDown) {
consumed = bf_dev_process_down(devEnv);
}
} else if(event->key == InputKeyOk) {
consumed = bf_dev_process_ok(devEnv, event);
}
return consumed;
}
static bool bf_dev_process_up(BFDevEnv* devEnv) {
UNUSED(devEnv);
selectedButton = buttonMappings[selectedButton].up;
return true;
}
static bool bf_dev_process_down(BFDevEnv* devEnv) {
UNUSED(devEnv);
selectedButton = buttonMappings[selectedButton].down;
return true;
}
static bool bf_dev_process_left(BFDevEnv* devEnv) {
UNUSED(devEnv);
selectedButton = buttonMappings[selectedButton].left;
return true;
}
static bool bf_dev_process_right(BFDevEnv* devEnv) {
UNUSED(devEnv);
selectedButton = buttonMappings[selectedButton].right;
return true;
}
static bool bf_dev_process_ok(BFDevEnv* devEnv, InputEvent* event) {
UNUSED(devEnv);
UNUSED(event);
if(event->type != InputTypePress) {
return false;
}
switch(selectedButton) {
case 0: {
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
appDev->dataBuffer[appDev->dataSize] = '+';
appDev->dataSize++;
}
break;
}
case 1: {
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
appDev->dataBuffer[appDev->dataSize] = '-';
appDev->dataSize++;
}
break;
}
case 2: {
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
appDev->dataBuffer[appDev->dataSize] = '<';
appDev->dataSize++;
}
break;
}
case 3: {
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
appDev->dataBuffer[appDev->dataSize] = '>';
appDev->dataSize++;
}
break;
}
case 4: {
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
appDev->dataBuffer[appDev->dataSize] = '[';
appDev->dataSize++;
}
break;
}
case 5: {
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
appDev->dataBuffer[appDev->dataSize] = ']';
appDev->dataSize++;
}
break;
}
case 6: {
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
appDev->dataBuffer[appDev->dataSize] = '.';
appDev->dataSize++;
}
break;
}
case 7: {
if(appDev->dataSize < BF_INST_BUFFER_SIZE) {
appDev->dataBuffer[appDev->dataSize] = ',';
appDev->dataSize++;
}
break;
}
case 8: {
if(appDev->dataSize > 0) {
appDev->dataSize--;
appDev->dataBuffer[appDev->dataSize] = (uint32_t)0x00;
}
break;
}
case 9: {
scene_manager_next_scene(appDev->scene_manager, brainfuckSceneSetInput);
break;
}
case 10: {
if(getStatus() != 0) {
killThread();
furi_thread_join(workerThread);
}
bf_save_changes();
initWorker(appDev);
text_box_set_focus(appDev->text_box, TextBoxFocusEnd);
text_box_set_text(appDev->text_box, workerGetOutput());
workerThread = furi_thread_alloc_ex("Worker", 2048, (void*)beginWorker, NULL);
furi_thread_start(workerThread);
scene_manager_next_scene(appDev->scene_manager, brainfuckSceneExecEnv);
break;
}
case 11: {
bf_save_changes();
saveNotifyCountdown = 3;
break;
}
}
bool consumed = false;
return consumed;
}
static void bf_dev_enter_callback(void* context) {
furi_assert(context);
BFDevEnv* devEnv = context;
with_view_model(
devEnv->view,
BFDevEnvModel * model,
{
model->col = 0;
model->row = 0;
},
true);
appDev = devEnv->appDev;
selectedButton = 0;
//exit the running thread if required
if(getStatus() != 0) {
killThread();
furi_thread_join(workerThread);
}
//clear the bf instruction buffer
memset(appDev->dataBuffer, 0x00, BF_INST_BUFFER_SIZE * sizeof(char));
//open the file
Storage* storage = furi_record_open(RECORD_STORAGE);
Stream* stream = buffered_file_stream_alloc(storage);
buffered_file_stream_open(
stream, furi_string_get_cstr(appDev->BF_file_path), FSAM_READ, FSOM_OPEN_EXISTING);
//read into the buffer
appDev->dataSize = stream_size(stream);
if(appDev->dataSize > 2000) {
return; //BF file is too large
}
stream_read(stream, (uint8_t*)appDev->dataBuffer, appDev->dataSize);
buffered_file_stream_close(stream);
//replaces any invalid characters with an underscore. strips out newlines, comments, etc
for(int i = 0; i < appDev->dataSize; i++) {
if(!strchr(bfChars, appDev->dataBuffer[i])) {
appDev->dataBuffer[i] = '_';
}
}
//find the end of the file to begin editing
int tptr = 0;
while(appDev->dataBuffer[tptr] != 0x00) {
tptr++;
}
appDev->dataSize = tptr;
}
BFDevEnv* bf_dev_env_alloc(BFApp* appDev) {
BFDevEnv* devEnv = malloc(sizeof(BFDevEnv));
devEnv->view = view_alloc();
devEnv->appDev = appDev;
view_allocate_model(devEnv->view, ViewModelTypeLocking, sizeof(BFDevEnvModel));
with_view_model(
devEnv->view,
BFDevEnvModel * model,
{
model->col = 0;
model->row = 0;
},
true);
view_set_context(devEnv->view, devEnv);
view_set_draw_callback(devEnv->view, bf_dev_draw_callback);
view_set_input_callback(devEnv->view, bf_dev_input_callback);
view_set_enter_callback(devEnv->view, bf_dev_enter_callback);
return devEnv;
}
void bf_dev_env_free(BFDevEnv* devEnv) {
if(getStatus() != 0) {
killThread();
furi_thread_join(workerThread);
}
furi_assert(devEnv);
view_free(devEnv->view);
free(devEnv);
}
View* bf_dev_env_get_view(BFDevEnv* devEnv) {
furi_assert(devEnv);
return devEnv->view;
}

View File

@@ -0,0 +1,15 @@
#pragma once
#include "../brainfuck_i.h"
#include <gui/view.h>
typedef void (*DevEnvOkCallback)(InputType type, void* context);
BFDevEnv* bf_dev_env_alloc(BFApp* application);
void bf_dev_set_file_path(FuriString* path);
void bf_dev_env_free(BFDevEnv* devEnv);
View* bf_dev_env_get_view(BFDevEnv* devEnv);
void bf_dev_env_set_ok(BFDevEnv* devEnv, DevEnvOkCallback callback, void* context);

291
applications/external/brainfuck/worker.c vendored Normal file
View File

@@ -0,0 +1,291 @@
#include "worker.h"
#include <furi_hal_resources.h>
#include <furi.h>
bool killswitch = false;
int status = 0; //0: idle, 1: running, 2: failure
char* inst = 0;
int instCount = 0;
int instPtr = 0;
int runOpCount = 0;
char* wOutput = 0;
int wOutputPtr = 0;
char* wInput = 0;
int wInputPtr = 0;
uint8_t* bfStack = 0;
int stackPtr = 0;
int stackSize = BF_STACK_INITIAL_SIZE;
int stackSizeReal = 0;
BFApp* wrkrApp = 0;
void killThread() {
killswitch = true;
}
bool validateInstPtr() {
if(instPtr > instCount || instPtr < 0) {
return false;
}
return true;
}
bool validateStackPtr() {
if(stackPtr > stackSize || stackPtr < 0) {
return false;
}
return true;
}
char* workerGetOutput() {
return wOutput;
}
int getStackSize() {
return stackSizeReal;
}
int getOpCount() {
return runOpCount;
}
int getStatus() {
return status;
}
void initWorker(BFApp* app) {
wrkrApp = app;
//rebuild output
if(wOutput) {
free(wOutput);
}
wOutput = (char*)malloc(BF_OUTPUT_SIZE);
wOutputPtr = 0;
//rebuild stack
if(bfStack) {
free(bfStack);
}
bfStack = (uint8_t*)malloc(BF_STACK_INITIAL_SIZE);
memset(bfStack, 0x00, BF_STACK_INITIAL_SIZE);
stackSize = BF_STACK_INITIAL_SIZE;
stackSizeReal = 0;
stackPtr = 0;
//set instructions
inst = wrkrApp->dataBuffer;
instCount = wrkrApp->dataSize;
instPtr = 0;
runOpCount = 0;
//set input
wInput = wrkrApp->inputBuffer;
wInputPtr = 0;
//set status
status = 0;
}
void rShift() {
runOpCount++;
stackPtr++;
if(!validateStackPtr()) {
status = 2;
return;
}
while(stackPtr > stackSize) {
stackSize += BF_STACK_STEP_SIZE;
void* tmp = realloc(bfStack, stackSize);
if(!tmp) {
status = 2;
return;
}
memset((tmp + stackSize) - BF_STACK_STEP_SIZE, 0x00, BF_STACK_STEP_SIZE);
bfStack = (uint8_t*)tmp;
};
if(stackPtr > stackSizeReal) {
stackSizeReal = stackPtr;
}
}
void lShift() {
runOpCount++;
stackPtr--;
if(!validateStackPtr()) {
status = 2;
return;
}
}
void inc() {
runOpCount++;
if(!validateStackPtr()) {
status = 2;
return;
}
bfStack[stackPtr]++;
}
void dec() {
runOpCount++;
if(!validateStackPtr()) {
status = 2;
return;
}
bfStack[stackPtr]--;
}
void print() {
runOpCount++;
wOutput[wOutputPtr] = bfStack[stackPtr];
wOutputPtr++;
if(wOutputPtr > (BF_OUTPUT_SIZE - 1)) {
wOutputPtr = 0;
}
}
void input() {
runOpCount++;
bfStack[stackPtr] = (uint8_t)wInput[wInputPtr];
if(wInput[wInputPtr] == 0x00 || wInputPtr >= 64) {
wInputPtr = 0;
} else {
wInputPtr++;
}
}
void loop() {
runOpCount++;
if(bfStack[stackPtr] == 0) {
int loopCount = 1;
while(loopCount > 0) {
instPtr++;
if(!validateInstPtr()) {
status = 2;
return;
}
if(inst[instPtr] == '[') {
loopCount++;
} else if(inst[instPtr] == ']') {
loopCount--;
}
}
}
}
void endLoop() {
runOpCount++;
if(bfStack[stackPtr] != 0) {
int loopCount = 1;
while(loopCount > 0) {
instPtr--;
if(!validateInstPtr()) {
status = 2;
return;
}
if(inst[instPtr] == ']') {
loopCount++;
} else if(inst[instPtr] == '[') {
loopCount--;
}
}
}
}
static const NotificationSequence led_on = {
&message_blue_255,
&message_do_not_reset,
NULL,
};
static const NotificationSequence led_off = {
&message_blue_0,
NULL,
};
void input_kill(void* _ctx) {
UNUSED(_ctx);
killswitch = true;
}
void beginWorker() {
status = 1;
//redefined from furi_hal_resources.c
const GpioPin gpio_button_back = {.port = GPIOC, .pin = LL_GPIO_PIN_13};
while(inst[instPtr] != 0x00) {
if(runOpCount % 500 == 0) {
text_box_set_text(wrkrApp->text_box, workerGetOutput());
notification_message(wrkrApp->notifications, &led_on);
}
//status 2 indicates failure
if(status == 2) {
status = 0;
break;
}
//read back button directly to avoid weirdness in furi
if(killswitch || !furi_hal_gpio_read(&gpio_button_back)) {
status = 0;
killswitch = false;
break;
}
switch(inst[instPtr]) {
case '>':
rShift();
break;
case '<':
lShift();
break;
case '+':
inc();
break;
case '-':
dec();
break;
case '.':
print();
break;
case ',':
input();
break;
case '[':
loop();
break;
case ']':
endLoop();
break;
default:
break;
}
instPtr++;
if(!validateInstPtr()) {
status = 0;
break;
}
}
notification_message(wrkrApp->notifications, &led_off);
text_box_set_text(wrkrApp->text_box, workerGetOutput());
status = 0;
}

View File

@@ -0,0 +1,9 @@
#include "brainfuck_i.h"
void initWorker(BFApp* application);
char* workerGetOutput();
int getStackSize();
int getOpCount();
int getStatus();
void beginWorker();
void killThread();