came_atomo.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #include "came_atomo.h"
  2. #include <lib/toolbox/manchester_decoder.h>
  3. #include "../blocks/const.h"
  4. #include "../blocks/decoder.h"
  5. #include "../blocks/encoder.h"
  6. #include "../blocks/generic.h"
  7. #include "../blocks/math.h"
  8. #define TAG "SubGhzProtocoCameAtomo"
  9. #define SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE 0xFFFFFFFFFFFFFFFF
  10. static const SubGhzBlockConst subghz_protocol_came_atomo_const = {
  11. .te_short = 600,
  12. .te_long = 1200,
  13. .te_delta = 250,
  14. .min_count_bit_for_found = 62,
  15. };
  16. struct SubGhzProtocolDecoderCameAtomo {
  17. SubGhzProtocolDecoderBase base;
  18. SubGhzBlockDecoder decoder;
  19. SubGhzBlockGeneric generic;
  20. ManchesterState manchester_saved_state;
  21. const char* came_atomo_rainbow_table_file_name;
  22. };
  23. struct SubGhzProtocolEncoderCameAtomo {
  24. SubGhzProtocolEncoderBase base;
  25. SubGhzProtocolBlockEncoder encoder;
  26. SubGhzBlockGeneric generic;
  27. };
  28. typedef enum {
  29. CameAtomoDecoderStepReset = 0,
  30. CameAtomoDecoderStepDecoderData,
  31. } CameAtomoDecoderStep;
  32. const SubGhzProtocolDecoder subghz_protocol_came_atomo_decoder = {
  33. .alloc = subghz_protocol_decoder_came_atomo_alloc,
  34. .free = subghz_protocol_decoder_came_atomo_free,
  35. .feed = subghz_protocol_decoder_came_atomo_feed,
  36. .reset = subghz_protocol_decoder_came_atomo_reset,
  37. .get_hash_data = subghz_protocol_decoder_came_atomo_get_hash_data,
  38. .serialize = subghz_protocol_decoder_came_atomo_serialize,
  39. .deserialize = subghz_protocol_decoder_came_atomo_deserialize,
  40. .get_string = subghz_protocol_decoder_came_atomo_get_string,
  41. };
  42. const SubGhzProtocolEncoder subghz_protocol_came_atomo_encoder = {
  43. .alloc = NULL,
  44. .free = NULL,
  45. .deserialize = NULL,
  46. .stop = NULL,
  47. .yield = NULL,
  48. };
  49. const SubGhzProtocol subghz_protocol_came_atomo = {
  50. .name = SUBGHZ_PROTOCOL_CAME_ATOMO_NAME,
  51. .type = SubGhzProtocolTypeDynamic,
  52. .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
  53. .decoder = &subghz_protocol_came_atomo_decoder,
  54. .encoder = &subghz_protocol_came_atomo_encoder,
  55. };
  56. void* subghz_protocol_decoder_came_atomo_alloc(SubGhzEnvironment* environment) {
  57. SubGhzProtocolDecoderCameAtomo* instance = malloc(sizeof(SubGhzProtocolDecoderCameAtomo));
  58. instance->base.protocol = &subghz_protocol_came_atomo;
  59. instance->generic.protocol_name = instance->base.protocol->name;
  60. instance->came_atomo_rainbow_table_file_name =
  61. subghz_environment_get_came_atomo_rainbow_table_file_name(environment);
  62. if(instance->came_atomo_rainbow_table_file_name) {
  63. FURI_LOG_I(
  64. TAG, "Loading rainbow table from %s", instance->came_atomo_rainbow_table_file_name);
  65. }
  66. return instance;
  67. }
  68. void subghz_protocol_decoder_came_atomo_free(void* context) {
  69. furi_assert(context);
  70. SubGhzProtocolDecoderCameAtomo* instance = context;
  71. instance->came_atomo_rainbow_table_file_name = NULL;
  72. free(instance);
  73. }
  74. void subghz_protocol_decoder_came_atomo_reset(void* context) {
  75. furi_assert(context);
  76. SubGhzProtocolDecoderCameAtomo* instance = context;
  77. instance->decoder.parser_step = CameAtomoDecoderStepReset;
  78. manchester_advance(
  79. instance->manchester_saved_state,
  80. ManchesterEventReset,
  81. &instance->manchester_saved_state,
  82. NULL);
  83. }
  84. void subghz_protocol_decoder_came_atomo_feed(void* context, bool level, uint32_t duration) {
  85. furi_assert(context);
  86. SubGhzProtocolDecoderCameAtomo* instance = context;
  87. ManchesterEvent event = ManchesterEventReset;
  88. switch(instance->decoder.parser_step) {
  89. case CameAtomoDecoderStepReset:
  90. if((!level) && (DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long * 60) <
  91. subghz_protocol_came_atomo_const.te_delta * 40)) {
  92. //Found header CAME
  93. instance->decoder.parser_step = CameAtomoDecoderStepDecoderData;
  94. instance->decoder.decode_data = 0;
  95. instance->decoder.decode_count_bit = 1;
  96. manchester_advance(
  97. instance->manchester_saved_state,
  98. ManchesterEventReset,
  99. &instance->manchester_saved_state,
  100. NULL);
  101. manchester_advance(
  102. instance->manchester_saved_state,
  103. ManchesterEventShortLow,
  104. &instance->manchester_saved_state,
  105. NULL);
  106. }
  107. break;
  108. case CameAtomoDecoderStepDecoderData:
  109. if(!level) {
  110. if(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_short) <
  111. subghz_protocol_came_atomo_const.te_delta) {
  112. event = ManchesterEventShortLow;
  113. } else if(
  114. DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long) <
  115. subghz_protocol_came_atomo_const.te_delta) {
  116. event = ManchesterEventLongLow;
  117. } else if(
  118. duration >= ((uint32_t)subghz_protocol_came_atomo_const.te_long * 2 +
  119. subghz_protocol_came_atomo_const.te_delta)) {
  120. if(instance->decoder.decode_count_bit ==
  121. subghz_protocol_came_atomo_const.min_count_bit_for_found) {
  122. instance->generic.data = instance->decoder.decode_data;
  123. instance->generic.data_count_bit = instance->decoder.decode_count_bit;
  124. if(instance->base.callback)
  125. instance->base.callback(&instance->base, instance->base.context);
  126. }
  127. instance->decoder.decode_data = 0;
  128. instance->decoder.decode_count_bit = 1;
  129. manchester_advance(
  130. instance->manchester_saved_state,
  131. ManchesterEventReset,
  132. &instance->manchester_saved_state,
  133. NULL);
  134. manchester_advance(
  135. instance->manchester_saved_state,
  136. ManchesterEventShortLow,
  137. &instance->manchester_saved_state,
  138. NULL);
  139. } else {
  140. instance->decoder.parser_step = CameAtomoDecoderStepReset;
  141. }
  142. } else {
  143. if(DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_short) <
  144. subghz_protocol_came_atomo_const.te_delta) {
  145. event = ManchesterEventShortHigh;
  146. } else if(
  147. DURATION_DIFF(duration, subghz_protocol_came_atomo_const.te_long) <
  148. subghz_protocol_came_atomo_const.te_delta) {
  149. event = ManchesterEventLongHigh;
  150. } else {
  151. instance->decoder.parser_step = CameAtomoDecoderStepReset;
  152. }
  153. }
  154. if(event != ManchesterEventReset) {
  155. bool data;
  156. bool data_ok = manchester_advance(
  157. instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
  158. if(data_ok) {
  159. instance->decoder.decode_data = (instance->decoder.decode_data << 1) | !data;
  160. instance->decoder.decode_count_bit++;
  161. }
  162. }
  163. break;
  164. }
  165. }
  166. /**
  167. * Read bytes from rainbow table
  168. * @param file_name Full path to rainbow table the file
  169. * @param number_atomo_magic_xor Сell number in the array
  170. * @return atomo_magic_xor
  171. */
  172. static uint64_t subghz_protocol_came_atomo_get_magic_xor_in_file(
  173. const char* file_name,
  174. uint8_t number_atomo_magic_xor) {
  175. if(!strcmp(file_name, "")) return SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
  176. uint8_t buffer[sizeof(uint64_t)] = {0};
  177. uint32_t address = number_atomo_magic_xor * sizeof(uint64_t);
  178. uint64_t atomo_magic_xor = 0;
  179. if(subghz_keystore_raw_get_data(file_name, address, buffer, sizeof(uint64_t))) {
  180. for(size_t i = 0; i < sizeof(uint64_t); i++) {
  181. atomo_magic_xor = (atomo_magic_xor << 8) | buffer[i];
  182. }
  183. } else {
  184. atomo_magic_xor = SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE;
  185. }
  186. return atomo_magic_xor;
  187. }
  188. /**
  189. * Analysis of received data
  190. * @param instance Pointer to a SubGhzBlockGeneric* instance
  191. * @param file_name Full path to rainbow table the file
  192. */
  193. static void subghz_protocol_came_atomo_remote_controller(
  194. SubGhzBlockGeneric* instance,
  195. const char* file_name) {
  196. /*
  197. * 0x1fafef3ed0f7d9ef
  198. * 0x185fcc1531ee86e7
  199. * 0x184fa96912c567ff
  200. * 0x187f8a42f3dc38f7
  201. * 0x186f63915492a5cd
  202. * 0x181f40bab58bfac5
  203. * 0x180f25c696a01bdd
  204. * 0x183f06ed77b944d5
  205. * 0x182ef661d83d21a9
  206. * 0x18ded54a39247ea1
  207. * 0x18ceb0361a0f9fb9
  208. * 0x18fe931dfb16c0b1
  209. * 0x18ee7ace5c585d8b
  210. * ........
  211. * transmission consists of 99 parcels with increasing counter while holding down the button
  212. * with each new press, the counter in the encrypted part increases
  213. *
  214. * 0x1FAFF13ED0F7D9EF
  215. * 0x1FAFF11ED0F7D9EF
  216. * 0x1FAFF10ED0F7D9EF
  217. * 0x1FAFF0FED0F7D9EF
  218. * 0x1FAFF0EED0F7D9EF
  219. * 0x1FAFF0DED0F7D9EF
  220. * 0x1FAFF0CED0F7D9EF
  221. * 0x1FAFF0BED0F7D9EF
  222. * 0x1FAFF0AED0F7D9EF
  223. *
  224. * where 0x1FAF - parcel counter, 0хF0A - button press counter,
  225. * 0xED0F7D9E - serial number, 0хF - key
  226. * 0x1FAF parcel counter - 1 in the parcel queue ^ 0x185F = 0x07F0
  227. * 0x185f ^ 0x185F = 0x0000
  228. * 0x184f ^ 0x185F = 0x0010
  229. * 0x187f ^ 0x185F = 0x0020
  230. * .....
  231. * 0x182e ^ 0x185F = 0x0071
  232. * 0x18de ^ 0x185F = 0x0081
  233. * .....
  234. * 0x1e43 ^ 0x185F = 0x061C
  235. * where the last nibble is incremented every 8 samples
  236. *
  237. * Decode
  238. *
  239. * 0x1cf6931dfb16c0b1 => 0x1cf6
  240. * 0x1cf6 ^ 0x185F = 0x04A9
  241. * 0x04A9 => 0x04A = 74 (dec)
  242. * 74+1 % 32(atomo_magic_xor) = 11
  243. * GET atomo_magic_xor[11] = 0xXXXXXXXXXXXXXXXX
  244. * 0x931dfb16c0b1 ^ 0xXXXXXXXXXXXXXXXX = 0xEF3ED0F7D9EF
  245. * 0xEF3 ED0F7D9E F => 0xEF3 - CNT, 0xED0F7D9E - SN, 0xF - key
  246. *
  247. * */
  248. uint16_t parcel_counter = instance->data >> 48;
  249. parcel_counter = parcel_counter ^ 0x185F;
  250. parcel_counter >>= 4;
  251. uint8_t ind = (parcel_counter + 1) % 32;
  252. uint64_t temp_data = instance->data & 0x0000FFFFFFFFFFFF;
  253. uint64_t atomo_magic_xor = subghz_protocol_came_atomo_get_magic_xor_in_file(file_name, ind);
  254. if(atomo_magic_xor != SUBGHZ_NO_CAME_ATOMO_RAINBOW_TABLE) {
  255. temp_data = temp_data ^ atomo_magic_xor;
  256. instance->cnt = temp_data >> 36;
  257. instance->serial = (temp_data >> 4) & 0x000FFFFFFFF;
  258. instance->btn = temp_data & 0xF;
  259. } else {
  260. instance->cnt = 0;
  261. instance->serial = 0;
  262. instance->btn = 0;
  263. }
  264. }
  265. uint8_t subghz_protocol_decoder_came_atomo_get_hash_data(void* context) {
  266. furi_assert(context);
  267. SubGhzProtocolDecoderCameAtomo* instance = context;
  268. return subghz_protocol_blocks_get_hash_data(
  269. &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
  270. }
  271. bool subghz_protocol_decoder_came_atomo_serialize(
  272. void* context,
  273. FlipperFormat* flipper_format,
  274. SubGhzRadioPreset* preset) {
  275. furi_assert(context);
  276. SubGhzProtocolDecoderCameAtomo* instance = context;
  277. return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
  278. }
  279. bool subghz_protocol_decoder_came_atomo_deserialize(void* context, FlipperFormat* flipper_format) {
  280. furi_assert(context);
  281. SubGhzProtocolDecoderCameAtomo* instance = context;
  282. bool ret = false;
  283. do {
  284. if(!subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
  285. break;
  286. }
  287. if(instance->generic.data_count_bit !=
  288. subghz_protocol_came_atomo_const.min_count_bit_for_found) {
  289. FURI_LOG_E(TAG, "Wrong number of bits in key");
  290. break;
  291. }
  292. ret = true;
  293. } while(false);
  294. return ret;
  295. }
  296. void subghz_protocol_decoder_came_atomo_get_string(void* context, FuriString* output) {
  297. furi_assert(context);
  298. SubGhzProtocolDecoderCameAtomo* instance = context;
  299. subghz_protocol_came_atomo_remote_controller(
  300. &instance->generic, instance->came_atomo_rainbow_table_file_name);
  301. uint32_t code_found_hi = instance->generic.data >> 32;
  302. uint32_t code_found_lo = instance->generic.data & 0x00000000ffffffff;
  303. furi_string_cat_printf(
  304. output,
  305. "%s %db\r\n"
  306. "Key:0x%lX%08lX\r\n"
  307. "Sn:0x%08lX Btn:0x%01X\r\n"
  308. "Cnt:0x%03lX\r\n",
  309. instance->generic.protocol_name,
  310. instance->generic.data_count_bit,
  311. code_found_hi,
  312. code_found_lo,
  313. instance->generic.serial,
  314. instance->generic.btn,
  315. instance->generic.cnt);
  316. }