boilerplate_scene_1.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. #include "../malveke_gb_photo.h"
  2. #include <furi.h>
  3. #include <furi_hal.h>
  4. #include <input/input.h>
  5. #include <gui/elements.h>
  6. #include <dolphin/dolphin.h>
  7. extern const uint8_t u8g2_font_5x7_mf[1911]; // Declare as extern
  8. const uint8_t _I_DolphinCommon_56x48_0[] = {
  9. 0x01,
  10. 0x00,
  11. 0xdf,
  12. 0x00,
  13. 0x00,
  14. 0x1f,
  15. 0xfe,
  16. 0x0e,
  17. 0x05,
  18. 0x3f,
  19. 0x04,
  20. 0x06,
  21. 0x78,
  22. 0x06,
  23. 0x30,
  24. 0x20,
  25. 0xf8,
  26. 0x00,
  27. 0xc6,
  28. 0x12,
  29. 0x1c,
  30. 0x04,
  31. 0x0c,
  32. 0x0a,
  33. 0x38,
  34. 0x08,
  35. 0x08,
  36. 0x0c,
  37. 0x60,
  38. 0xc0,
  39. 0x21,
  40. 0xe0,
  41. 0x04,
  42. 0x0a,
  43. 0x18,
  44. 0x02,
  45. 0x1b,
  46. 0x00,
  47. 0x18,
  48. 0xa3,
  49. 0x00,
  50. 0x21,
  51. 0x90,
  52. 0x01,
  53. 0x8a,
  54. 0x20,
  55. 0x02,
  56. 0x19,
  57. 0x80,
  58. 0x18,
  59. 0x80,
  60. 0x64,
  61. 0x09,
  62. 0x20,
  63. 0x89,
  64. 0x81,
  65. 0x8c,
  66. 0x3e,
  67. 0x41,
  68. 0xe2,
  69. 0x80,
  70. 0x50,
  71. 0x00,
  72. 0x43,
  73. 0x08,
  74. 0x01,
  75. 0x0c,
  76. 0xfc,
  77. 0x68,
  78. 0x40,
  79. 0x61,
  80. 0xc0,
  81. 0x50,
  82. 0x30,
  83. 0x00,
  84. 0x63,
  85. 0xa0,
  86. 0x7f,
  87. 0x80,
  88. 0xc4,
  89. 0x41,
  90. 0x19,
  91. 0x07,
  92. 0xff,
  93. 0x02,
  94. 0x06,
  95. 0x18,
  96. 0x24,
  97. 0x03,
  98. 0x41,
  99. 0xf3,
  100. 0x2b,
  101. 0x10,
  102. 0x19,
  103. 0x38,
  104. 0x10,
  105. 0x30,
  106. 0x31,
  107. 0x7f,
  108. 0xe0,
  109. 0x34,
  110. 0x08,
  111. 0x30,
  112. 0x19,
  113. 0x60,
  114. 0x80,
  115. 0x65,
  116. 0x86,
  117. 0x0a,
  118. 0x4c,
  119. 0x0c,
  120. 0x30,
  121. 0x81,
  122. 0xb9,
  123. 0x41,
  124. 0xa0,
  125. 0x54,
  126. 0x08,
  127. 0xc7,
  128. 0xe2,
  129. 0x06,
  130. 0x8a,
  131. 0x18,
  132. 0x25,
  133. 0x02,
  134. 0x21,
  135. 0x0f,
  136. 0x19,
  137. 0x88,
  138. 0xd8,
  139. 0x6e,
  140. 0x1b,
  141. 0x01,
  142. 0xd1,
  143. 0x1b,
  144. 0x86,
  145. 0x39,
  146. 0x66,
  147. 0x3a,
  148. 0xa4,
  149. 0x1a,
  150. 0x50,
  151. 0x06,
  152. 0x48,
  153. 0x18,
  154. 0x18,
  155. 0xd0,
  156. 0x03,
  157. 0x01,
  158. 0x41,
  159. 0x98,
  160. 0xcc,
  161. 0x60,
  162. 0x39,
  163. 0x01,
  164. 0x49,
  165. 0x2d,
  166. 0x06,
  167. 0x03,
  168. 0x50,
  169. 0xf8,
  170. 0x40,
  171. 0x3e,
  172. 0x02,
  173. 0xc1,
  174. 0x82,
  175. 0x86,
  176. 0xc7,
  177. 0xfe,
  178. 0x0f,
  179. 0x28,
  180. 0x2c,
  181. 0x91,
  182. 0xd2,
  183. 0x90,
  184. 0x9a,
  185. 0x18,
  186. 0x19,
  187. 0x3e,
  188. 0x6d,
  189. 0x73,
  190. 0x12,
  191. 0x16,
  192. 0x00,
  193. 0x32,
  194. 0x49,
  195. 0x72,
  196. 0xc0,
  197. 0x7e,
  198. 0x5d,
  199. 0x44,
  200. 0xba,
  201. 0x2c,
  202. 0x08,
  203. 0xa4,
  204. 0xc8,
  205. 0x82,
  206. 0x06,
  207. 0x17,
  208. 0xe0,
  209. 0x81,
  210. 0x90,
  211. 0x2a,
  212. 0x40,
  213. 0x61,
  214. 0xe1,
  215. 0xa2,
  216. 0x44,
  217. 0x0c,
  218. 0x76,
  219. 0x2b,
  220. 0xe8,
  221. 0x89,
  222. 0x26,
  223. 0x43,
  224. 0x83,
  225. 0x31,
  226. 0x8c,
  227. 0x78,
  228. 0x0c,
  229. 0xb0,
  230. 0x48,
  231. 0x10,
  232. 0x1a,
  233. 0xe0,
  234. 0x00,
  235. 0x63,
  236. };
  237. const uint8_t *const _I_DolphinCommon_56x48[] = {_I_DolphinCommon_56x48_0};
  238. const Icon I_DolphinCommon_56x48 = {.width = 56, .height = 48, .frame_count = 1, .frame_rate = 0, .frames = _I_DolphinCommon_56x48};
  239. struct BoilerplateScene1
  240. {
  241. View *view;
  242. BoilerplateScene1Callback callback;
  243. void *context;
  244. };
  245. typedef struct
  246. {
  247. BoilerplateScene1 *instance;
  248. } BoilerplateScene1Model;
  249. void boilerplate_scene_1_set_callback(
  250. BoilerplateScene1 *instance,
  251. BoilerplateScene1Callback callback,
  252. void *context)
  253. {
  254. furi_assert(instance);
  255. furi_assert(callback);
  256. instance->callback = callback;
  257. instance->context = context;
  258. }
  259. void boilerplate_scene_1_draw(Canvas *canvas, BoilerplateScene1Model *model)
  260. {
  261. UNUSED(model);
  262. BoilerplateScene1 *instance = model->instance;
  263. Boilerplate *app = instance->context;
  264. canvas_clear(canvas);
  265. // Prepare canvas
  266. canvas_set_color(canvas, ColorBlack);
  267. canvas_draw_frame(canvas, 0, 0, FRAME_WIDTH, FRAME_HEIGTH);
  268. if (app->show_instructions)
  269. {
  270. canvas_draw_icon(canvas, 71, 15, &I_DolphinCommon_56x48);
  271. canvas_set_font(canvas, FontSecondary);
  272. canvas_draw_str_aligned(canvas, (128 / 2), 4, AlignCenter, AlignTop, "INSTRUCTIONS");
  273. canvas_set_custom_u8g2_font(canvas, u8g2_font_5x7_mf); // 5x7 font, 9 lines
  274. canvas_draw_icon_ex(canvas, 15, 18, &I_arrow_13x6, IconRotation180); // DOWN
  275. canvas_draw_icon(canvas, 28, 18, &I_arrow_13x6); // UP
  276. canvas_draw_str_aligned(canvas, 47, 21, AlignLeft, AlignCenter, "SCROLL");
  277. canvas_draw_icon_ex(canvas, 33, 26, &I_arrow_13x6, IconRotation270); // PREV
  278. canvas_draw_icon_ex(canvas, 22, 36, &I_arrow_13x6, IconRotation90); // NEXT
  279. canvas_draw_str_aligned(canvas, 47, 32, AlignLeft, AlignCenter, "LEFT");
  280. canvas_draw_str_aligned(canvas, 47, 43, AlignLeft, AlignCenter, "RIGHT");
  281. canvas_set_font(canvas, FontPrimary);
  282. elements_button_center(canvas, "OK");
  283. }
  284. else
  285. {
  286. int count = (app->page + 1) * 0x1000;
  287. uint8_t status = app->scratchpad1[0x11B2 + app->page];
  288. storage_file_seek(app->camera_ram_sav, count, true);
  289. for (int y = app->pos_y; y < 14; y++)
  290. {
  291. for (int x = app->pos_x; x < 16; x++)
  292. {
  293. storage_file_read(app->camera_ram_sav, app->tile_data, sizeof(app->tile_data));
  294. for (int row = 0; row < 8; row++)
  295. {
  296. uint8_t temp1 = app->tile_data[row * 2];
  297. uint8_t temp2 = app->tile_data[row * 2 + 1];
  298. for (int pixel = 7; pixel >= 0; pixel--)
  299. {
  300. if (((temp1 & 1) + ((temp2 & 1) * 2)) >= 2)
  301. {
  302. canvas_draw_dot(canvas, (x * 8) + pixel, (y * 8) + row);
  303. }
  304. temp1 >>= 1;
  305. temp2 >>= 1;
  306. }
  307. }
  308. }
  309. }
  310. if (app->info)
  311. {
  312. if (status == 0xFF)
  313. {
  314. canvas_draw_rbox(canvas, 100, 4, 20, 11, 4);
  315. canvas_invert_color(canvas);
  316. canvas_draw_str_aligned(canvas, 110, 10, AlignCenter, AlignCenter, "D");
  317. canvas_invert_color(canvas);
  318. }
  319. }
  320. }
  321. }
  322. static void boilerplate_scene_1_model_init(BoilerplateScene1Model *const model, void *context)
  323. {
  324. BoilerplateScene1 *instance = context;
  325. UNUSED(model);
  326. UNUSED(instance);
  327. model->instance = context;
  328. }
  329. void save_image(void *context)
  330. {
  331. Boilerplate *app = context;
  332. furi_assert(app);
  333. NotificationApp *notifications = furi_record_open(RECORD_NOTIFICATION);
  334. // Create MALVEKE dir
  335. if (storage_common_stat(app->storage, MALVEKE_APP_FOLDER, NULL) == FSE_NOT_EXIST)
  336. {
  337. storage_simply_mkdir(app->storage, MALVEKE_APP_FOLDER);
  338. }
  339. // Create MALVEKE Photos dir
  340. if (storage_common_stat(app->storage, MALVEKE_APP_FOLDER_PHOTOS, NULL) == FSE_NOT_EXIST)
  341. {
  342. storage_simply_mkdir(app->storage, MALVEKE_APP_FOLDER_PHOTOS);
  343. }
  344. int count = (app->page + 1) * 0x1000;
  345. storage_file_seek(app->camera_ram_sav, count, true);
  346. // create file name
  347. FuriString *file_name = furi_string_alloc();
  348. get_timefilename(file_name, app->page);
  349. File *file = storage_file_alloc(app->storage);
  350. bool result =
  351. storage_file_open(file, furi_string_get_cstr(file_name), FSAM_WRITE, FSOM_OPEN_ALWAYS);
  352. if (result)
  353. {
  354. static char bmp[BMP_SIZE(WIDTH, HEIGHT)];
  355. bmp_init(bmp, WIDTH, HEIGHT);
  356. // Selected Palette
  357. uint32_t palette[] = {
  358. bmp_encode(app->palette_color_hex_a),
  359. bmp_encode(app->palette_color_hex_b),
  360. bmp_encode(app->palette_color_hex_c),
  361. bmp_encode(app->palette_color_hex_d)};
  362. UNUSED(palette);
  363. for (int y = 0; y < 14; y++)
  364. {
  365. for (int x = 0; x < 16; x++)
  366. {
  367. storage_file_read(app->camera_ram_sav, app->tile_data, sizeof(app->tile_data));
  368. for (int row = 0; row < 8; row++)
  369. {
  370. uint8_t temp1 = app->tile_data[row * 2];
  371. uint8_t temp2 = app->tile_data[row * 2 + 1];
  372. for (int pixel = 7; pixel >= 0; pixel--)
  373. {
  374. bmp_set(
  375. bmp,
  376. (x * 8) + pixel,
  377. (y * 8) + row,
  378. palette[((temp1 & 1) + ((temp2 & 1) * 2))]);
  379. temp1 >>= 1;
  380. temp2 >>= 1;
  381. }
  382. }
  383. }
  384. }
  385. storage_file_write(file, bmp, sizeof(bmp));
  386. storage_file_close(file);
  387. }
  388. // Closing the "file descriptor"
  389. storage_file_close(file);
  390. // Freeing up memory
  391. storage_file_free(file);
  392. notification_message(notifications, result ? &sequence_success : &sequence_error);
  393. }
  394. bool boilerplate_scene_1_input(InputEvent *event, void *context)
  395. {
  396. furi_assert(context);
  397. BoilerplateScene1 *instance = context;
  398. Boilerplate *app = instance->context;
  399. if (event->type == InputTypeRelease)
  400. {
  401. switch (event->key)
  402. {
  403. case InputKeyBack:
  404. with_view_model(
  405. instance->view,
  406. BoilerplateScene1Model * model,
  407. {
  408. UNUSED(model);
  409. instance->callback(BoilerplateCustomEventScene1Back, instance->context);
  410. },
  411. true);
  412. break;
  413. case InputKeyLeft:
  414. with_view_model(
  415. instance->view,
  416. BoilerplateScene1Model * model,
  417. {
  418. UNUSED(model);
  419. app->pos_y = 0;
  420. app->pos_x = 0;
  421. if (app->page > 0)
  422. {
  423. app->page--;
  424. }
  425. else
  426. {
  427. app->page = 29;
  428. }
  429. },
  430. true);
  431. break;
  432. case InputKeyRight:
  433. with_view_model(
  434. instance->view,
  435. BoilerplateScene1Model * model,
  436. {
  437. UNUSED(model);
  438. app->pos_y = 0;
  439. app->pos_x = 0;
  440. if (app->page < 29)
  441. {
  442. app->page++;
  443. }
  444. else
  445. {
  446. app->page = 0;
  447. }
  448. },
  449. true);
  450. break;
  451. case InputKeyUp:
  452. with_view_model(
  453. instance->view,
  454. BoilerplateScene1Model * model,
  455. {
  456. UNUSED(model);
  457. if (app->pos_y < 0)
  458. {
  459. app->pos_y++;
  460. }
  461. },
  462. true);
  463. break;
  464. case InputKeyDown:
  465. with_view_model(
  466. instance->view,
  467. BoilerplateScene1Model * model,
  468. {
  469. UNUSED(model);
  470. if (app->pos_y > -6)
  471. {
  472. app->pos_y--;
  473. }
  474. },
  475. true);
  476. break;
  477. case InputKeyOk:
  478. with_view_model(
  479. instance->view,
  480. BoilerplateScene1Model * model,
  481. {
  482. UNUSED(model);
  483. if (app->show_instructions)
  484. {
  485. app->show_instructions = false;
  486. }
  487. else
  488. {
  489. save_image(app);
  490. }
  491. },
  492. true);
  493. break;
  494. case InputKeyMAX:
  495. break;
  496. }
  497. }
  498. return true;
  499. }
  500. void boilerplate_scene_1_exit(void *context)
  501. {
  502. furi_assert(context);
  503. }
  504. void boilerplate_scene_1_enter(void *context)
  505. {
  506. furi_assert(context);
  507. BoilerplateScene1 *instance = (BoilerplateScene1 *)context;
  508. with_view_model(
  509. instance->view,
  510. BoilerplateScene1Model * model,
  511. {
  512. boilerplate_scene_1_model_init(model, instance);
  513. },
  514. true);
  515. }
  516. BoilerplateScene1 *boilerplate_scene_1_alloc()
  517. {
  518. BoilerplateScene1 *instance = malloc(sizeof(BoilerplateScene1));
  519. instance->view = view_alloc();
  520. view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(BoilerplateScene1Model));
  521. view_set_context(instance->view, instance); // furi_assert crashes in events without this
  522. view_set_draw_callback(instance->view, (ViewDrawCallback)boilerplate_scene_1_draw);
  523. view_set_input_callback(instance->view, boilerplate_scene_1_input);
  524. view_set_enter_callback(instance->view, boilerplate_scene_1_enter);
  525. view_set_exit_callback(instance->view, boilerplate_scene_1_exit);
  526. with_view_model(
  527. instance->view,
  528. BoilerplateScene1Model * model,
  529. {
  530. boilerplate_scene_1_model_init(model, instance);
  531. },
  532. true);
  533. return instance;
  534. }
  535. void boilerplate_scene_1_free(BoilerplateScene1 *instance)
  536. {
  537. furi_assert(instance);
  538. with_view_model(
  539. instance->view,
  540. BoilerplateScene1Model * model,
  541. {
  542. UNUSED(model);
  543. },
  544. true);
  545. view_free(instance->view);
  546. free(instance);
  547. }
  548. View *boilerplate_scene_1_get_view(BoilerplateScene1 *instance)
  549. {
  550. furi_assert(instance);
  551. return instance->view;
  552. }