action_ir_utils.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. signal->is_raw = false;
  64. if(!flipper_format_read_string(fff_data_file, "protocol", temp_str)) {
  65. // ACTION_SET_ERROR("IR: Invalid or missing protocol");
  66. break;
  67. }
  68. signal->payload.message.protocol =
  69. infrared_get_protocol_by_name(furi_string_get_cstr(temp_str));
  70. if(!infrared_is_protocol_valid(signal->payload.message.protocol)) {
  71. // ACTION_SET_ERROR("IR: Invalid or unknown protocol");
  72. break;
  73. }
  74. if(!flipper_format_read_hex(
  75. fff_data_file, "address", (uint8_t*)&signal->payload.message.address, 4)) {
  76. // ACTION_SET_ERROR("IR: Failed to read address");
  77. break;
  78. }
  79. if(!flipper_format_read_hex(
  80. fff_data_file, "command", (uint8_t*)&signal->payload.message.command, 4)) {
  81. // ACTION_SET_ERROR("IR: Failed to read command");
  82. break;
  83. }
  84. success = true;
  85. } else if(furi_string_equal(temp_str, "raw")) {
  86. signal->is_raw = true;
  87. if(!flipper_format_read_uint32(
  88. fff_data_file, "frequency", &signal->payload.raw.frequency, 1)) {
  89. // ACTION_SET_ERROR("IR: Failed to read frequency");
  90. break;
  91. }
  92. if(!flipper_format_read_float(
  93. fff_data_file, "duty_cycle", &signal->payload.raw.duty_cycle, 1)) {
  94. // ACTION_SET_ERROR("IR: Failed to read duty cycle");
  95. break;
  96. }
  97. if(!flipper_format_get_value_count(fff_data_file, "data", &temp_data32)) {
  98. // ACTION_SET_ERROR("IR: Failed to get size of data");
  99. break;
  100. }
  101. if(temp_data32 > MAX_TIMINGS_AMOUNT) {
  102. // ACTION_SET_ERROR("IR: Data size exceeds limit");
  103. break;
  104. }
  105. signal->payload.raw.timings_size = temp_data32;
  106. signal->payload.raw.timings =
  107. malloc(sizeof(uint32_t) * signal->payload.raw.timings_size);
  108. if(!flipper_format_read_uint32(
  109. fff_data_file, "data", signal->payload.raw.timings, temp_data32)) {
  110. // ACTION_SET_ERROR("IR: Failed to read data");
  111. free(signal->payload.raw.timings);
  112. break;
  113. }
  114. success = true;
  115. }
  116. } while(false);
  117. return success;
  118. }
  119. bool infrared_utils_write_signal(
  120. FlipperFormat* fff_data_file,
  121. InfraredSignal* signal,
  122. FuriString* name) {
  123. //
  124. bool success = false;
  125. do {
  126. if(!flipper_format_write_header_cstr(
  127. fff_data_file, INFRARED_FILE_TYPE, INFRARED_FILE_VERSION)) {
  128. FURI_LOG_E(TAG, "Error writing header");
  129. break;
  130. }
  131. if(!flipper_format_write_comment_cstr(fff_data_file, "")) {
  132. FURI_LOG_E(TAG, "Error writing blank comment");
  133. break;
  134. }
  135. if(!flipper_format_write_string(fff_data_file, "name", name)) {
  136. FURI_LOG_E(TAG, "Error writing name");
  137. break;
  138. }
  139. if(!flipper_format_write_string_cstr(
  140. fff_data_file, "type", signal->is_raw ? "raw" : "parsed")) {
  141. FURI_LOG_E(TAG, "Error writing type");
  142. break;
  143. }
  144. if(signal->is_raw) {
  145. // raw
  146. if(!flipper_format_write_uint32(
  147. fff_data_file, "frequency", &signal->payload.raw.frequency, 1)) {
  148. FURI_LOG_E(TAG, "Error writing frequency");
  149. break;
  150. }
  151. if(!flipper_format_write_float(
  152. fff_data_file, "duty_cycle", &signal->payload.raw.duty_cycle, 1)) {
  153. FURI_LOG_E(TAG, "Error writing duty_cycle");
  154. break;
  155. }
  156. if(!flipper_format_write_uint32(
  157. fff_data_file,
  158. "data",
  159. signal->payload.raw.timings,
  160. signal->payload.raw.timings_size)) {
  161. FURI_LOG_E(TAG, "Error writing data");
  162. break;
  163. }
  164. success = true;
  165. } else {
  166. // parsed
  167. if(!flipper_format_write_string_cstr(
  168. fff_data_file,
  169. "protocol",
  170. infrared_get_protocol_name(signal->payload.message.protocol))) {
  171. FURI_LOG_E(TAG, "Error writing protocol");
  172. break;
  173. }
  174. if(!flipper_format_write_hex(
  175. fff_data_file, "address", (uint8_t*)&signal->payload.message.address, 4)) {
  176. FURI_LOG_E(TAG, "Error writing address");
  177. break;
  178. }
  179. if(!flipper_format_write_hex(
  180. fff_data_file, "command", (uint8_t*)&signal->payload.message.command, 4)) {
  181. FURI_LOG_E(TAG, "Error writing command");
  182. break;
  183. }
  184. success = true;
  185. }
  186. } while(false);
  187. return success;
  188. }