irda.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #include "flipper.h"
  2. #include "flipper_v2.h"
  3. #include "irda_nec.h"
  4. #include "irda_samsung.h"
  5. #include "irda_protocols.h"
  6. typedef enum {
  7. EventTypeTick,
  8. EventTypeKey,
  9. } EventType;
  10. typedef struct {
  11. union {
  12. InputEvent input;
  13. } value;
  14. EventType type;
  15. } AppEvent;
  16. typedef struct {
  17. uint8_t mode_id;
  18. uint16_t carrier_freq;
  19. uint8_t carrier_duty_cycle_id;
  20. uint8_t nec_packet_id;
  21. uint8_t samsung_packet_id;
  22. } State;
  23. typedef void (*ModeInput)(AppEvent*, State*);
  24. typedef void (*ModeRender)(CanvasApi*, State*);
  25. void input_carrier(AppEvent* event, State* state);
  26. void render_carrier(CanvasApi* canvas, State* state);
  27. void input_nec(AppEvent* event, State* state);
  28. void render_nec(CanvasApi* canvas, State* state);
  29. void render_carrier(CanvasApi* canvas, State* state);
  30. void input_samsung(AppEvent* event, State* state);
  31. void render_samsung(CanvasApi* canvas, State* state);
  32. typedef struct {
  33. ModeRender render;
  34. ModeInput input;
  35. } Mode;
  36. typedef struct {
  37. uint8_t addr;
  38. uint8_t data;
  39. } NecPacket;
  40. typedef struct {
  41. uint16_t addr;
  42. uint16_t data;
  43. } SamsungPacket;
  44. const Mode modes[] = {
  45. {.render = render_carrier, .input = input_carrier},
  46. {.render = render_nec, .input = input_nec},
  47. {.render = render_samsung, .input = input_samsung},
  48. };
  49. const NecPacket nec_packets[] = {
  50. {.addr = 0xFF, .data = 0x11},
  51. {.addr = 0xF7, .data = 0x59},
  52. {.addr = 0xFF, .data = 0x01},
  53. {.addr = 0xFF, .data = 0x10},
  54. {.addr = 0xFF, .data = 0x15},
  55. {.addr = 0xFF, .data = 0x25},
  56. {.addr = 0xFF, .data = 0xF0},
  57. };
  58. const SamsungPacket samsung_packets[] = {
  59. {.addr = 0xE0E, .data = 0xF30C},
  60. {.addr = 0xE0E, .data = 0xF40D},
  61. {.addr = 0xE0E, .data = 0xF50E},
  62. };
  63. const float duty_cycles[] = {0.1, 0.25, 0.333, 0.5, 1.0};
  64. void render_carrier(CanvasApi* canvas, State* state) {
  65. canvas->set_font(canvas, FontSecondary);
  66. canvas->draw_str(canvas, 2, 25, "carrier mode >");
  67. canvas->draw_str(canvas, 2, 37, "? /\\ freq | \\/ duty cycle");
  68. {
  69. char buf[24];
  70. sprintf(buf, "frequency: %u Hz", state->carrier_freq);
  71. canvas->draw_str(canvas, 2, 50, buf);
  72. sprintf(
  73. buf, "duty cycle: %d/1000", (int)(duty_cycles[state->carrier_duty_cycle_id] * 1000));
  74. canvas->draw_str(canvas, 2, 62, buf);
  75. }
  76. }
  77. void render_nec(CanvasApi* canvas, State* state) {
  78. canvas->set_font(canvas, FontSecondary);
  79. canvas->draw_str(canvas, 2, 25, "< nec mode >");
  80. canvas->draw_str(canvas, 2, 37, "? /\\ \\/ packet");
  81. {
  82. char buf[24];
  83. sprintf(
  84. buf,
  85. "packet: %02X %02X",
  86. nec_packets[state->nec_packet_id].addr,
  87. nec_packets[state->nec_packet_id].data);
  88. canvas->draw_str(canvas, 2, 50, buf);
  89. }
  90. }
  91. void render_samsung(CanvasApi* canvas, State* state) {
  92. canvas->set_font(canvas, FontSecondary);
  93. canvas->draw_str(canvas, 2, 25, "< samsung32 mode");
  94. canvas->draw_str(canvas, 2, 37, "? /\\ \\/ packet");
  95. {
  96. char buf[24];
  97. sprintf(
  98. buf,
  99. "packet: %02X %02X",
  100. samsung_packets[state->samsung_packet_id].addr,
  101. samsung_packets[state->samsung_packet_id].data);
  102. canvas->draw_str(canvas, 2, 50, buf);
  103. }
  104. }
  105. void input_carrier(AppEvent* event, State* state) {
  106. if(event->value.input.input == InputOk) {
  107. if(event->value.input.state) {
  108. hal_pwm_set(
  109. duty_cycles[state->carrier_duty_cycle_id],
  110. state->carrier_freq,
  111. &htim2,
  112. TIM_CHANNEL_4);
  113. } else {
  114. hal_pwm_stop(&htim2, TIM_CHANNEL_4);
  115. }
  116. }
  117. if(event->value.input.state && event->value.input.input == InputUp) {
  118. if(state->carrier_freq < 45000) {
  119. state->carrier_freq += 1000;
  120. } else {
  121. state->carrier_freq = 33000;
  122. }
  123. }
  124. if(event->value.input.state && event->value.input.input == InputDown) {
  125. uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]);
  126. if(state->carrier_duty_cycle_id < (duty_cycles_count - 1)) {
  127. state->carrier_duty_cycle_id++;
  128. } else {
  129. state->carrier_duty_cycle_id = 0;
  130. }
  131. }
  132. }
  133. void input_nec(AppEvent* event, State* state) {
  134. uint8_t packets_count = sizeof(nec_packets) / sizeof(nec_packets[0]);
  135. if(event->value.input.input == InputOk) {
  136. if(event->value.input.state) {
  137. vTaskSuspendAll();
  138. ir_nec_send(
  139. nec_packets[state->nec_packet_id].addr, nec_packets[state->nec_packet_id].data);
  140. xTaskResumeAll();
  141. }
  142. }
  143. if(event->value.input.state && event->value.input.input == InputUp) {
  144. if(state->nec_packet_id < (packets_count - 1)) {
  145. state->nec_packet_id++;
  146. } else {
  147. state->nec_packet_id = 0;
  148. }
  149. }
  150. if(event->value.input.state && event->value.input.input == InputDown) {
  151. if(state->nec_packet_id > 0) {
  152. state->nec_packet_id--;
  153. } else {
  154. state->nec_packet_id = packets_count - 1;
  155. }
  156. }
  157. }
  158. void input_samsung(AppEvent* event, State* state) {
  159. uint8_t packets_count = sizeof(samsung_packets) / sizeof(samsung_packets[0]);
  160. if(event->value.input.input == InputOk) {
  161. if(event->value.input.state) {
  162. vTaskSuspendAll();
  163. ir_samsung_send(
  164. samsung_packets[state->samsung_packet_id].addr,
  165. samsung_packets[state->samsung_packet_id].data);
  166. xTaskResumeAll();
  167. }
  168. }
  169. if(event->value.input.state && event->value.input.input == InputUp) {
  170. if(state->samsung_packet_id < (packets_count - 1)) {
  171. state->samsung_packet_id++;
  172. } else {
  173. state->samsung_packet_id = 0;
  174. }
  175. }
  176. if(event->value.input.state && event->value.input.input == InputDown) {
  177. if(state->samsung_packet_id > 0) {
  178. state->samsung_packet_id--;
  179. } else {
  180. state->samsung_packet_id = packets_count - 1;
  181. }
  182. }
  183. }
  184. static void render_callback(CanvasApi* canvas, void* ctx) {
  185. State* state = (State*)acquire_mutex((ValueMutex*)ctx, 25);
  186. canvas->clear(canvas);
  187. canvas->set_color(canvas, ColorBlack);
  188. canvas->set_font(canvas, FontPrimary);
  189. canvas->draw_str(canvas, 2, 12, "irda test");
  190. modes[state->mode_id].render(canvas, state);
  191. release_mutex((ValueMutex*)ctx, state);
  192. }
  193. static void input_callback(InputEvent* input_event, void* ctx) {
  194. osMessageQueueId_t event_queue = (QueueHandle_t)ctx;
  195. AppEvent event;
  196. event.type = EventTypeKey;
  197. event.value.input = *input_event;
  198. osMessageQueuePut(event_queue, &event, 0, 0);
  199. }
  200. void irda(void* p) {
  201. osMessageQueueId_t event_queue = osMessageQueueNew(1, sizeof(AppEvent), NULL);
  202. State _state;
  203. uint8_t mode_count = sizeof(modes) / sizeof(modes[0]);
  204. uint8_t duty_cycles_count = sizeof(duty_cycles) / sizeof(duty_cycles[0]);
  205. _state.carrier_duty_cycle_id = duty_cycles_count - 2;
  206. _state.carrier_freq = 36000;
  207. _state.mode_id = 0;
  208. _state.nec_packet_id = 0;
  209. _state.samsung_packet_id = 0;
  210. ValueMutex state_mutex;
  211. if(!init_mutex(&state_mutex, &_state, sizeof(State))) {
  212. printf("cannot create mutex\n");
  213. furiac_exit(NULL);
  214. }
  215. Widget* widget = widget_alloc();
  216. widget_draw_callback_set(widget, render_callback, &state_mutex);
  217. widget_input_callback_set(widget, input_callback, event_queue);
  218. // Open GUI and register widget
  219. GuiApi* gui = (GuiApi*)furi_open("gui");
  220. if(gui == NULL) {
  221. printf("gui is not available\n");
  222. furiac_exit(NULL);
  223. }
  224. gui->add_widget(gui, widget, GuiLayerFullscreen);
  225. AppEvent event;
  226. while(1) {
  227. osStatus_t event_status = osMessageQueueGet(event_queue, &event, NULL, osWaitForever);
  228. State* state = (State*)acquire_mutex_block(&state_mutex);
  229. if(event_status == osOK) {
  230. if(event.type == EventTypeKey) {
  231. // press events
  232. if(event.value.input.state && event.value.input.input == InputBack) {
  233. printf("[irda] bye!\n");
  234. // TODO remove all widgets create by app
  235. widget_enabled_set(widget, false);
  236. furiac_exit(NULL);
  237. }
  238. if(event.value.input.state && event.value.input.input == InputLeft) {
  239. if(state->mode_id > 0) {
  240. state->mode_id--;
  241. }
  242. }
  243. if(event.value.input.state && event.value.input.input == InputRight) {
  244. if(state->mode_id < (mode_count - 1)) {
  245. state->mode_id++;
  246. }
  247. }
  248. modes[state->mode_id].input(&event, state);
  249. }
  250. } else {
  251. // event timeout
  252. }
  253. release_mutex(&state_mutex, state);
  254. widget_update(widget);
  255. }
  256. }