irda.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include "irda.h"
  2. #include "furi/check.h"
  3. #include "irda_common_i.h"
  4. #include "irda_protocol_defs_i.h"
  5. #include <stdbool.h>
  6. #include <stdint.h>
  7. #include <stdlib.h>
  8. #include <furi.h>
  9. #include "irda_i.h"
  10. #include <api-hal-irda.h>
  11. struct IrdaDecoderHandler {
  12. void** ctx;
  13. };
  14. typedef struct {
  15. IrdaAlloc alloc;
  16. IrdaDecode decode;
  17. IrdaReset reset;
  18. IrdaFree free;
  19. } IrdaDecoders;
  20. typedef struct {
  21. IrdaEncoderReset reset;
  22. IrdaAlloc alloc;
  23. IrdaEncode encode;
  24. IrdaFree free;
  25. } IrdaEncoders;
  26. typedef struct {
  27. IrdaProtocol protocol;
  28. const char* name;
  29. IrdaDecoders decoder;
  30. IrdaEncoders encoder;
  31. uint8_t address_length;
  32. uint8_t command_length;
  33. } IrdaProtocolImplementation;
  34. struct IrdaEncoderHandler {
  35. void* encoder;
  36. IrdaProtocol protocol;
  37. };
  38. // TODO: replace with key-value, Now we refer by enum index, which is dangerous.
  39. static const IrdaProtocolImplementation irda_protocols[] = {
  40. // #0
  41. { .protocol = IrdaProtocolNEC,
  42. .name = "NEC",
  43. .decoder = {
  44. .alloc = irda_decoder_nec_alloc,
  45. .decode = irda_decoder_nec_decode,
  46. .reset = irda_decoder_nec_reset,
  47. .free = irda_decoder_nec_free},
  48. .encoder = {
  49. .alloc = irda_encoder_nec_alloc,
  50. .encode = irda_encoder_nec_encode,
  51. .reset = irda_encoder_nec_reset,
  52. .free = irda_encoder_nec_free},
  53. .address_length = 2,
  54. .command_length = 2,
  55. },
  56. // #1 - have to be after NEC
  57. { .protocol = IrdaProtocolNECext,
  58. .name = "NECext",
  59. .decoder = {
  60. .alloc = irda_decoder_necext_alloc,
  61. .decode = irda_decoder_nec_decode,
  62. .reset = irda_decoder_nec_reset,
  63. .free = irda_decoder_nec_free},
  64. .encoder = {
  65. .alloc = irda_encoder_necext_alloc,
  66. .encode = irda_encoder_nec_encode,
  67. .reset = irda_encoder_necext_reset,
  68. .free = irda_encoder_nec_free},
  69. .address_length = 4,
  70. .command_length = 2,
  71. },
  72. // #2
  73. { .protocol = IrdaProtocolSamsung32,
  74. .name ="Samsung32",
  75. .decoder = {
  76. .alloc = irda_decoder_samsung32_alloc,
  77. .decode = irda_decoder_samsung32_decode,
  78. .reset = irda_decoder_samsung32_reset,
  79. .free = irda_decoder_samsung32_free},
  80. .encoder = {
  81. .alloc = irda_encoder_samsung32_alloc,
  82. .encode = irda_encoder_samsung32_encode,
  83. .reset = irda_encoder_samsung32_reset,
  84. .free = irda_encoder_samsung32_free},
  85. .address_length = 2,
  86. .command_length = 2,
  87. },
  88. // #3
  89. { .protocol = IrdaProtocolRC6,
  90. .name = "RC6",
  91. .decoder = {
  92. .alloc = irda_decoder_rc6_alloc,
  93. .decode = irda_decoder_rc6_decode,
  94. .reset = irda_decoder_rc6_reset,
  95. .free = irda_decoder_rc6_free},
  96. .encoder = {
  97. .alloc = irda_encoder_rc6_alloc,
  98. .encode = irda_encoder_rc6_encode,
  99. .reset = irda_encoder_rc6_reset,
  100. .free = irda_encoder_rc6_free},
  101. .address_length = 2,
  102. .command_length = 2,
  103. },
  104. };
  105. const IrdaMessage* irda_decode(IrdaDecoderHandler* handler, bool level, uint32_t duration) {
  106. furi_assert(handler);
  107. IrdaMessage* message = NULL;
  108. IrdaMessage* result = NULL;
  109. for (int i = 0; i < COUNT_OF(irda_protocols); ++i) {
  110. if (irda_protocols[i].decoder.decode) {
  111. message = irda_protocols[i].decoder.decode(handler->ctx[i], level, duration);
  112. if (!result && message) {
  113. message->protocol = irda_protocols[i].protocol;
  114. result = message;
  115. }
  116. }
  117. }
  118. return result;
  119. }
  120. IrdaDecoderHandler* irda_alloc_decoder(void) {
  121. IrdaDecoderHandler* handler = furi_alloc(sizeof(IrdaDecoderHandler));
  122. handler->ctx = furi_alloc(sizeof(void*) * COUNT_OF(irda_protocols));
  123. for (int i = 0; i < COUNT_OF(irda_protocols); ++i) {
  124. handler->ctx[i] = 0;
  125. if (irda_protocols[i].decoder.alloc)
  126. handler->ctx[i] = irda_protocols[i].decoder.alloc();
  127. }
  128. return handler;
  129. }
  130. void irda_free_decoder(IrdaDecoderHandler* handler) {
  131. furi_assert(handler);
  132. furi_assert(handler->ctx);
  133. for (int i = 0; i < COUNT_OF(irda_protocols); ++i) {
  134. if (irda_protocols[i].decoder.free)
  135. irda_protocols[i].decoder.free(handler->ctx[i]);
  136. }
  137. free(handler->ctx);
  138. free(handler);
  139. }
  140. void irda_reset_decoder(IrdaDecoderHandler* handler) {
  141. for (int i = 0; i < COUNT_OF(irda_protocols); ++i) {
  142. if (irda_protocols[i].decoder.reset)
  143. irda_protocols[i].decoder.reset(handler->ctx[i]);
  144. }
  145. }
  146. IrdaEncoderHandler* irda_alloc_encoder(void) {
  147. IrdaEncoderHandler* handler = furi_alloc(sizeof(IrdaEncoderHandler));
  148. handler->encoder = NULL;
  149. handler->protocol = IrdaProtocolUnknown;
  150. return handler;
  151. }
  152. void irda_free_encoder(IrdaEncoderHandler* handler) {
  153. furi_assert(handler);
  154. if (handler->encoder) {
  155. furi_assert(irda_is_protocol_valid(handler->protocol));
  156. furi_assert(irda_protocols[handler->protocol].encoder.free);
  157. irda_protocols[handler->protocol].encoder.free(handler->encoder);
  158. }
  159. free(handler);
  160. }
  161. void irda_reset_encoder(IrdaEncoderHandler* handler, const IrdaMessage* message) {
  162. furi_assert(handler);
  163. furi_assert(message);
  164. furi_assert(irda_is_protocol_valid(message->protocol));
  165. furi_assert(irda_protocols[message->protocol].encoder.reset);
  166. furi_assert(irda_protocols[message->protocol].encoder.alloc);
  167. /* Realloc encoder if different protocol set */
  168. if (message->protocol != handler->protocol) {
  169. if (handler->encoder != NULL) {
  170. furi_assert(handler->protocol != IrdaProtocolUnknown);
  171. irda_protocols[handler->protocol].encoder.free(handler->encoder);
  172. }
  173. handler->encoder = irda_protocols[message->protocol].encoder.alloc();
  174. handler->protocol = message->protocol;
  175. }
  176. irda_protocols[handler->protocol].encoder.reset(handler->encoder, message);
  177. }
  178. IrdaStatus irda_encode(IrdaEncoderHandler* handler, uint32_t* duration, bool* level) {
  179. furi_assert(handler);
  180. furi_assert(irda_is_protocol_valid(handler->protocol));
  181. furi_assert(irda_protocols[handler->protocol].encoder.encode);
  182. IrdaStatus status = irda_protocols[handler->protocol].encoder.encode(handler->encoder, duration, level);
  183. furi_assert(status != IrdaStatusError);
  184. return status;
  185. }
  186. bool irda_is_protocol_valid(IrdaProtocol protocol) {
  187. return (protocol >= 0) && (protocol < COUNT_OF(irda_protocols));
  188. }
  189. IrdaProtocol irda_get_protocol_by_name(const char* protocol_name) {
  190. for (int i = 0; i < COUNT_OF(irda_protocols); ++i) {
  191. if (!strcmp(irda_protocols[i].name, protocol_name))
  192. return i;
  193. }
  194. return IrdaProtocolUnknown;
  195. }
  196. const char* irda_get_protocol_name(IrdaProtocol protocol) {
  197. if (irda_is_protocol_valid(protocol))
  198. return irda_protocols[protocol].name;
  199. else
  200. return "Invalid";
  201. }
  202. uint8_t irda_get_protocol_address_length(IrdaProtocol protocol) {
  203. if (irda_is_protocol_valid(protocol))
  204. return irda_protocols[protocol].address_length;
  205. else
  206. return 0;
  207. }
  208. uint8_t irda_get_protocol_command_length(IrdaProtocol protocol) {
  209. if (irda_is_protocol_valid(protocol))
  210. return irda_protocols[protocol].command_length;
  211. else
  212. return 0;
  213. }