action_ir_utils.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. // Utility methods for IR transmission
  2. #include <furi.h>
  3. #include "../quac.h"
  4. #include <flipper_format/flipper_format.h>
  5. #include "action_ir_utils.h"
  6. InfraredSignal* infrared_utils_signal_alloc() {
  7. InfraredSignal* signal = malloc(sizeof(InfraredSignal));
  8. signal->is_raw = false;
  9. signal->payload.message.protocol = InfraredProtocolUnknown;
  10. return signal;
  11. }
  12. void infrared_utils_signal_free(InfraredSignal* signal) {
  13. if(signal->is_raw) {
  14. free(signal->payload.raw.timings);
  15. signal->payload.raw.timings = NULL;
  16. }
  17. free(signal);
  18. }
  19. bool infrared_utils_read_signal_at_index(
  20. FlipperFormat* fff_data_file,
  21. uint32_t index,
  22. InfraredSignal* signal,
  23. FuriString* name) {
  24. //
  25. FuriString* temp_str;
  26. temp_str = furi_string_alloc();
  27. uint32_t temp_data32;
  28. bool success = false;
  29. do {
  30. if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
  31. FURI_LOG_E(TAG, "IR: Missing or incorrect header");
  32. break;
  33. }
  34. if(!furi_string_cmp_str(temp_str, INFRARED_FILE_TYPE) &&
  35. temp_data32 == INFRARED_FILE_VERSION) {
  36. } else {
  37. // ACTION_SET_ERROR("IR: File type or version mismatch");
  38. FURI_LOG_E(TAG, "IR: File type or version mismatch");
  39. break;
  40. }
  41. // Read the file until we find the signal we want
  42. uint32_t i = 0;
  43. bool found = false;
  44. while(flipper_format_read_string(fff_data_file, "name", name)) {
  45. if(i == index) {
  46. found = true;
  47. break;
  48. }
  49. ++i;
  50. }
  51. if(!found) {
  52. // ACTION_SET_ERROR("IR: Could not find command %lu!", index);
  53. FURI_LOG_E(TAG, "Requested IR command %lu not found", index);
  54. furi_string_reset(name);
  55. break;
  56. }
  57. FURI_LOG_I(TAG, "Reading signal %s", furi_string_get_cstr(temp_str));
  58. if(!flipper_format_read_string(fff_data_file, "type", temp_str)) {
  59. // ACTION_SET_ERROR("IR: Type missing");
  60. break;
  61. }
  62. if(furi_string_equal(temp_str, "parsed")) {
  63. FURI_LOG_I(TAG, "IR File is PARSED");
  64. signal->is_raw = false;
  65. if(!flipper_format_read_string(fff_data_file, "protocol", temp_str)) {
  66. // ACTION_SET_ERROR("IR: Invalid or missing protocol");
  67. break;
  68. }
  69. signal->payload.message.protocol =
  70. infrared_get_protocol_by_name(furi_string_get_cstr(temp_str));
  71. if(!infrared_is_protocol_valid(signal->payload.message.protocol)) {
  72. // ACTION_SET_ERROR("IR: Invalid or unknown protocol");
  73. break;
  74. }
  75. if(!flipper_format_read_hex(
  76. fff_data_file, "address", (uint8_t*)&signal->payload.message.address, 4)) {
  77. // ACTION_SET_ERROR("IR: Failed to read address");
  78. break;
  79. }
  80. if(!flipper_format_read_hex(
  81. fff_data_file, "command", (uint8_t*)&signal->payload.message.command, 4)) {
  82. // ACTION_SET_ERROR("IR: Failed to read command");
  83. break;
  84. }
  85. success = true;
  86. } else if(furi_string_equal(temp_str, "raw")) {
  87. FURI_LOG_I(TAG, "IR File is RAW");
  88. signal->is_raw = true;
  89. if(!flipper_format_read_uint32(
  90. fff_data_file, "frequency", &signal->payload.raw.frequency, 1)) {
  91. // ACTION_SET_ERROR("IR: Failed to read frequency");
  92. break;
  93. }
  94. if(!flipper_format_read_float(
  95. fff_data_file, "duty_cycle", &signal->payload.raw.duty_cycle, 1)) {
  96. // ACTION_SET_ERROR("IR: Failed to read duty cycle");
  97. break;
  98. }
  99. if(!flipper_format_get_value_count(fff_data_file, "data", &temp_data32)) {
  100. // ACTION_SET_ERROR("IR: Failed to get size of data");
  101. break;
  102. }
  103. if(temp_data32 > MAX_TIMINGS_AMOUNT) {
  104. // ACTION_SET_ERROR("IR: Data size exceeds limit");
  105. break;
  106. }
  107. signal->payload.raw.timings_size = temp_data32;
  108. signal->payload.raw.timings =
  109. malloc(sizeof(uint32_t) * signal->payload.raw.timings_size);
  110. if(!flipper_format_read_uint32(
  111. fff_data_file, "data", signal->payload.raw.timings, temp_data32)) {
  112. // ACTION_SET_ERROR("IR: Failed to read data");
  113. free(signal->payload.raw.timings);
  114. break;
  115. }
  116. success = true;
  117. }
  118. } while(false);
  119. return success;
  120. }
  121. bool infrared_utils_write_signal(
  122. FlipperFormat* fff_data_file,
  123. InfraredSignal* signal,
  124. FuriString* name) {
  125. //
  126. bool success = false;
  127. do {
  128. if(!flipper_format_write_header_cstr(
  129. fff_data_file, INFRARED_FILE_TYPE, INFRARED_FILE_VERSION)) {
  130. FURI_LOG_E(TAG, "Error writing header");
  131. break;
  132. }
  133. if(!flipper_format_write_comment_cstr(fff_data_file, "")) {
  134. FURI_LOG_E(TAG, "Error writing blank comment");
  135. break;
  136. }
  137. if(!flipper_format_write_string(fff_data_file, "name", name)) {
  138. FURI_LOG_E(TAG, "Error writing name");
  139. break;
  140. }
  141. if(!flipper_format_write_string_cstr(
  142. fff_data_file, "type", signal->is_raw ? "raw" : "parsed")) {
  143. FURI_LOG_E(TAG, "Error writing type");
  144. break;
  145. }
  146. if(signal->is_raw) {
  147. // raw
  148. if(!flipper_format_write_uint32(
  149. fff_data_file, "frequency", &signal->payload.raw.frequency, 1)) {
  150. FURI_LOG_E(TAG, "Error writing frequency");
  151. break;
  152. }
  153. if(!flipper_format_write_float(
  154. fff_data_file, "duty_cycle", &signal->payload.raw.duty_cycle, 1)) {
  155. FURI_LOG_E(TAG, "Error writing duty_cycle");
  156. break;
  157. }
  158. if(!flipper_format_write_uint32(
  159. fff_data_file,
  160. "data",
  161. signal->payload.raw.timings,
  162. signal->payload.raw.timings_size)) {
  163. FURI_LOG_E(TAG, "Error writing data");
  164. break;
  165. }
  166. success = true;
  167. } else {
  168. // parsed
  169. if(!flipper_format_write_string_cstr(
  170. fff_data_file,
  171. "protocol",
  172. infrared_get_protocol_name(signal->payload.message.protocol))) {
  173. FURI_LOG_E(TAG, "Error writing protocol");
  174. break;
  175. }
  176. if(!flipper_format_write_hex(
  177. fff_data_file, "address", (uint8_t*)&signal->payload.message.address, 4)) {
  178. FURI_LOG_E(TAG, "Error writing address");
  179. break;
  180. }
  181. if(!flipper_format_write_hex(
  182. fff_data_file, "command", (uint8_t*)&signal->payload.message.command, 4)) {
  183. FURI_LOG_E(TAG, "Error writing command");
  184. break;
  185. }
  186. success = true;
  187. }
  188. } while(false);
  189. return success;
  190. }