subghz_protocol_came_atomo.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. #include "subghz_protocol_came_atomo.h"
  2. #include "subghz_protocol_common.h"
  3. #include <lib/toolbox/manchester-decoder.h>
  4. #define SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF
  5. struct SubGhzProtocolCameAtomo {
  6. SubGhzProtocolCommon common;
  7. ManchesterState manchester_saved_state;
  8. const char* rainbow_table_file_name;
  9. };
  10. typedef enum {
  11. CameAtomoDecoderStepReset = 0,
  12. CameAtomoDecoderStepDecoderData,
  13. } CameAtomoDecoderStep;
  14. SubGhzProtocolCameAtomo* subghz_protocol_came_atomo_alloc() {
  15. SubGhzProtocolCameAtomo* instance = furi_alloc(sizeof(SubGhzProtocolCameAtomo));
  16. instance->common.name = "CAME Atomo";
  17. instance->common.code_min_count_bit_for_found = 62;
  18. instance->common.te_short = 600;
  19. instance->common.te_long = 1200;
  20. instance->common.te_delta = 250;
  21. instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
  22. instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_atomo_to_str;
  23. // instance->common.to_save_string =
  24. // (SubGhzProtocolCommonGetStrSave)subghz_protocol_came_atomo_to_save_str;
  25. //instance->common.to_load_protocol_from_file =
  26. // (SubGhzProtocolCommonLoadFromFile)subghz_protocol_came_atomo_to_load_protocol_from_file;
  27. instance->common.to_load_protocol =
  28. (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_atomo_to_load_protocol;
  29. // instance->common.get_upload_protocol =
  30. // (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_came_atomo_send_key;
  31. return instance;
  32. }
  33. void subghz_protocol_came_atomo_free(SubGhzProtocolCameAtomo* instance) {
  34. furi_assert(instance);
  35. free(instance);
  36. }
  37. void subghz_protocol_came_atomo_name_file(SubGhzProtocolCameAtomo* instance, const char* name) {
  38. instance->rainbow_table_file_name = name;
  39. printf("Loading CAME Atomo rainbow table %s\r\n", name);
  40. }
  41. /** Read bytes from rainbow table
  42. *
  43. * @param instance - SubGhzProtocolCameAtomo* instance
  44. * @param number_atomo_magic_xor
  45. * @return atomo_magic_xor
  46. */
  47. uint64_t subghz_came_atomo_get_atomo_magic_xor_in_file(
  48. SubGhzProtocolCameAtomo* instance,
  49. uint8_t number_atomo_magic_xor) {
  50. if(!strcmp(instance->rainbow_table_file_name, "")) return SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
  51. uint8_t buffer[sizeof(uint64_t)] = {0};
  52. uint32_t address = number_atomo_magic_xor * sizeof(uint64_t);
  53. uint64_t atomo_magic_xor = 0;
  54. FileWorker* file_worker = file_worker_alloc(true);
  55. if(file_worker_open(
  56. file_worker, instance->rainbow_table_file_name, FSAM_READ, FSOM_OPEN_EXISTING)) {
  57. file_worker_seek(file_worker, address, true);
  58. file_worker_read(file_worker, &buffer, sizeof(uint64_t));
  59. for(size_t i = 0; i < sizeof(uint64_t); i++) {
  60. atomo_magic_xor = (atomo_magic_xor << 8) | buffer[i];
  61. }
  62. } else {
  63. atomo_magic_xor = SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
  64. }
  65. file_worker_close(file_worker);
  66. file_worker_free(file_worker);
  67. return atomo_magic_xor;
  68. }
  69. /** Analysis of received data
  70. *
  71. * @param instance SubGhzProtocolCameAtomo instance
  72. */
  73. void subghz_protocol_came_atomo_remote_controller(SubGhzProtocolCameAtomo* instance) {
  74. /*
  75. * 0x1fafef3ed0f7d9ef
  76. * 0x185fcc1531ee86e7
  77. * 0x184fa96912c567ff
  78. * 0x187f8a42f3dc38f7
  79. * 0x186f63915492a5cd
  80. * 0x181f40bab58bfac5
  81. * 0x180f25c696a01bdd
  82. * 0x183f06ed77b944d5
  83. * 0x182ef661d83d21a9
  84. * 0x18ded54a39247ea1
  85. * 0x18ceb0361a0f9fb9
  86. * 0x18fe931dfb16c0b1
  87. * 0x18ee7ace5c585d8b
  88. * ........
  89. * transmission consists of 99 parcels with increasing counter while holding down the button
  90. * with each new press, the counter in the encrypted part increases
  91. *
  92. * 0x1FAFF13ED0F7D9EF
  93. * 0x1FAFF11ED0F7D9EF
  94. * 0x1FAFF10ED0F7D9EF
  95. * 0x1FAFF0FED0F7D9EF
  96. * 0x1FAFF0EED0F7D9EF
  97. * 0x1FAFF0DED0F7D9EF
  98. * 0x1FAFF0CED0F7D9EF
  99. * 0x1FAFF0BED0F7D9EF
  100. * 0x1FAFF0AED0F7D9EF
  101. *
  102. * where 0x1FAF - parcel counter, 0хF0A - button press counter,
  103. * 0xED0F7D9E - serial number, 0хF - key
  104. * 0x1FAF parcel counter - 1 in the parcel queue ^ 0x185F = 0x07F0
  105. * 0x185f ^ 0x185F = 0x0000
  106. * 0x184f ^ 0x185F = 0x0010
  107. * 0x187f ^ 0x185F = 0x0020
  108. * .....
  109. * 0x182e ^ 0x185F = 0x0071
  110. * 0x18de ^ 0x185F = 0x0081
  111. * .....
  112. * 0x1e43 ^ 0x185F = 0x061C
  113. * where the last nibble is incremented every 8 samples
  114. *
  115. * Decode
  116. *
  117. * 0x1cf6931dfb16c0b1 => 0x1cf6
  118. * 0x1cf6 ^ 0x185F = 0x04A9
  119. * 0x04A9 => 0x04A = 74 (dec)
  120. * 74+1 % 32(atomo_magic_xor) = 11
  121. * GET atomo_magic_xor[11] = 0xXXXXXXXXXXXXXXXX
  122. * 0x931dfb16c0b1 ^ 0xXXXXXXXXXXXXXXXX = 0xEF3ED0F7D9EF
  123. * 0xEF3 ED0F7D9E F => 0xEF3 - CNT, 0xED0F7D9E - SN, 0xF - key
  124. *
  125. * */
  126. uint16_t parcel_counter = instance->common.code_last_found >> 48;
  127. parcel_counter = parcel_counter ^ 0x185F;
  128. parcel_counter >>= 4;
  129. uint8_t ind = (parcel_counter + 1) % 32;
  130. uint64_t temp_data = instance->common.code_last_found & 0x0000FFFFFFFFFFFF;
  131. uint64_t atomo_magic_xor = subghz_came_atomo_get_atomo_magic_xor_in_file(instance, ind);
  132. if(atomo_magic_xor != SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE) {
  133. temp_data = temp_data ^ atomo_magic_xor;
  134. instance->common.cnt = temp_data >> 36;
  135. instance->common.serial = (temp_data >> 4) & 0x000FFFFFFFF;
  136. instance->common.btn = temp_data & 0xF;
  137. } else {
  138. instance->common.cnt = 0;
  139. instance->common.serial = 0;
  140. instance->common.btn = 0;
  141. }
  142. }
  143. void subghz_protocol_came_atomo_reset(SubGhzProtocolCameAtomo* instance) {
  144. instance->common.parser_step = CameAtomoDecoderStepReset;
  145. manchester_advance(
  146. instance->manchester_saved_state,
  147. ManchesterEventReset,
  148. &instance->manchester_saved_state,
  149. NULL);
  150. }
  151. void subghz_protocol_came_atomo_parse(
  152. SubGhzProtocolCameAtomo* instance,
  153. bool level,
  154. uint32_t duration) {
  155. ManchesterEvent event = ManchesterEventReset;
  156. switch(instance->common.parser_step) {
  157. case CameAtomoDecoderStepReset:
  158. if((!level) && (DURATION_DIFF(duration, instance->common.te_long * 65) <
  159. instance->common.te_delta * 20)) {
  160. //Found header CAME
  161. instance->common.parser_step = CameAtomoDecoderStepDecoderData;
  162. instance->common.code_found = 0;
  163. instance->common.code_count_bit = 1;
  164. manchester_advance(
  165. instance->manchester_saved_state,
  166. ManchesterEventReset,
  167. &instance->manchester_saved_state,
  168. NULL);
  169. manchester_advance(
  170. instance->manchester_saved_state,
  171. ManchesterEventShortLow,
  172. &instance->manchester_saved_state,
  173. NULL);
  174. } else {
  175. instance->common.parser_step = CameAtomoDecoderStepReset;
  176. }
  177. break;
  178. case CameAtomoDecoderStepDecoderData:
  179. if(!level) {
  180. if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
  181. event = ManchesterEventShortLow;
  182. } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
  183. event = ManchesterEventLongLow;
  184. } else if(duration >= (instance->common.te_long * 2 + instance->common.te_delta)) {
  185. if(instance->common.code_count_bit ==
  186. instance->common.code_min_count_bit_for_found) {
  187. instance->common.code_last_found = instance->common.code_found;
  188. instance->common.code_last_count_bit = instance->common.code_count_bit;
  189. if(instance->common.callback)
  190. instance->common.callback(
  191. (SubGhzProtocolCommon*)instance, instance->common.context);
  192. }
  193. instance->common.code_found = 0;
  194. instance->common.code_count_bit = 1;
  195. manchester_advance(
  196. instance->manchester_saved_state,
  197. ManchesterEventReset,
  198. &instance->manchester_saved_state,
  199. NULL);
  200. manchester_advance(
  201. instance->manchester_saved_state,
  202. ManchesterEventShortLow,
  203. &instance->manchester_saved_state,
  204. NULL);
  205. } else {
  206. instance->common.parser_step = CameAtomoDecoderStepReset;
  207. }
  208. } else {
  209. if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
  210. event = ManchesterEventShortHigh;
  211. } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
  212. event = ManchesterEventLongHigh;
  213. } else {
  214. instance->common.parser_step = CameAtomoDecoderStepReset;
  215. }
  216. }
  217. if(event != ManchesterEventReset) {
  218. bool data;
  219. bool data_ok = manchester_advance(
  220. instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
  221. if(data_ok) {
  222. instance->common.code_found = (instance->common.code_found << 1) | !data;
  223. instance->common.code_count_bit++;
  224. }
  225. }
  226. break;
  227. }
  228. }
  229. void subghz_protocol_came_atomo_to_str(SubGhzProtocolCameAtomo* instance, string_t output) {
  230. subghz_protocol_came_atomo_remote_controller(instance);
  231. uint32_t code_found_hi = instance->common.code_last_found >> 32;
  232. uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
  233. string_cat_printf(
  234. output,
  235. "%s %db\r\n"
  236. "Key:0x%lX%08lX\r\n"
  237. "Sn:0x%08lX Btn:0x%01X\r\n"
  238. "Cnt:0x%03X\r\n",
  239. instance->common.name,
  240. instance->common.code_last_count_bit,
  241. code_found_hi,
  242. code_found_lo,
  243. instance->common.serial,
  244. instance->common.btn,
  245. instance->common.cnt);
  246. }
  247. // void subghz_protocol_came_atomo_to_save_str(SubGhzProtocolCameAtomo* instance, string_t output) {
  248. // string_printf(
  249. // output,
  250. // "Protocol: %s\n"
  251. // "Bit: %d\n"
  252. // "Key: %08lX%08lX\r\n",
  253. // instance->common.name,
  254. // instance->common.code_last_count_bit,
  255. // (uint32_t)(instance->common.code_last_found >> 32),
  256. // (uint32_t)(instance->common.code_last_found & 0xFFFFFFFF));
  257. // }
  258. // bool subghz_protocol_came_atomo_to_load_protocol_from_file(
  259. // FileWorker* file_worker,
  260. // SubGhzProtocolCameAtomo* instance,
  261. // const char* file_path) {
  262. // bool loaded = false;
  263. // string_t temp_str;
  264. // string_init(temp_str);
  265. // int res = 0;
  266. // int data = 0;
  267. // do {
  268. // // Read and parse bit data from 2nd line
  269. // if(!file_worker_read_until(file_worker, temp_str, '\n')) {
  270. // break;
  271. // }
  272. // res = sscanf(string_get_cstr(temp_str), "Bit: %d\n", &data);
  273. // if(res != 1) {
  274. // break;
  275. // }
  276. // instance->common.code_last_count_bit = (uint8_t)data;
  277. // // Read and parse key data from 3nd line
  278. // if(!file_worker_read_until(file_worker, temp_str, '\n')) {
  279. // break;
  280. // }
  281. // // strlen("Key: ") = 5
  282. // string_right(temp_str, 5);
  283. // uint8_t buf_key[8] = {0};
  284. // if(!subghz_protocol_common_read_hex(temp_str, buf_key, 8)) {
  285. // break;
  286. // }
  287. // for(uint8_t i = 0; i < 8; i++) {
  288. // instance->common.code_last_found = instance->common.code_last_found << 8 | buf_key[i];
  289. // }
  290. // loaded = true;
  291. // } while(0);
  292. // string_clear(temp_str);
  293. // subghz_protocol_came_atomo_remote_controller(instance);
  294. // return loaded;
  295. // }
  296. void subghz_decoder_came_atomo_to_load_protocol(SubGhzProtocolCameAtomo* instance, void* context) {
  297. furi_assert(context);
  298. furi_assert(instance);
  299. SubGhzProtocolCommonLoad* data = context;
  300. instance->common.code_last_found = data->code_found;
  301. instance->common.code_last_count_bit = data->code_count_bit;
  302. subghz_protocol_came_atomo_remote_controller(instance);
  303. }