bf_dev_env.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. #include "bf_dev_env.h"
  2. #include <gui/elements.h>
  3. typedef struct BFDevEnv {
  4. View* view;
  5. DevEnvOkCallback callback;
  6. void* context;
  7. BFApp* appDev;
  8. } BFDevEnv;
  9. typedef struct {
  10. uint32_t row;
  11. uint32_t col;
  12. } BFDevEnvModel;
  13. typedef struct{
  14. int up;
  15. int down;
  16. int left;
  17. int right;
  18. }bMapping;
  19. static bool bf_dev_process_up(BFDevEnv* devEnv);
  20. static bool bf_dev_process_down(BFDevEnv* devEnv);
  21. static bool bf_dev_process_left(BFDevEnv* devEnv);
  22. static bool bf_dev_process_right(BFDevEnv* devEnv);
  23. static bool bf_dev_process_ok(BFDevEnv* devEnv, InputEvent* event);
  24. BFApp* appDev;
  25. FuriThread* workerThread;
  26. char bfChars[9] = {'<', '>', '[', ']', '+', '-', '.', ',', 0x00};
  27. int selectedButton = 0;
  28. int saveNotifyCountdown = 0;
  29. int execCountdown = 0;
  30. char dspLine0[25] = {};
  31. char dspLine1[25] = {};
  32. char dspLine2[25] = {};
  33. static bMapping buttonMappings[12] = {
  34. { 8, 8, 7, 1}, //0
  35. { 8, 8, 0, 2}, //1
  36. { 9, 9, 1, 3}, //2
  37. { 9, 9, 2, 4}, //3
  38. {10, 10, 3, 5}, //4
  39. {10, 10, 4, 6}, //5
  40. {11, 11, 5, 7}, //6
  41. {11, 11, 6, 0}, //7
  42. { 0, 0, 11, 9}, //8
  43. { 3, 3, 8, 10}, //9
  44. { 5, 5, 9, 11}, //10
  45. { 6, 6, 10, 8} //11
  46. };
  47. #define BT_X 14
  48. #define BT_Y 14
  49. static void bf_dev_draw_button(Canvas* canvas, int x, int y, bool selected, const char* lbl){
  50. UNUSED(lbl);
  51. if(selected){
  52. canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3);
  53. canvas_invert_color(canvas);
  54. canvas_set_font(canvas, FontBatteryPercent);
  55. canvas_draw_str_aligned(canvas, x + (BT_X/2), y + (BT_Y/2) - 1, AlignCenter, AlignCenter, lbl);
  56. canvas_invert_color(canvas);
  57. }
  58. else{
  59. canvas_draw_rbox(canvas, x, y, BT_X, BT_Y, 3);
  60. canvas_invert_color(canvas);
  61. canvas_draw_rbox(canvas, x+2, y-1, BT_X - 2, BT_Y - 1, 3);
  62. canvas_invert_color(canvas);
  63. canvas_draw_rframe(canvas, x, y, BT_X, BT_Y, 3);
  64. canvas_set_font(canvas, FontBatteryPercent);
  65. canvas_draw_str_aligned(canvas, x + (BT_X/2), y + (BT_Y/2) - 1, AlignCenter, AlignCenter, lbl);
  66. }
  67. }
  68. static void bf_dev_draw_callback(Canvas* canvas, void* _model) {
  69. UNUSED(_model);
  70. // if(execCountdown > 0){
  71. // execCountdown--;
  72. // canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "RUNNING...");
  73. // if(execCountdown == 0){
  74. // initWorker(appDev);
  75. // beginWorker();
  76. // text_box_set_text(appDev->text_box, workerGetOutput());
  77. // scene_manager_next_scene(appDev->scene_manager, brainfuckSceneExecEnv);
  78. // }
  79. // return;
  80. // }
  81. if(saveNotifyCountdown > 0){
  82. canvas_draw_str_aligned(canvas, 64, 32, AlignCenter, AlignCenter, "SAVED");
  83. saveNotifyCountdown--;
  84. return;
  85. }
  86. bf_dev_draw_button(canvas, 1, 36, (selectedButton == 0), "+"); //T 0
  87. bf_dev_draw_button(canvas, 17, 36, (selectedButton == 1), "-"); //T 1
  88. bf_dev_draw_button(canvas, 33, 36, (selectedButton == 2), "<"); //T 2
  89. bf_dev_draw_button(canvas, 49, 36, (selectedButton == 3), ">"); //T 3
  90. bf_dev_draw_button(canvas, 65, 36, (selectedButton == 4), "["); //B 0
  91. bf_dev_draw_button(canvas, 81, 36, (selectedButton == 5), "]"); //B 1
  92. bf_dev_draw_button(canvas, 97, 36, (selectedButton == 6), "."); //B 2
  93. bf_dev_draw_button(canvas, 113, 36, (selectedButton == 7), ","); //B 3
  94. //backspace, input, run, save
  95. canvas_draw_icon(canvas, 1, 52, (selectedButton == 8) ? &I_KeyBackspaceSelected_24x11 : &I_KeyBackspace_24x11);
  96. canvas_draw_icon(canvas, 45, 52, (selectedButton == 9) ? &I_KeyInputSelected_30x11 : &I_KeyInput_30x11);
  97. canvas_draw_icon(canvas, 77, 52, (selectedButton == 10) ? &I_KeyRunSelected_24x11 : &I_KeyRun_24x11);
  98. canvas_draw_icon(canvas, 103, 52, (selectedButton == 11) ? &I_KeySaveSelected_24x11 : &I_KeySave_24x11);
  99. if(saveNotifyCountdown > 0){
  100. canvas_draw_icon(canvas, 98, 54, &I_ButtonRightSmall_3x5);
  101. saveNotifyCountdown--;
  102. }
  103. //textbox
  104. //grossly overcomplicated. not fixing it.
  105. canvas_draw_rframe(canvas, 1, 1, 126, 33, 2);
  106. canvas_set_font(canvas, FontBatteryPercent);
  107. int dbOffset = 0;
  108. if(appDev->dataSize > 72){
  109. dbOffset = (appDev->dataSize - 72);
  110. }
  111. memset(dspLine0, 0x00, 25);
  112. memset(dspLine1, 0x00, 25);
  113. memset(dspLine2, 0x00, 25);
  114. int tpM = 0;
  115. int tp0 = 0;
  116. int tp1 = 0;
  117. int tp2 = 0;
  118. for(int p = dbOffset; p < appDev->dataSize; p++){
  119. if(tpM < 24 * 1){
  120. dspLine0[tp0] = appDev->dataBuffer[p];
  121. tp0++;
  122. }
  123. else if(tpM < 24 * 2){
  124. dspLine1[tp1] = appDev->dataBuffer[p];
  125. tp1++;
  126. }
  127. else if(tpM < 24 * 3){
  128. dspLine2[tp2] = appDev->dataBuffer[p];
  129. tp2++;
  130. }
  131. tpM++;
  132. }
  133. canvas_draw_str_aligned(canvas, 3, 8, AlignLeft, AlignCenter, dspLine0);
  134. canvas_draw_str_aligned(canvas, 3, 17, AlignLeft, AlignCenter, dspLine1);
  135. canvas_draw_str_aligned(canvas, 3, 26, AlignLeft, AlignCenter, dspLine2);
  136. }
  137. static bool bf_dev_input_callback(InputEvent* event, void* context) {
  138. furi_assert(context);
  139. BFDevEnv* devEnv = context;
  140. bool consumed = false;
  141. if(event->type == InputTypeShort) {
  142. if(event->key == InputKeyRight) {
  143. consumed = bf_dev_process_right(devEnv);
  144. } else if(event->key == InputKeyLeft) {
  145. consumed = bf_dev_process_left(devEnv);
  146. } else if(event->key == InputKeyUp) {
  147. consumed = bf_dev_process_up(devEnv);
  148. } else if(event->key == InputKeyDown) {
  149. consumed = bf_dev_process_down(devEnv);
  150. }
  151. } else if(event->key == InputKeyOk) {
  152. consumed = bf_dev_process_ok(devEnv, event);
  153. }
  154. return consumed;
  155. }
  156. static bool bf_dev_process_up(BFDevEnv* devEnv) {
  157. UNUSED(devEnv);
  158. selectedButton = buttonMappings[selectedButton].up;
  159. return true;
  160. }
  161. static bool bf_dev_process_down(BFDevEnv* devEnv) {
  162. UNUSED(devEnv);
  163. selectedButton = buttonMappings[selectedButton].down;
  164. return true;
  165. }
  166. static bool bf_dev_process_left(BFDevEnv* devEnv) {
  167. UNUSED(devEnv);
  168. selectedButton = buttonMappings[selectedButton].left;
  169. return true;
  170. }
  171. static bool bf_dev_process_right(BFDevEnv* devEnv) {
  172. UNUSED(devEnv);
  173. selectedButton = buttonMappings[selectedButton].right;
  174. return true;
  175. }
  176. static bool bf_dev_process_ok(BFDevEnv* devEnv, InputEvent* event) {
  177. UNUSED(devEnv);
  178. UNUSED(event);
  179. if(event->type != InputTypePress){ return false; }
  180. switch(selectedButton){
  181. case 0:
  182. {
  183. if(appDev->dataSize < BF_INST_BUFFER_SIZE){
  184. appDev->dataBuffer[appDev->dataSize] = '+';
  185. appDev->dataSize++; }
  186. break;
  187. }
  188. case 1:
  189. {
  190. if(appDev->dataSize < BF_INST_BUFFER_SIZE){
  191. appDev->dataBuffer[appDev->dataSize] = '-';
  192. appDev->dataSize++; }
  193. break;
  194. }
  195. case 2:
  196. {
  197. if(appDev->dataSize < BF_INST_BUFFER_SIZE){
  198. appDev->dataBuffer[appDev->dataSize] = '<';
  199. appDev->dataSize++; }
  200. break;
  201. }
  202. case 3:
  203. {
  204. if(appDev->dataSize < BF_INST_BUFFER_SIZE){
  205. appDev->dataBuffer[appDev->dataSize] = '>';
  206. appDev->dataSize++; }
  207. break;
  208. }
  209. case 4:
  210. {
  211. if(appDev->dataSize < BF_INST_BUFFER_SIZE){
  212. appDev->dataBuffer[appDev->dataSize] = '[';
  213. appDev->dataSize++; }
  214. break;
  215. }
  216. case 5:
  217. {
  218. if(appDev->dataSize < BF_INST_BUFFER_SIZE){
  219. appDev->dataBuffer[appDev->dataSize] = ']';
  220. appDev->dataSize++; }
  221. break;
  222. }
  223. case 6:
  224. {
  225. if(appDev->dataSize < BF_INST_BUFFER_SIZE){
  226. appDev->dataBuffer[appDev->dataSize] = '.';
  227. appDev->dataSize++; }
  228. break;
  229. }
  230. case 7:
  231. {
  232. if(appDev->dataSize < BF_INST_BUFFER_SIZE){
  233. appDev->dataBuffer[appDev->dataSize] = ',';
  234. appDev->dataSize++; }
  235. break;
  236. }
  237. case 8:
  238. {
  239. if(appDev->dataSize > 0){
  240. appDev->dataSize--;
  241. appDev->dataBuffer[appDev->dataSize] = (uint32_t)0x00;}
  242. break;
  243. }
  244. case 9:
  245. {
  246. scene_manager_next_scene(appDev->scene_manager, brainfuckSceneSetInput);
  247. break;
  248. }
  249. case 10:
  250. {
  251. if(getStatus() != 0){
  252. killThread();
  253. furi_thread_join(workerThread);
  254. }
  255. initWorker(appDev);
  256. text_box_set_focus(appDev->text_box, TextBoxFocusEnd);
  257. text_box_set_text(appDev->text_box, workerGetOutput());
  258. workerThread = furi_thread_alloc_ex("Worker", 2048, (void*)beginWorker, NULL);
  259. furi_thread_start(workerThread);
  260. scene_manager_next_scene(appDev->scene_manager, brainfuckSceneExecEnv);
  261. break;
  262. }
  263. case 11:
  264. {
  265. //remove old file
  266. Storage* storage = furi_record_open(RECORD_STORAGE);
  267. storage_simply_remove(storage, furi_string_get_cstr(appDev->BF_file_path));
  268. //save new file
  269. Stream* stream = buffered_file_stream_alloc(storage);
  270. buffered_file_stream_open(stream, furi_string_get_cstr(appDev->BF_file_path), FSAM_WRITE, FSOM_CREATE_ALWAYS);
  271. stream_write(stream, (const uint8_t*)appDev->dataBuffer, appDev->dataSize);
  272. buffered_file_stream_close(stream);
  273. //notify
  274. saveNotifyCountdown = 3;
  275. break;
  276. }
  277. }
  278. bool consumed = false;
  279. return consumed;
  280. }
  281. static void bf_dev_enter_callback(void* context) {
  282. furi_assert(context);
  283. BFDevEnv* devEnv = context;
  284. with_view_model(
  285. devEnv->view,
  286. BFDevEnvModel* model,
  287. {
  288. model->col = 0;
  289. model->row = 0;
  290. },
  291. true);
  292. appDev = devEnv->appDev;
  293. selectedButton = 0;
  294. //exit the running thread if required
  295. if(getStatus() != 0){
  296. killThread();
  297. furi_thread_join(workerThread);
  298. }
  299. //clear the bf instruction buffer
  300. memset(appDev->dataBuffer, 0x00, BF_INST_BUFFER_SIZE * sizeof(char));
  301. //open the file
  302. Storage* storage = furi_record_open(RECORD_STORAGE);
  303. Stream* stream = buffered_file_stream_alloc(storage);
  304. buffered_file_stream_open(stream, furi_string_get_cstr(appDev->BF_file_path), FSAM_READ, FSOM_OPEN_EXISTING);
  305. //read into the buffer
  306. appDev->dataSize = stream_size(stream);
  307. stream_read(stream, (uint8_t*)appDev->dataBuffer, appDev->dataSize);
  308. buffered_file_stream_close(stream);
  309. //replaces any invalid characters with an underscore. strips out newlines, comments, etc
  310. for(int i = 0; i < appDev->dataSize; i++){
  311. if(!strchr(bfChars, appDev->dataBuffer[i])){
  312. appDev->dataBuffer[i] = '_';
  313. }
  314. }
  315. //find the end of the file to begin editing
  316. int tptr = 0;
  317. while(appDev->dataBuffer[tptr] != 0x00){ tptr++; }
  318. appDev->dataSize = tptr;
  319. }
  320. BFDevEnv* bf_dev_env_alloc(BFApp* appDev) {
  321. BFDevEnv* devEnv = malloc(sizeof(BFDevEnv));
  322. devEnv->view = view_alloc();
  323. devEnv->appDev = appDev;
  324. view_allocate_model(devEnv->view, ViewModelTypeLocking, sizeof(BFDevEnvModel));
  325. with_view_model(
  326. devEnv->view,
  327. BFDevEnvModel* model,
  328. {
  329. model->col = 0;
  330. model->row = 0;
  331. },
  332. true);
  333. view_set_context(devEnv->view, devEnv);
  334. view_set_draw_callback(devEnv->view, bf_dev_draw_callback);
  335. view_set_input_callback(devEnv->view, bf_dev_input_callback);
  336. view_set_enter_callback(devEnv->view, bf_dev_enter_callback);
  337. return devEnv;
  338. }
  339. void bf_dev_env_free(BFDevEnv* devEnv) {
  340. if(getStatus() != 0){
  341. killThread();
  342. furi_thread_join(workerThread);
  343. }
  344. furi_assert(devEnv);
  345. view_free(devEnv->view);
  346. free(devEnv);
  347. }
  348. View* bf_dev_env_get_view(BFDevEnv* devEnv) {
  349. furi_assert(devEnv);
  350. return devEnv->view;
  351. }