action_subghz.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. // Methods for Sub-GHz transmission
  2. #include <flipper_format/flipper_format_i.h>
  3. #include <path.h>
  4. #include <string.h>
  5. #include "helpers/subghz_txrx.h"
  6. #include "action_i.h"
  7. #include "quac.h"
  8. #define SUBGHZ_DIR_PATH EXT_PATH("subghz/")
  9. typedef struct SubGhzNeedSaveContext {
  10. App* app;
  11. SubGhzTxRx* txrx;
  12. FuriString* file_path;
  13. } SubGhzNeedSaveContext;
  14. void action_subghz_need_save_callback(void* context) {
  15. FURI_LOG_I(TAG, "Saving udpated subghz signal");
  16. SubGhzNeedSaveContext* savectx = (SubGhzNeedSaveContext*)context;
  17. FlipperFormat* ff = subghz_txrx_get_fff_data(savectx->txrx);
  18. Stream* ff_stream = flipper_format_get_raw_stream(ff);
  19. flipper_format_delete_key(ff, "Repeat");
  20. flipper_format_delete_key(ff, "Manufacture");
  21. do {
  22. if(!storage_simply_remove(
  23. savectx->app->storage, furi_string_get_cstr(savectx->file_path))) {
  24. FURI_LOG_E(TAG, "Failed to delete subghz file before re-save");
  25. break;
  26. }
  27. stream_seek(ff_stream, 0, StreamOffsetFromStart);
  28. stream_save_to_file(
  29. ff_stream,
  30. savectx->app->storage,
  31. furi_string_get_cstr(savectx->file_path),
  32. FSOM_CREATE_ALWAYS);
  33. if(storage_common_stat(
  34. savectx->app->storage, furi_string_get_cstr(savectx->file_path), NULL) != FSE_OK) {
  35. FURI_LOG_E(TAG, "Error verifying new subghz file after re-save");
  36. break;
  37. }
  38. } while(0);
  39. // Update original .sub file.
  40. //In case when rolling code was used in Quac we must update original .sub file with actual rolling code counter
  41. // Take file name from quac_app path
  42. FuriString* quac_filename = furi_string_alloc();
  43. furi_string_reset(quac_filename);
  44. path_extract_filename(savectx->file_path, quac_filename, false);
  45. FURI_LOG_I(TAG, "Extracted quac filename: %s", furi_string_get_cstr(quac_filename));
  46. //create new char string with full path (dir+filename) to original subghz folder
  47. char* full_subghz_file_name =
  48. malloc(1 + strlen(SUBGHZ_DIR_PATH) + strlen(furi_string_get_cstr(quac_filename)));
  49. strcpy(full_subghz_file_name, SUBGHZ_DIR_PATH);
  50. strcat(full_subghz_file_name, furi_string_get_cstr(quac_filename));
  51. FURI_LOG_I(TAG, "Full path to safe file: %s", full_subghz_file_name);
  52. //Save subghz file to original subghz location
  53. do {
  54. if(!storage_simply_remove(savectx->app->storage, full_subghz_file_name)) {
  55. FURI_LOG_E(
  56. TAG, "Failed to delete subghz file before re-save in original SUBGHZ location");
  57. break;
  58. }
  59. stream_seek(ff_stream, 0, StreamOffsetFromStart);
  60. stream_save_to_file(
  61. ff_stream, savectx->app->storage, full_subghz_file_name, FSOM_CREATE_ALWAYS);
  62. if(storage_common_stat(savectx->app->storage, full_subghz_file_name, NULL) != FSE_OK) {
  63. FURI_LOG_E(
  64. TAG, "Error verifying new subghz file after re-save in original SUBGHZ location");
  65. break;
  66. }
  67. } while(0);
  68. free(full_subghz_file_name);
  69. furi_string_free(quac_filename);
  70. }
  71. void action_subghz_tx(void* context, FuriString* action_path, FuriString* error) {
  72. App* app = context;
  73. const char* file_name = furi_string_get_cstr(action_path);
  74. FlipperFormat* fff_data_file = flipper_format_file_alloc(app->storage);
  75. SubGhzTxRx* txrx = subghz_txrx_alloc();
  76. SubGhzNeedSaveContext save_context = {app, txrx, action_path};
  77. subghz_txrx_set_need_save_callback(txrx, action_subghz_need_save_callback, &save_context);
  78. Stream* fff_data_stream = flipper_format_get_raw_stream(subghz_txrx_get_fff_data(txrx));
  79. stream_clean(fff_data_stream);
  80. FuriString* preset_name = furi_string_alloc();
  81. FuriString* protocol_name = furi_string_alloc();
  82. FuriString* temp_str;
  83. temp_str = furi_string_alloc();
  84. uint32_t temp_data32;
  85. uint32_t frequency = 0;
  86. FURI_LOG_I(TAG, "SUBGHZ: Action starting...");
  87. do {
  88. if(!flipper_format_file_open_existing(fff_data_file, file_name)) {
  89. FURI_LOG_E(TAG, "Error opening %s", file_name);
  90. ACTION_SET_ERROR("SUBGHZ: Error opening %s", file_name);
  91. break;
  92. }
  93. if(!flipper_format_read_header(fff_data_file, temp_str, &temp_data32)) {
  94. FURI_LOG_E(TAG, "Missing or incorrect header");
  95. ACTION_SET_ERROR("SUBGHZ: Missing or incorrect header");
  96. break;
  97. }
  98. if(((!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_KEY_FILE_TYPE)) ||
  99. (!strcmp(furi_string_get_cstr(temp_str), SUBGHZ_RAW_FILE_TYPE))) &&
  100. temp_data32 == SUBGHZ_KEY_FILE_VERSION) {
  101. } else {
  102. FURI_LOG_E(TAG, "Type or version mismatch");
  103. ACTION_SET_ERROR("SUBGHZ: Type or version mismatch");
  104. break;
  105. }
  106. SubGhzSetting* setting = subghz_txrx_get_setting(txrx);
  107. if(!flipper_format_read_uint32(fff_data_file, "Frequency", &frequency, 1)) {
  108. FURI_LOG_W(TAG, "Missing Frequency. Setting default frequency");
  109. frequency = subghz_setting_get_default_frequency(setting);
  110. } else if(!subghz_txrx_radio_device_is_frequecy_valid(txrx, frequency)) {
  111. FURI_LOG_E(TAG, "Frequency not supported on the chosen radio module");
  112. ACTION_SET_ERROR("SUBGHZ: Frequency not supported");
  113. break;
  114. }
  115. if(!flipper_format_read_string(fff_data_file, "Preset", temp_str)) {
  116. FURI_LOG_E(TAG, "Missing Preset");
  117. ACTION_SET_ERROR("SUBGHZ: Missing preset");
  118. break;
  119. }
  120. furi_string_set_str(
  121. temp_str, subghz_txrx_get_preset_name(txrx, furi_string_get_cstr(temp_str)));
  122. if(!strcmp(furi_string_get_cstr(temp_str), "")) {
  123. FURI_LOG_E(TAG, "Unknown preset");
  124. ACTION_SET_ERROR("SUBGHZ: Unknown preset");
  125. break;
  126. }
  127. if(!strcmp(furi_string_get_cstr(temp_str), "CUSTOM")) {
  128. subghz_setting_delete_custom_preset(setting, furi_string_get_cstr(temp_str));
  129. if(!subghz_setting_load_custom_preset(
  130. setting, furi_string_get_cstr(temp_str), fff_data_file)) {
  131. FURI_LOG_E(TAG, "Missing Custom preset");
  132. ACTION_SET_ERROR("SUBGHZ: Missing Custom preset");
  133. break;
  134. }
  135. }
  136. furi_string_set(preset_name, temp_str);
  137. size_t preset_index =
  138. subghz_setting_get_inx_preset_by_name(setting, furi_string_get_cstr(preset_name));
  139. subghz_txrx_set_preset(
  140. txrx,
  141. furi_string_get_cstr(preset_name),
  142. frequency,
  143. subghz_setting_get_preset_data(setting, preset_index),
  144. subghz_setting_get_preset_data_size(setting, preset_index));
  145. // Load Protocol
  146. if(!flipper_format_read_string(fff_data_file, "Protocol", protocol_name)) {
  147. FURI_LOG_E(TAG, "Missing protocol");
  148. ACTION_SET_ERROR("SUBGHZ: Missing protocol");
  149. break;
  150. }
  151. FlipperFormat* fff_data = subghz_txrx_get_fff_data(txrx);
  152. if(!strcmp(furi_string_get_cstr(protocol_name), "RAW")) {
  153. subghz_protocol_raw_gen_fff_data(
  154. fff_data, file_name, subghz_txrx_radio_device_get_name(txrx));
  155. } else {
  156. stream_copy_full(
  157. flipper_format_get_raw_stream(fff_data_file),
  158. flipper_format_get_raw_stream(fff_data));
  159. }
  160. if(subghz_txrx_load_decoder_by_name_protocol(txrx, furi_string_get_cstr(protocol_name))) {
  161. SubGhzProtocolStatus status =
  162. subghz_protocol_decoder_base_deserialize(subghz_txrx_get_decoder(txrx), fff_data);
  163. if(status != SubGhzProtocolStatusOk) {
  164. break;
  165. }
  166. } else {
  167. FURI_LOG_E(TAG, "Protocol not found: %s", furi_string_get_cstr(protocol_name));
  168. break;
  169. }
  170. } while(false);
  171. flipper_format_file_close(fff_data_file);
  172. flipper_format_free(fff_data_file);
  173. if(subghz_txrx_tx_start(txrx, subghz_txrx_get_fff_data(txrx)) != SubGhzTxRxStartTxStateOk) {
  174. FURI_LOG_E(TAG, "Failed to start TX");
  175. }
  176. // TODO: Should this be based on a Setting?
  177. furi_delay_ms(100);
  178. FURI_LOG_I(TAG, "SUBGHZ: Action complete.");
  179. // This will call need_save_callback, if necessary
  180. subghz_txrx_stop(txrx);
  181. subghz_txrx_free(txrx);
  182. furi_string_free(preset_name);
  183. furi_string_free(protocol_name);
  184. furi_string_free(temp_str);
  185. }