coleco.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #include <furi.h>
  2. #include <furi_hal_gpio.h>
  3. #include <furi_hal_power.h>
  4. #include <gui/gui.h>
  5. #include <gui/modules/button_panel.h>
  6. #define CODE_0 0x0A
  7. #define CODE_1 0x0D
  8. #define CODE_2 0x07
  9. #define CODE_3 0x0C
  10. #define CODE_4 0x02
  11. #define CODE_5 0x03
  12. #define CODE_6 0x0E
  13. #define CODE_7 0x05
  14. #define CODE_8 0x01
  15. #define CODE_9 0x0B
  16. #define CODE_H 0x06
  17. #define CODE_S 0x09
  18. #define CODE_N 0x0F
  19. const GpioPin* const pin_up = &gpio_ext_pa6;
  20. const GpioPin* const pin_down = &gpio_ext_pc0;
  21. const GpioPin* const pin_right = &gpio_ext_pb2;
  22. const GpioPin* const pin_left = &gpio_ext_pc3;
  23. const GpioPin* const pin_code0 = &gpio_ext_pa7;
  24. const GpioPin* const pin_code1 = &gpio_ext_pa4;
  25. const GpioPin* const pin_code2 = &ibutton_gpio;
  26. const GpioPin* const pin_code3 = &gpio_ext_pc1;
  27. const GpioPin* const pin_fire = &gpio_ext_pb3;
  28. typedef enum
  29. {
  30. EventTypeTick,
  31. EventTypeKey,
  32. } EventType;
  33. typedef struct
  34. {
  35. EventType type;
  36. InputEvent input;
  37. } PluginEvent;
  38. typedef struct
  39. {
  40. ButtonPanel* button_panel;
  41. bool dpad;
  42. } Coleco;
  43. static void render_callback(Canvas* const canvas, void* context)
  44. {
  45. Coleco* coleco = acquire_mutex((ValueMutex*)context, 25);
  46. if (coleco == NULL)
  47. {
  48. return;
  49. }
  50. canvas_set_font(canvas, FontPrimary);
  51. canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignBottom, "ColecoVision");
  52. canvas_set_font(canvas, FontSecondary);
  53. if (coleco->dpad)
  54. {
  55. canvas_draw_str_aligned(canvas, 64, 18, AlignCenter, AlignBottom, "d-pad");
  56. }
  57. else
  58. {
  59. canvas_draw_str_aligned(canvas, 64, 18, AlignCenter, AlignBottom, "numbers");
  60. }
  61. release_mutex((ValueMutex*)context, coleco);
  62. }
  63. static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue)
  64. {
  65. furi_assert(event_queue);
  66. PluginEvent event = {.type = EventTypeKey, .input = *input_event};
  67. furi_message_queue_put(event_queue, &event, FuriWaitForever);
  68. }
  69. static void coleco_write_code(unsigned int code)
  70. {
  71. furi_hal_gpio_write(pin_code0, (code & 1));
  72. furi_hal_gpio_write(pin_code1, (code & 2));
  73. furi_hal_gpio_write(pin_code2, (code & 4));
  74. furi_hal_gpio_write(pin_code3, (code & 8));
  75. }
  76. static Coleco* coleco_alloc()
  77. {
  78. Coleco* coleco = malloc(sizeof(Coleco));
  79. coleco->button_panel = button_panel_alloc();
  80. coleco->dpad = false;
  81. // configure output pins
  82. furi_hal_gpio_init(pin_up, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  83. furi_hal_gpio_init(pin_down, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  84. furi_hal_gpio_init(pin_right, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  85. furi_hal_gpio_init(pin_left, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  86. furi_hal_gpio_init(pin_code0, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  87. furi_hal_gpio_init(pin_code1, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  88. furi_hal_gpio_init(pin_code2, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  89. furi_hal_gpio_init(pin_code3, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  90. furi_hal_gpio_init(pin_fire, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  91. furi_hal_gpio_write(pin_up, true);
  92. furi_hal_gpio_write(pin_down, true);
  93. furi_hal_gpio_write(pin_right, true);
  94. furi_hal_gpio_write(pin_left, true);
  95. furi_hal_gpio_write(pin_fire, true);
  96. coleco_write_code(CODE_N);
  97. return coleco;
  98. }
  99. static void coleco_free(Coleco* coleco)
  100. {
  101. furi_assert(coleco);
  102. button_panel_free(coleco->button_panel);
  103. free(coleco);
  104. }
  105. int32_t coleco_app(void* p)
  106. {
  107. UNUSED(p);
  108. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
  109. Coleco* coleco = coleco_alloc();
  110. ValueMutex coleco_mutex;
  111. if (!init_mutex(&coleco_mutex, coleco, sizeof(Coleco)))
  112. {
  113. FURI_LOG_E("Coleco", "cannot create mutex\r\n");
  114. coleco_free(coleco);
  115. return 255;
  116. }
  117. // set system callbacks
  118. ViewPort* view_port = view_port_alloc();
  119. view_port_draw_callback_set(view_port, render_callback, &coleco_mutex);
  120. view_port_input_callback_set(view_port, input_callback, event_queue);
  121. // open GUI and register view_port
  122. Gui* gui = furi_record_open("gui");
  123. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  124. furi_hal_power_enable_otg();
  125. PluginEvent event;
  126. for (bool processing = true; processing;)
  127. {
  128. FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
  129. Coleco* coleco = (Coleco*)acquire_mutex_block(&coleco_mutex);
  130. if (event_status == FuriStatusOk)
  131. {
  132. // press events
  133. if (event.type == EventTypeKey)
  134. {
  135. switch (event.input.key)
  136. {
  137. case InputKeyUp:
  138. if (coleco->dpad)
  139. {
  140. if (event.input.type == InputTypePress)
  141. {
  142. furi_hal_gpio_write(pin_up, false);
  143. }
  144. else if (event.input.type == InputTypeRelease)
  145. {
  146. furi_hal_gpio_write(pin_up, true);
  147. }
  148. }
  149. else // FIXME: hack to allow the 1 to be pressed
  150. {
  151. if (event.input.type == InputTypePress)
  152. {
  153. coleco_write_code(CODE_1);
  154. }
  155. else if (event.input.type == InputTypeRelease)
  156. {
  157. coleco_write_code(CODE_N);
  158. }
  159. }
  160. break;
  161. case InputKeyDown:
  162. if (coleco->dpad)
  163. {
  164. if (event.input.type == InputTypePress)
  165. {
  166. furi_hal_gpio_write(pin_down, false);
  167. }
  168. else if (event.input.type == InputTypeRelease)
  169. {
  170. furi_hal_gpio_write(pin_down, true);
  171. }
  172. }
  173. else // FIXME: hack to allow the 2 to be pressed
  174. {
  175. if (event.input.type == InputTypePress)
  176. {
  177. coleco_write_code(CODE_2);
  178. }
  179. else if (event.input.type == InputTypeRelease)
  180. {
  181. coleco_write_code(CODE_N);
  182. }
  183. }
  184. break;
  185. case InputKeyRight:
  186. if (coleco->dpad)
  187. {
  188. if (event.input.type == InputTypePress)
  189. {
  190. furi_hal_gpio_write(pin_right, false);
  191. }
  192. else if (event.input.type == InputTypeRelease)
  193. {
  194. furi_hal_gpio_write(pin_right, true);
  195. }
  196. }
  197. else // FIXME: hack to allow the 3 to be pressed
  198. {
  199. if (event.input.type == InputTypePress)
  200. {
  201. coleco_write_code(CODE_3);
  202. }
  203. else if (event.input.type == InputTypeRelease)
  204. {
  205. coleco_write_code(CODE_N);
  206. }
  207. }
  208. break;
  209. case InputKeyLeft:
  210. if (coleco->dpad)
  211. {
  212. if (event.input.type == InputTypePress)
  213. {
  214. furi_hal_gpio_write(pin_left, false);
  215. }
  216. else if (event.input.type == InputTypeRelease)
  217. {
  218. furi_hal_gpio_write(pin_left, true);
  219. }
  220. }
  221. else // FIXME: hack to allow the 4 to be pressed
  222. {
  223. if (event.input.type == InputTypePress)
  224. {
  225. coleco_write_code(CODE_4);
  226. }
  227. else if (event.input.type == InputTypeRelease)
  228. {
  229. coleco_write_code(CODE_N);
  230. }
  231. }
  232. break;
  233. case InputKeyOk:
  234. if (coleco->dpad)
  235. {
  236. if (event.input.type == InputTypePress)
  237. {
  238. furi_hal_gpio_write(pin_fire, false);
  239. }
  240. else if (event.input.type == InputTypeRelease)
  241. {
  242. furi_hal_gpio_write(pin_fire, true);
  243. }
  244. }
  245. else
  246. {
  247. coleco->dpad = true;
  248. }
  249. break;
  250. case InputKeyBack:
  251. if (event.input.type == InputTypePress)
  252. {
  253. if (coleco->dpad)
  254. {
  255. coleco->dpad = false;
  256. }
  257. else
  258. {
  259. processing = false;
  260. }
  261. }
  262. break;
  263. default:
  264. break;
  265. }
  266. view_port_update(view_port);
  267. }
  268. }
  269. else
  270. {
  271. FURI_LOG_D("Coleco", "FuriMessageQueue: event timeout");
  272. }
  273. release_mutex(&coleco_mutex, coleco);
  274. }
  275. furi_hal_power_disable_otg();
  276. view_port_enabled_set(view_port, false);
  277. gui_remove_view_port(gui, view_port);
  278. furi_record_close("gui");
  279. view_port_free(view_port);
  280. furi_message_queue_free(event_queue);
  281. delete_mutex(&coleco_mutex);
  282. coleco_free(coleco);
  283. return 0;
  284. }