Files
Momentum-Firmware/applications/external/brainfuck/worker.c
2023-03-17 22:50:23 +00:00

291 lines
5.3 KiB
C

#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;
}