xremote_ir_signal.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #include "xremote_ir_signal.h"
  2. #include "../../xremote_i.h"
  3. static void xremote_ir_signal_clear_timings(InfraredSignal* signal) {
  4. if(signal->is_raw) {
  5. free(signal->payload.raw.timings);
  6. signal->payload.raw.timings_size = 0;
  7. signal->payload.raw.timings = NULL;
  8. }
  9. }
  10. static bool xremote_ir_signal_is_message_valid(InfraredMessage* message) {
  11. if(!infrared_is_protocol_valid(message->protocol)) {
  12. FURI_LOG_E(TAG, "Unknown protocol");
  13. return false;
  14. }
  15. uint32_t address_length = infrared_get_protocol_address_length(message->protocol);
  16. uint32_t address_mask = (1UL << address_length) - 1;
  17. if(message->address != (message->address & address_mask)) {
  18. FURI_LOG_E(
  19. TAG,
  20. "Address is out of range (mask 0x%08lX): 0x%lX\r\n",
  21. address_mask,
  22. message->address);
  23. return false;
  24. }
  25. uint32_t command_length = infrared_get_protocol_command_length(message->protocol);
  26. uint32_t command_mask = (1UL << command_length) - 1;
  27. if(message->command != (message->command & command_mask)) {
  28. FURI_LOG_E(
  29. TAG,
  30. "Command is out of range (mask 0x%08lX): 0x%lX\r\n",
  31. command_mask,
  32. message->command);
  33. return false;
  34. }
  35. return true;
  36. }
  37. static bool xremote_ir_signal_is_raw_valid(InfraredRawSignal* raw) {
  38. if((raw->frequency > INFRARED_MAX_FREQUENCY) || (raw->frequency < INFRARED_MIN_FREQUENCY)) {
  39. FURI_LOG_E(
  40. TAG,
  41. "Frequency is out of range (%X - %X): %lX",
  42. INFRARED_MIN_FREQUENCY,
  43. INFRARED_MAX_FREQUENCY,
  44. raw->frequency);
  45. return false;
  46. } else if((raw->duty_cycle <= 0) || (raw->duty_cycle > 1)) {
  47. FURI_LOG_E(TAG, "Duty cycle is out of range (0 - 1): %f", (double)raw->duty_cycle);
  48. return false;
  49. } else if((raw->timings_size <= 0) || (raw->timings_size > MAX_TIMINGS_AMOUNT)) {
  50. FURI_LOG_E(
  51. TAG,
  52. "Timings amount is out of range (0 - %X): %zX",
  53. MAX_TIMINGS_AMOUNT,
  54. raw->timings_size);
  55. return false;
  56. }
  57. return true;
  58. }
  59. static inline bool xremote_ir_signal_read_message(InfraredSignal* signal, FlipperFormat* ff) {
  60. FuriString* buf;
  61. buf = furi_string_alloc();
  62. bool success = false;
  63. do {
  64. if(!flipper_format_read_string(ff, "protocol", buf)) break;
  65. InfraredMessage message;
  66. message.protocol = infrared_get_protocol_by_name(furi_string_get_cstr(buf));
  67. success = flipper_format_read_hex(ff, "address", (uint8_t*)&message.address, 4) &&
  68. flipper_format_read_hex(ff, "command", (uint8_t*)&message.command, 4) &&
  69. xremote_ir_signal_is_message_valid(&message);
  70. if(!success) break;
  71. xremote_ir_signal_set_message(signal, &message);
  72. } while(0);
  73. return success;
  74. }
  75. static inline bool xremote_ir_signal_read_raw(InfraredSignal* signal, FlipperFormat* ff) {
  76. uint32_t timings_size, frequency;
  77. float duty_cycle;
  78. bool success = flipper_format_read_uint32(ff, "frequency", &frequency, 1) &&
  79. flipper_format_read_float(ff, "duty_cycle", &duty_cycle, 1) &&
  80. flipper_format_get_value_count(ff, "data", &timings_size);
  81. if(!success || timings_size > MAX_TIMINGS_AMOUNT) {
  82. return false;
  83. }
  84. uint32_t* timings = malloc(sizeof(uint32_t) * timings_size);
  85. success = flipper_format_read_uint32(ff, "data", timings, timings_size);
  86. if(success) {
  87. xremote_ir_signal_set_raw_signal(signal, timings, timings_size, frequency, duty_cycle);
  88. }
  89. free(timings);
  90. return success;
  91. }
  92. InfraredSignal* xremote_ir_signal_alloc() {
  93. InfraredSignal* signal = malloc(sizeof(InfraredSignal));
  94. signal->is_raw = false;
  95. signal->payload.message.protocol = InfraredProtocolUnknown;
  96. return signal;
  97. }
  98. void xremote_ir_signal_free(InfraredSignal* signal) {
  99. xremote_ir_signal_clear_timings(signal);
  100. free(signal);
  101. }
  102. bool xremote_ir_signal_is_raw(InfraredSignal* signal) {
  103. return signal->is_raw;
  104. }
  105. bool xremote_ir_signal_is_valid(InfraredSignal* signal) {
  106. return signal->is_raw ? xremote_ir_signal_is_raw_valid(&signal->payload.raw) :
  107. xremote_ir_signal_is_message_valid(&signal->payload.message);
  108. }
  109. void xremote_ir_signal_set_signal(InfraredSignal* signal, const InfraredSignal* other) {
  110. if(other->is_raw) {
  111. const InfraredRawSignal* raw = &other->payload.raw;
  112. xremote_ir_signal_set_raw_signal(
  113. signal, raw->timings, raw->timings_size, raw->frequency, raw->duty_cycle);
  114. } else {
  115. const InfraredMessage* message = &other->payload.message;
  116. xremote_ir_signal_set_message(signal, message);
  117. }
  118. }
  119. void xremote_ir_signal_set_raw_signal(
  120. InfraredSignal* signal,
  121. const uint32_t* timings,
  122. size_t timings_size,
  123. uint32_t frequency,
  124. float duty_cycle) {
  125. xremote_ir_signal_clear_timings(signal);
  126. signal->is_raw = true;
  127. signal->payload.raw.timings_size = timings_size;
  128. signal->payload.raw.frequency = frequency;
  129. signal->payload.raw.duty_cycle = duty_cycle;
  130. signal->payload.raw.timings = malloc(timings_size * sizeof(uint32_t));
  131. memcpy(signal->payload.raw.timings, timings, timings_size * sizeof(uint32_t));
  132. }
  133. InfraredRawSignal* xremote_ir_signal_get_raw_signal(InfraredSignal* signal) {
  134. furi_assert(signal->is_raw);
  135. return &signal->payload.raw;
  136. }
  137. static bool xremote_ir_signal_read_body(InfraredSignal* signal, FlipperFormat* ff) {
  138. FuriString* tmp = furi_string_alloc();
  139. bool success = false;
  140. do {
  141. if(!flipper_format_read_string(ff, "type", tmp)) break;
  142. if(furi_string_equal(tmp, "raw")) {
  143. success = xremote_ir_signal_read_raw(signal, ff);
  144. } else if(furi_string_equal(tmp, "parsed")) {
  145. success = xremote_ir_signal_read_message(signal, ff);
  146. } else {
  147. FURI_LOG_E(TAG, "Unknown signal type");
  148. }
  149. } while(false);
  150. furi_string_free(tmp);
  151. return success;
  152. }
  153. bool xremote_ir_signal_read(InfraredSignal* signal, FlipperFormat* ff, FuriString* name) {
  154. FuriString* tmp = furi_string_alloc();
  155. bool success = false;
  156. do {
  157. if(!flipper_format_read_string(ff, "name", tmp)) break;
  158. furi_string_set(name, tmp);
  159. if(!xremote_ir_signal_read_body(signal, ff)) break;
  160. success = true;
  161. } while(0);
  162. furi_string_free(tmp);
  163. return success;
  164. }
  165. void xremote_ir_signal_set_message(InfraredSignal* signal, const InfraredMessage* message) {
  166. xremote_ir_signal_clear_timings(signal);
  167. signal->is_raw = false;
  168. signal->payload.message = *message;
  169. }
  170. InfraredMessage* xremote_ir_signal_get_message(InfraredSignal* signal) {
  171. furi_assert(!signal->is_raw);
  172. return &signal->payload.message;
  173. }