gpio_controller.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. #include <furi.h>
  2. #include <furi_hal.h>
  3. #include <gui/gui.h>
  4. #include <input/input.h>
  5. /* Magic happens here -- this file is generated by fbt.
  6. * Just set fap_icon_assets in application.fam and #include {APPID}_icons.h */
  7. #include "gpio_controller_icons.h"
  8. #define GPIO_PIN_COUNT 8
  9. #define ANIMATE_FRAME_TIME_MS 133
  10. #define FRAME_TIME 66.666666
  11. typedef struct {
  12. int selected;
  13. //GPIOItems* gpio_items;
  14. int wiggle_frame;
  15. size_t prev_frame_time;
  16. size_t elapsed_time;
  17. } ViewerState;
  18. // 5V A7 A6 A4 B3 B2 C3 GND SET
  19. //
  20. //
  21. // 3V SWC GND SIO TX RX C1 C0 1W GND
  22. typedef enum {
  23. PIN_5V = 0,
  24. PIN_A7,
  25. PIN_A6,
  26. PIN_A4,
  27. PIN_B3,
  28. PIN_B2,
  29. PIN_C3,
  30. GEARIC,
  31. PIN_3V,
  32. PIN_SWC,
  33. PIN_SIO,
  34. PIN_TX,
  35. PIN_RX,
  36. PIN_C1,
  37. PIN_C0,
  38. PIN_1W,
  39. PIN_GND_08,
  40. PIN_GND_11,
  41. PIN_GND_18,
  42. NONE
  43. }enum_view_element;
  44. typedef struct {
  45. enum_view_element element;
  46. enum_view_element opposite;
  47. bool selectable;
  48. bool editable;
  49. bool top_row;
  50. bool pull_out;
  51. int gp_idx;
  52. uint8_t x_pos;
  53. uint8_t y_pos;
  54. const char* name;
  55. Icon* icon;
  56. Icon* selected_icon;
  57. }ViewElement;
  58. typedef struct {
  59. uint8_t element_idx;
  60. const GpioPin* pin;
  61. GpioMode mode;
  62. GpioPull pull;
  63. GpioSpeed speed;
  64. uint8_t value;
  65. const char* name;
  66. char* expression;
  67. bool unset;
  68. bool found;
  69. bool input;
  70. }GPIOPin;
  71. static ViewerState vstate = {.selected = PIN_A7,.wiggle_frame=-1};
  72. static int wiggle[] = {-1,1,-1,1};
  73. static uint32_t wiggle_frame_count = 4;
  74. static ViewElement elements[] = {
  75. {PIN_5V, PIN_3V, true, false, true, true, -1, 0, 0, "5V" , (Icon*)&I_5v_pin, NULL},
  76. {PIN_A7, PIN_SWC, true, false, true, true, -1, 14, 0, "PA7", (Icon*)&I_a7_pin, NULL},
  77. {PIN_A6, NONE, true, false, true, true, -1, 28, 0, "PA6", (Icon*)&I_a6_pin, NULL},
  78. {PIN_A4, PIN_SIO, true, false, true, true, -1, 42, 0, "PA4", (Icon*)&I_a4_pin, NULL},
  79. {PIN_B3, PIN_TX, true, false, true, true, -1, 56, 0, "PB3", (Icon*)&I_b3_pin, NULL},
  80. {PIN_B2, PIN_RX, true, false, true, true, -1, 70, 0, "PB2", (Icon*)&I_b2_pin, NULL},
  81. {PIN_C3, PIN_C1, true, false, true, true, -1, 84, 0, "PC3", (Icon*)&I_c3_pin, NULL},
  82. {GEARIC, PIN_1W, true, true, true, false, -1, 112, 0, "Settings", (Icon*)&I_gear_unhighlighted, (Icon*)&I_gear_highlighted},
  83. {PIN_3V, PIN_5V, true, false, false, true, -1, 0, 48, "3.3V", (Icon*)&I_3v_pin, NULL},
  84. {PIN_SWC, PIN_A7, true, false, false, true, -1, 14, 48, "Serial Wire Clock", (Icon*)&I_swc_pin, NULL},
  85. {PIN_SIO, PIN_A4, true, false, false, true, -1, 42, 48, "Serial IO", (Icon*)&I_sio_pin, NULL},
  86. {PIN_TX, PIN_B3, true, false, false, true, -1, 56, 48, "UART - Transmit", (Icon*)&I_tx_pin, NULL},
  87. {PIN_RX, PIN_B2, true, false, false, true, -1, 70, 48, "UART - Receive", (Icon*)&I_rx_pin, NULL},
  88. {PIN_C1, PIN_C3, true, false, false, true, -1, 84, 48, "PC1", (Icon*)&I_c1_pin, NULL},
  89. {PIN_C0, NONE, true, false, false, true, -1, 98, 48, "PC0", (Icon*)&I_c0_pin, NULL},
  90. {PIN_1W, GEARIC, true, true, false, true, -1, 112, 48, "1-Wire", (Icon*)&I_1w_pin, NULL},
  91. {PIN_GND_08, NONE, false, false, true, false, -1, 98, -1, "GND (Ground)", (Icon*)&I_gnd_pin, NULL},
  92. {PIN_GND_11, NONE, false, false, false, false, -1, 28, 48, "GND (Ground)", (Icon*)&I_gnd_pin, NULL},
  93. {PIN_GND_18, NONE, false, false, false, false, -1, 126, 48, "GND (Ground)", (Icon*)&I_gnd_pin, NULL},
  94. };
  95. static GPIOPin gpio_pin_config[GPIO_PIN_COUNT];
  96. static int element_count = NONE;
  97. // GPIO enums from firmware/targets/f7/furi_hal/furi_hal_gpio.h
  98. // /**
  99. // * Gpio modes
  100. // */
  101. // typedef enum {
  102. // *GpioModeInput,
  103. // *GpioModeOutputPushPull,
  104. // GpioModeOutputOpenDrain,
  105. // GpioModeAltFunctionPushPull,
  106. // GpioModeAltFunctionOpenDrain,
  107. // *GpioModeAnalog,
  108. // GpioModeInterruptRise,
  109. // GpioModeInterruptFall,
  110. // GpioModeInterruptRiseFall,
  111. // GpioModeEventRise,
  112. // GpioModeEventFall,
  113. // GpioModeEventRiseFall,
  114. // } GpioMode;
  115. // /**
  116. // * Gpio pull modes
  117. // */
  118. // typedef enum {
  119. // GpioPullNo,
  120. // GpioPullUp,
  121. // GpioPullDown,
  122. // } GpioPull;
  123. // /**
  124. // * Gpio speed modes
  125. // */
  126. // typedef enum {
  127. // GpioSpeedLow,
  128. // GpioSpeedMedium,
  129. // GpioSpeedHigh,
  130. // GpioSpeedVeryHigh,
  131. // } GpioSpeed;
  132. static void init_gpio()
  133. {
  134. int count = 0;
  135. for(size_t i = 0; i < gpio_pins_count; i++) {
  136. if(!gpio_pins[i].debug) {
  137. for(int j = 0; j < element_count; j++) {
  138. if( strcmp(elements[j].name,gpio_pins[i].name) == 0 )
  139. {
  140. gpio_pin_config[count].element_idx = j;
  141. gpio_pin_config[count].pin = gpio_pins[i].pin;
  142. gpio_pin_config[count].mode = GpioModeOutputPushPull;
  143. gpio_pin_config[count].pull = GpioPullNo;
  144. gpio_pin_config[count].speed = GpioSpeedVeryHigh;
  145. gpio_pin_config[count].value = 0;
  146. gpio_pin_config[count].name = gpio_pins[i].name;
  147. gpio_pin_config[count].expression = NULL;
  148. gpio_pin_config[count].unset = true;
  149. gpio_pin_config[count].found = true;
  150. gpio_pin_config[count].input = false;
  151. elements[j].gp_idx = i;
  152. elements[j].editable = true;
  153. count++;
  154. }
  155. }
  156. }
  157. }
  158. // naively set all as digitial output
  159. for(int i = 0; i < count; i++) {
  160. GPIOPin* gpc = &gpio_pin_config[i];
  161. gpc->input = true;
  162. gpc->unset = false;
  163. furi_hal_gpio_write(gpc->pin, false);
  164. furi_hal_gpio_init(gpc->pin, gpc->mode, gpc->pull, gpc->speed);
  165. }
  166. }
  167. //static void update_gpio()
  168. //{
  169. // // write to gpio pins
  170. //
  171. // // read frm gpio pins
  172. //}
  173. // TODO: Determine the lowest frame delta we can get away with.
  174. // TODO: Redraw only what changes.
  175. // - clear previous (drawn) selected pin
  176. // - clear newly selected pin
  177. // Screen is 128x64 px
  178. static void app_draw_callback(Canvas* canvas, void* ctx) {
  179. UNUSED(ctx);
  180. canvas_clear(canvas);
  181. size_t current_frame_time = furi_get_tick();
  182. size_t delta_cycles = (current_frame_time > vstate.prev_frame_time ? current_frame_time - vstate.prev_frame_time : 0);
  183. size_t delta_time_ms = delta_cycles * 1000 / furi_kernel_get_tick_frequency();
  184. // delay until desired delta time and recalculate
  185. if( delta_time_ms < FRAME_TIME )
  186. {
  187. furi_delay_ms(FRAME_TIME-delta_time_ms);
  188. current_frame_time = furi_get_tick();
  189. delta_cycles = (current_frame_time > vstate.prev_frame_time ? current_frame_time - vstate.prev_frame_time : 0);
  190. delta_time_ms = delta_cycles * 1000 / furi_kernel_get_tick_frequency();
  191. }
  192. vstate.elapsed_time += delta_time_ms;
  193. vstate.prev_frame_time = current_frame_time;
  194. // draw values
  195. for(int i = 0; i < GPIO_PIN_COUNT; i++) {
  196. if( !gpio_pin_config[i].unset )
  197. {
  198. ViewElement e = elements[gpio_pin_config[i].element_idx];
  199. // draw wire
  200. if(e.top_row)
  201. {
  202. canvas_draw_line(canvas, e.x_pos + 6, e.y_pos + 16, e.x_pos + 6, e.y_pos + 16 + 8);
  203. }
  204. else
  205. {
  206. canvas_draw_line(canvas, e.x_pos + 6, e.y_pos, e.x_pos + 6, e.y_pos - 8);
  207. }
  208. if(gpio_pin_config[i].mode == GpioModeAnalog)
  209. {
  210. }
  211. else
  212. {
  213. const Icon* icon = gpio_pin_config[i].value ? &I_digi_one : &I_digi_zero;
  214. if(e.top_row)
  215. {
  216. canvas_draw_icon(canvas, e.x_pos + 2, e.y_pos + 20, icon);
  217. }
  218. else
  219. {
  220. canvas_draw_icon(canvas, e.x_pos + 2, e.y_pos - 13, icon);
  221. }
  222. }
  223. }
  224. }
  225. for(int i = 0; i < element_count; i++)
  226. {
  227. ViewElement e = elements[i];
  228. int x = e.x_pos;
  229. int y = e.y_pos + (e.top_row && e.pull_out ? -3 : 0);
  230. Icon* icon = e.icon;
  231. if( vstate.selected == i )
  232. {
  233. if( e.pull_out )
  234. {
  235. y += e.top_row ? 3 : -3;
  236. }
  237. if( e.selected_icon != NULL )
  238. {
  239. icon = e.selected_icon;
  240. }
  241. if(vstate.wiggle_frame >= 0)
  242. {
  243. x += wiggle[vstate.wiggle_frame];
  244. if(vstate.elapsed_time >= ANIMATE_FRAME_TIME_MS)
  245. {
  246. vstate.wiggle_frame++;
  247. if ((unsigned int)(vstate.wiggle_frame) >= wiggle_frame_count) //(sizeof(wiggle)/sizeof(int)))
  248. {
  249. vstate.wiggle_frame = -1;
  250. }
  251. vstate.elapsed_time = 0;
  252. }
  253. }
  254. }
  255. canvas_draw_icon(canvas, x, y, icon);
  256. }
  257. canvas_set_font(canvas, FontSecondary);
  258. canvas_draw_str(canvas, 0, 40, elements[vstate.selected].name);
  259. }
  260. static void app_input_callback(InputEvent* input_event, void* ctx) {
  261. furi_assert(ctx);
  262. FuriMessageQueue* event_queue = ctx;
  263. furi_message_queue_put(event_queue, input_event, FuriWaitForever);
  264. }
  265. int32_t gpio_controller_main(void* p) {
  266. UNUSED(p);
  267. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
  268. // Configure view port
  269. ViewPort* view_port = view_port_alloc();
  270. view_port_draw_callback_set(view_port, app_draw_callback, view_port);
  271. view_port_input_callback_set(view_port, app_input_callback, event_queue);
  272. // Register view port in GUI
  273. Gui* gui = furi_record_open(RECORD_GUI);
  274. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  275. InputEvent event;
  276. init_gpio();
  277. vstate.prev_frame_time = furi_get_tick();
  278. vstate.elapsed_time = 0;
  279. bool running = true;
  280. while(running) {
  281. if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
  282. if( vstate.wiggle_frame < 0 )
  283. {
  284. if( (event.type == InputTypePress || event.type == InputTypeRelease) && event.key == InputKeyOk )
  285. {
  286. if( event.type == InputTypePress && elements[vstate.selected].gp_idx < 0 )
  287. {
  288. vstate.wiggle_frame = 0;
  289. vstate.elapsed_time = 0;
  290. }
  291. else if( elements[vstate.selected].gp_idx >= 0 && (event.type == InputTypePress || event.type == InputTypeRelease) )
  292. {
  293. int gp_idx = elements[vstate.selected].gp_idx;
  294. furi_hal_gpio_write(gpio_pin_config[gp_idx].pin, event.type == InputTypePress);
  295. gpio_pin_config[gp_idx].value = event.type == InputTypePress ? 1 : 0;
  296. }
  297. }
  298. else if(event.type == InputTypePress || event.type == InputTypeRepeat) {
  299. switch(event.key) {
  300. case InputKeyLeft:
  301. vstate.selected--;
  302. if(vstate.selected == GEARIC) vstate.selected = PIN_1W;
  303. else if(vstate.selected < 0) vstate.selected = GEARIC;
  304. break;
  305. case InputKeyRight:
  306. if(vstate.selected <= GEARIC)
  307. {
  308. vstate.selected++;
  309. vstate.selected = vstate.selected > GEARIC ? PIN_5V : vstate.selected;
  310. }
  311. else
  312. {
  313. vstate.selected++;
  314. vstate.selected = vstate.selected > PIN_1W ? PIN_3V : vstate.selected;
  315. }
  316. break;
  317. case InputKeyUp:
  318. case InputKeyDown:
  319. if (elements[vstate.selected].opposite != NONE) vstate.selected = elements[vstate.selected].opposite;
  320. break;
  321. case InputKeyBack:
  322. running = false;
  323. break;
  324. default:
  325. break;
  326. }
  327. }
  328. }
  329. }
  330. view_port_update(view_port);
  331. }
  332. view_port_enabled_set(view_port, false);
  333. gui_remove_view_port(gui, view_port);
  334. view_port_free(view_port);
  335. furi_message_queue_free(event_queue);
  336. furi_record_close(RECORD_GUI);
  337. return 0;
  338. }