mag_scene_settings.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  1. #include "../mag_i.h"
  2. #include "../mag_state.h"
  3. #include "../helpers/mag_helpers.h"
  4. #define TAG "MagSceneEmulateConfig"
  5. enum VarItemListIndex {
  6. VarItemListIndexPinInput,
  7. VarItemListIndexPinOutput,
  8. VarItemListIndexPinEnable,
  9. VarItemListIndexNRepeats,
  10. VarItemListIndexRepeatModeOn,
  11. VarItemListIndexAllowUART,
  12. };
  13. static const char* gpio[] = {
  14. [MagPinA7] = "2 (A7)",
  15. [MagPinA6] = "3 (A6)",
  16. [MagPinA4] = "4 (A4)",
  17. [MagPinB3] = "5 (B3)",
  18. [MagPinB2] = "6 (B2)",
  19. [MagPinC3] = "7 (C3)",
  20. [MagPinC1] = "15 (C1)",
  21. [MagPinC0] = "16 (C0)",
  22. };
  23. const uint8_t GPIO_COUNT = COUNT_OF(gpio);
  24. // static const char* uart_pins[] = {[DapUartTypeUSART1] = "13,14", [DapUartTypeLPUART1] = "15,16"};
  25. // static const char* uart_swap[] = {[DapUartTXRXNormal] = "No", [DapUartTXRXSwap] = "Yes"};
  26. #define N_REPEATS_COUNT 10
  27. const char* const n_repeats_text[N_REPEATS_COUNT] = {
  28. "2",
  29. "3",
  30. "4",
  31. "5",
  32. "6",
  33. "7",
  34. "8",
  35. "9",
  36. "10",
  37. "20",
  38. };
  39. const uint32_t n_repeats_value[N_REPEATS_COUNT] = {
  40. 2,
  41. 3,
  42. 4,
  43. 5,
  44. 6,
  45. 7,
  46. 8,
  47. 9,
  48. 10,
  49. 20,
  50. };
  51. #define OFF_ON_COUNT 2
  52. const char* const off_on_text[OFF_ON_COUNT] = {
  53. "OFF",
  54. "ON",
  55. };
  56. void mag_scene_settings_var_item_list_callback(void* context, uint32_t index) {
  57. Mag* mag = context;
  58. view_dispatcher_send_custom_event(mag->view_dispatcher, index);
  59. }
  60. static void mag_scene_settings_set_gpio(VariableItem* item, MagPin* pin_out) {
  61. MagPin pin = variable_item_get_current_value_index(item);
  62. variable_item_set_current_value_text(item, gpio[pin]);
  63. *pin_out = pin;
  64. }
  65. static void mag_scene_settings_set_gpio_input(VariableItem* item) {
  66. Mag* mag = variable_item_get_context(item);
  67. mag_scene_settings_set_gpio(item, &mag->state.pin_input);
  68. }
  69. static void mag_scene_settings_set_gpio_output(VariableItem* item) {
  70. Mag* mag = variable_item_get_context(item);
  71. mag_scene_settings_set_gpio(item, &mag->state.pin_output);
  72. }
  73. static void mag_scene_settings_set_gpio_enable(VariableItem* item) {
  74. Mag* mag = variable_item_get_context(item);
  75. mag_scene_settings_set_gpio(item, &mag->state.pin_enable);
  76. }
  77. static void mag_scene_settings_set_n_repeats(VariableItem* item) {
  78. Mag* mag = variable_item_get_context(item);
  79. uint8_t index = variable_item_get_current_value_index(item);
  80. variable_item_set_current_value_text(item, n_repeats_text[index]);
  81. mag->state.n_repeats = n_repeats_value[index];
  82. }
  83. static void mag_scene_settings_set_bool(VariableItem* item, bool* bool_out) {
  84. uint8_t index = variable_item_get_current_value_index(item);
  85. variable_item_set_current_value_text(item, off_on_text[index]);
  86. *bool_out = (bool)index;
  87. }
  88. static void mag_scene_settings_set_repeat_mode(VariableItem* item) {
  89. Mag* mag = variable_item_get_context(item);
  90. mag_scene_settings_set_bool(item, &mag->state.repeat_mode);
  91. }
  92. static void mag_scene_settings_set_allow_uart(VariableItem* item) {
  93. Mag* mag = variable_item_get_context(item);
  94. // rising change when value index is truth-y, and prior value false
  95. bool rising = !mag->state.allow_uart && !!variable_item_get_current_value_index(item);
  96. // trigger dialog only on rising change
  97. if(rising) {
  98. scene_manager_set_scene_state(mag->scene_manager, MagSceneSettings, (uint32_t)item);
  99. view_dispatcher_send_custom_event(mag->view_dispatcher, MagEventConfirmDialog);
  100. }
  101. // set value & text based on current varitem index
  102. mag_scene_settings_set_bool(item, &mag->state.allow_uart);
  103. }
  104. static void mag_pin_variable_item_list_add(
  105. Mag* mag,
  106. const char* label,
  107. MagPin pin,
  108. VariableItemChangeCallback change_callback) {
  109. VariableItem* item =
  110. variable_item_list_add(mag->variable_item_list, label, GPIO_COUNT, change_callback, mag);
  111. variable_item_set_current_value_index(item, pin);
  112. variable_item_set_current_value_text(item, gpio[pin]);
  113. }
  114. static void mag_bool_variable_item_list_add(
  115. Mag* mag,
  116. const char* label,
  117. bool value,
  118. VariableItemChangeCallback change_callback) {
  119. VariableItem* item =
  120. variable_item_list_add(mag->variable_item_list, label, OFF_ON_COUNT, change_callback, mag);
  121. uint32_t value_index = (uint32_t)value;
  122. variable_item_set_current_value_index(item, value_index);
  123. variable_item_set_current_value_text(item, off_on_text[value_index]);
  124. }
  125. void mag_scene_settings_on_enter(void* context) {
  126. Mag* mag = context;
  127. VariableItemList* var_item_list = mag->variable_item_list;
  128. VariableItem* item;
  129. uint32_t value_index;
  130. // reload state in the event temporary changes have been
  131. // made on the emulate config screen
  132. // only changes made in this scene should be saved, and this scene
  133. // should always represent the saved settings, not the transient ones for
  134. // a given emulation.
  135. mag_state_load(&mag->state);
  136. mag_pin_variable_item_list_add(
  137. mag, "Input pin:", mag->state.pin_input, mag_scene_settings_set_gpio_input);
  138. mag_pin_variable_item_list_add(
  139. mag, "Output pin:", mag->state.pin_output, mag_scene_settings_set_gpio_output);
  140. mag_pin_variable_item_list_add(
  141. mag, "Enable pin:", mag->state.pin_enable, mag_scene_settings_set_gpio_enable);
  142. mag_bool_variable_item_list_add(
  143. mag, "Repeat default:", mag->state.repeat_mode, mag_scene_settings_set_repeat_mode);
  144. item = variable_item_list_add(
  145. var_item_list, "# repeats: ", N_REPEATS_COUNT, mag_scene_settings_set_n_repeats, mag);
  146. value_index = value_index_uint32(mag->state.n_repeats, n_repeats_value, N_REPEATS_COUNT);
  147. variable_item_set_current_value_index(item, value_index);
  148. variable_item_set_current_value_text(item, n_repeats_text[value_index]);
  149. mag_bool_variable_item_list_add(
  150. mag, "UART MSR:", mag->state.allow_uart, mag_scene_settings_set_allow_uart);
  151. variable_item_list_set_enter_callback(
  152. var_item_list, mag_scene_settings_var_item_list_callback, mag);
  153. variable_item_list_set_selected_item(
  154. var_item_list, scene_manager_get_scene_state(mag->scene_manager, MagSceneSettings));
  155. view_dispatcher_switch_to_view(mag->view_dispatcher, MagViewVariableItemList);
  156. }
  157. void mag_scene_settings_dialog_invalid_pins(Mag* mag) {
  158. SceneManager* scene_manager = mag->scene_manager;
  159. DialogMessage* message = dialog_message_alloc();
  160. dialog_message_set_header(message, "Invalid Pin Config!", 64, 0, AlignCenter, AlignTop);
  161. dialog_message_set_buttons(message, "Modify", NULL, "Reset");
  162. dialog_message_set_text(
  163. message,
  164. "Pins cannot overlap.\nChange, or reset to defaults.",
  165. 64,
  166. 32,
  167. AlignCenter,
  168. AlignCenter);
  169. DialogMessageButton res = dialog_message_show(furi_record_open(RECORD_DIALOGS), message);
  170. dialog_message_free(message);
  171. furi_record_close(RECORD_DIALOGS);
  172. if(res == DialogMessageButtonRight) {
  173. mag_state_gpio_reset(&mag->state);
  174. scene_manager_previous_scene(scene_manager);
  175. }
  176. }
  177. bool mag_scene_settings_on_event(void* context, SceneManagerEvent event) {
  178. Mag* mag = context;
  179. SceneManager* scene_manager = mag->scene_manager;
  180. bool consumed = false;
  181. switch(event.type) {
  182. case SceneManagerEventTypeBack:
  183. // when attempting to exit, validate pin configuration
  184. // if invalid, prompt
  185. consumed = true;
  186. if(!mag_state_gpio_is_valid(&mag->state)) {
  187. mag_scene_settings_dialog_invalid_pins(mag);
  188. } else {
  189. scene_manager_previous_scene(scene_manager);
  190. }
  191. break;
  192. case SceneManagerEventTypeCustom:
  193. // scene_manager_set_scene_state(mag->scene_manager, MagSceneSettings, event.event);
  194. consumed = true;
  195. if(event.event == MagEventConfirmDialog) {
  196. DialogMessage* msg = dialog_message_alloc();
  197. dialog_message_set_header(msg, "UART MSR", 64, 0, AlignCenter, AlignTop);
  198. dialog_message_set_buttons(msg, "No", NULL, "Yes");
  199. dialog_message_set_text(
  200. msg,
  201. "This option requires a\nUART-compatible mag reader.\nIs it installed?\n",
  202. 64,
  203. 32,
  204. AlignCenter,
  205. AlignCenter);
  206. DialogMessageButton res = dialog_message_show(furi_record_open(RECORD_DIALOGS), msg);
  207. if(res != DialogMessageButtonRight) {
  208. // if not "Yes", reset to "OFF" (0 / false-y)
  209. VariableItem* item =
  210. (VariableItem*)scene_manager_get_scene_state(scene_manager, MagSceneSettings);
  211. variable_item_set_current_value_index(item, 0);
  212. mag_scene_settings_set_bool(item, &mag->state.allow_uart);
  213. }
  214. dialog_message_free(msg);
  215. furi_record_close(RECORD_DIALOGS);
  216. // clear item from scene state
  217. scene_manager_set_scene_state(scene_manager, MagSceneSettings, 0);
  218. }
  219. break;
  220. default:
  221. break;
  222. }
  223. return consumed;
  224. }
  225. void mag_scene_settings_on_exit(void* context) {
  226. Mag* mag = context;
  227. variable_item_list_reset(mag->variable_item_list);
  228. mag_state_save(&mag->state);
  229. }