subghz_protocol_came_twee.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. #include "subghz_protocol_came_twee.h"
  2. #include "subghz_protocol_common.h"
  3. #include <lib/toolbox/manchester-decoder.h>
  4. #include <lib/toolbox/manchester-encoder.h>
  5. /*
  6. * Help
  7. * https://phreakerclub.com/forum/showthread.php?t=635&highlight=came+twin
  8. *
  9. */
  10. #define DIP_PATTERN "%c%c%c%c%c%c%c%c%c%c"
  11. #define CNT_TO_DIP(dip) \
  12. (dip & 0x0200 ? '1' : '0'), (dip & 0x0100 ? '1' : '0'), (dip & 0x0080 ? '1' : '0'), \
  13. (dip & 0x0040 ? '1' : '0'), (dip & 0x0020 ? '1' : '0'), (dip & 0x0010 ? '1' : '0'), \
  14. (dip & 0x0008 ? '1' : '0'), (dip & 0x0004 ? '1' : '0'), (dip & 0x0002 ? '1' : '0'), \
  15. (dip & 0x0001 ? '1' : '0')
  16. struct SubGhzProtocolCameTwee {
  17. SubGhzProtocolCommon common;
  18. ManchesterState manchester_saved_state;
  19. };
  20. typedef enum {
  21. CameTweeDecoderStepReset = 0,
  22. CameTweeDecoderStepDecoderData,
  23. } CameTweeDecoderStep;
  24. SubGhzProtocolCameTwee* subghz_protocol_came_twee_alloc() {
  25. SubGhzProtocolCameTwee* instance = furi_alloc(sizeof(SubGhzProtocolCameTwee));
  26. instance->common.name = "CAME TWEE";
  27. instance->common.code_min_count_bit_for_found = 54;
  28. instance->common.te_short = 500;
  29. instance->common.te_long = 1000;
  30. instance->common.te_delta = 250;
  31. instance->common.type_protocol = SubGhzProtocolCommonTypeStatic;
  32. instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_came_twee_to_str;
  33. instance->common.to_save_file =
  34. (SubGhzProtocolCommonSaveFile)subghz_protocol_came_twee_to_save_file;
  35. instance->common.to_load_protocol_from_file =
  36. (SubGhzProtocolCommonLoadFromFile)subghz_protocol_came_twee_to_load_protocol_from_file;
  37. instance->common.to_load_protocol =
  38. (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_came_twee_to_load_protocol;
  39. instance->common.get_upload_protocol =
  40. (SubGhzProtocolCommonEncoderGetUpLoad)subghz_protocol_came_twee_send_key;
  41. return instance;
  42. }
  43. void subghz_protocol_came_twee_free(SubGhzProtocolCameTwee* instance) {
  44. furi_assert(instance);
  45. free(instance);
  46. }
  47. LevelDuration subghz_protocol_came_twee_add_duration_to_upload(
  48. SubGhzProtocolCameTwee* instance,
  49. ManchesterEncoderResult result) {
  50. LevelDuration data = {.duration = 0, .level = 0};
  51. switch(result) {
  52. case ManchesterEncoderResultShortLow:
  53. data.duration = instance->common.te_short;
  54. data.level = false;
  55. break;
  56. case ManchesterEncoderResultLongLow:
  57. data.duration = instance->common.te_long;
  58. data.level = false;
  59. break;
  60. case ManchesterEncoderResultLongHigh:
  61. data.duration = instance->common.te_long;
  62. data.level = true;
  63. break;
  64. case ManchesterEncoderResultShortHigh:
  65. data.duration = instance->common.te_short;
  66. data.level = true;
  67. break;
  68. default:
  69. printf("DO CRASH HERE\r\n");
  70. // furi_crash
  71. break;
  72. }
  73. return level_duration_make(data.level, data.duration);
  74. }
  75. bool subghz_protocol_came_twee_send_key(
  76. SubGhzProtocolCameTwee* instance,
  77. SubGhzProtocolCommonEncoder* encoder) {
  78. furi_assert(instance);
  79. furi_assert(encoder);
  80. const uint32_t magic_numbers_xor[15] = {
  81. 0x0E0E0E00,
  82. 0x1D1D1D11,
  83. 0x2C2C2C22,
  84. 0x3B3B3B33,
  85. 0x4A4A4A44,
  86. 0x59595955,
  87. 0x68686866,
  88. 0x77777777,
  89. 0x86868688,
  90. 0x95959599,
  91. 0xA4A4A4AA,
  92. 0xB3B3B3BB,
  93. 0xC2C2C2CC,
  94. 0xD1D1D1DD,
  95. 0xE0E0E0EE,
  96. };
  97. size_t index = 0;
  98. ManchesterEncoderState enc_state;
  99. manchester_encoder_reset(&enc_state);
  100. ManchesterEncoderResult result;
  101. // encoder->size_upload = (instance->common.code_last_count_bit * 2) + 2;
  102. // if(encoder->size_upload > SUBGHZ_ENCODER_UPLOAD_MAX_SIZE) return false;
  103. uint64_t temp_parcel = 0x003FFF7200000000; //parcel mask
  104. for(int i = 14; i >= 0; i--) {
  105. temp_parcel = (temp_parcel & 0xFFFFFFFF00000000) |
  106. (instance->common.serial ^ magic_numbers_xor[i]);
  107. for(uint8_t i = instance->common.code_last_count_bit; i > 0; i--) {
  108. if(!manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result)) {
  109. encoder->upload[index++] =
  110. subghz_protocol_came_twee_add_duration_to_upload(instance, result);
  111. manchester_encoder_advance(&enc_state, !bit_read(temp_parcel, i - 1), &result);
  112. }
  113. encoder->upload[index++] =
  114. subghz_protocol_came_twee_add_duration_to_upload(instance, result);
  115. }
  116. encoder->upload[index] = subghz_protocol_came_twee_add_duration_to_upload(
  117. instance, manchester_encoder_finish(&enc_state));
  118. if(level_duration_get_level(encoder->upload[index])) {
  119. index++;
  120. }
  121. encoder->upload[index++] =
  122. level_duration_make(false, (uint32_t)instance->common.te_long * 51);
  123. }
  124. encoder->size_upload = index;
  125. return true;
  126. }
  127. /** Analysis of received data
  128. *
  129. * @param instance SubGhzProtocolCameTwee instance
  130. */
  131. void subghz_protocol_came_twee_remote_controller(SubGhzProtocolCameTwee* instance) {
  132. /* Came Twee 54 bit, rolling code 15 parcels with
  133. * a decreasing counter from 0xE to 0x0
  134. * with originally coded dip switches on the console 10 bit code
  135. *
  136. * 0x003FFF72E04A6FEE
  137. * 0x003FFF72D17B5EDD
  138. * 0x003FFF72C2684DCC
  139. * 0x003FFF72B3193CBB
  140. * 0x003FFF72A40E2BAA
  141. * 0x003FFF72953F1A99
  142. * 0x003FFF72862C0988
  143. * 0x003FFF7277DDF877
  144. * 0x003FFF7268C2E766
  145. * 0x003FFF7259F3D655
  146. * 0x003FFF724AE0C544
  147. * 0x003FFF723B91B433
  148. * 0x003FFF722C86A322
  149. * 0x003FFF721DB79211
  150. * 0x003FFF720EA48100
  151. *
  152. * decryption
  153. * the last 32 bits, do XOR by the desired number, divide the result by 4,
  154. * convert the first 16 bits of the resulting 32-bit number to bin and do
  155. * bit-by-bit mirroring, adding up to 10 bits
  156. *
  157. * Example
  158. * Step 1. 0x003FFF721DB79211 => 0x1DB79211
  159. * Step 4. 0x1DB79211 xor 0x1D1D1D11 => 0x00AA8F00
  160. * Step 4. 0x00AA8F00 / 4 => 0x002AA3C0
  161. * Step 5. 0x002AA3C0 => 0x002A
  162. * Step 6. 0x002A bin => b101010
  163. * Step 7. b101010 => b0101010000
  164. * Step 8. b0101010000 => (Dip) Off ON Off ON Off ON Off Off Off Off
  165. */
  166. const uint32_t magic_numbers_xor[15] = {
  167. 0x0E0E0E00,
  168. 0x1D1D1D11,
  169. 0x2C2C2C22,
  170. 0x3B3B3B33,
  171. 0x4A4A4A44,
  172. 0x59595955,
  173. 0x68686866,
  174. 0x77777777,
  175. 0x86868688,
  176. 0x95959599,
  177. 0xA4A4A4AA,
  178. 0xB3B3B3BB,
  179. 0xC2C2C2CC,
  180. 0xD1D1D1DD,
  181. 0xE0E0E0EE,
  182. };
  183. uint8_t cnt_parcel = (uint8_t)(instance->common.code_last_found & 0xF);
  184. uint32_t data = (uint32_t)(instance->common.code_last_found & 0x0FFFFFFFF);
  185. data = (data ^ magic_numbers_xor[cnt_parcel]);
  186. instance->common.serial = data;
  187. data /= 4;
  188. instance->common.btn = (data >> 4) & 0x0F;
  189. data >>= 16;
  190. data = (uint16_t)subghz_protocol_common_reverse_key(data, 16);
  191. instance->common.cnt = data >> 6;
  192. }
  193. void subghz_protocol_came_twee_reset(SubGhzProtocolCameTwee* instance) {
  194. instance->common.parser_step = CameTweeDecoderStepReset;
  195. manchester_advance(
  196. instance->manchester_saved_state,
  197. ManchesterEventReset,
  198. &instance->manchester_saved_state,
  199. NULL);
  200. }
  201. void subghz_protocol_came_twee_parse(
  202. SubGhzProtocolCameTwee* instance,
  203. bool level,
  204. uint32_t duration) {
  205. ManchesterEvent event = ManchesterEventReset;
  206. switch(instance->common.parser_step) {
  207. case CameTweeDecoderStepReset:
  208. if((!level) && (DURATION_DIFF(duration, instance->common.te_long * 51) <
  209. instance->common.te_delta * 20)) {
  210. //Found header CAME
  211. instance->common.parser_step = CameTweeDecoderStepDecoderData;
  212. instance->common.code_found = 0;
  213. instance->common.code_count_bit = 0;
  214. manchester_advance(
  215. instance->manchester_saved_state,
  216. ManchesterEventLongLow,
  217. &instance->manchester_saved_state,
  218. NULL);
  219. manchester_advance(
  220. instance->manchester_saved_state,
  221. ManchesterEventLongHigh,
  222. &instance->manchester_saved_state,
  223. NULL);
  224. manchester_advance(
  225. instance->manchester_saved_state,
  226. ManchesterEventShortLow,
  227. &instance->manchester_saved_state,
  228. NULL);
  229. }
  230. break;
  231. case CameTweeDecoderStepDecoderData:
  232. if(!level) {
  233. if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
  234. event = ManchesterEventShortLow;
  235. } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
  236. event = ManchesterEventLongLow;
  237. } else if(duration >= (instance->common.te_long * 2 + instance->common.te_delta)) {
  238. if(instance->common.code_count_bit >=
  239. instance->common.code_min_count_bit_for_found) {
  240. instance->common.code_last_found = instance->common.code_found;
  241. instance->common.code_last_count_bit = instance->common.code_count_bit;
  242. if(instance->common.callback)
  243. instance->common.callback(
  244. (SubGhzProtocolCommon*)instance, instance->common.context);
  245. }
  246. instance->common.code_found = 0;
  247. instance->common.code_count_bit = 0;
  248. manchester_advance(
  249. instance->manchester_saved_state,
  250. ManchesterEventLongLow,
  251. &instance->manchester_saved_state,
  252. NULL);
  253. manchester_advance(
  254. instance->manchester_saved_state,
  255. ManchesterEventLongHigh,
  256. &instance->manchester_saved_state,
  257. NULL);
  258. manchester_advance(
  259. instance->manchester_saved_state,
  260. ManchesterEventShortLow,
  261. &instance->manchester_saved_state,
  262. NULL);
  263. } else {
  264. instance->common.parser_step = CameTweeDecoderStepReset;
  265. }
  266. } else {
  267. if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
  268. event = ManchesterEventShortHigh;
  269. } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
  270. event = ManchesterEventLongHigh;
  271. } else {
  272. instance->common.parser_step = CameTweeDecoderStepReset;
  273. }
  274. }
  275. if(event != ManchesterEventReset) {
  276. bool data;
  277. bool data_ok = manchester_advance(
  278. instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
  279. if(data_ok) {
  280. instance->common.code_found = (instance->common.code_found << 1) | !data;
  281. instance->common.code_count_bit++;
  282. }
  283. }
  284. break;
  285. }
  286. }
  287. void subghz_protocol_came_twee_to_str(SubGhzProtocolCameTwee* instance, string_t output) {
  288. uint32_t code_found_hi = instance->common.code_last_found >> 32;
  289. uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
  290. string_cat_printf(
  291. output,
  292. "%s %dbit\r\n"
  293. "Key:0x%lX%08lX\r\n"
  294. "Btn:%lX\r\n"
  295. "DIP:" DIP_PATTERN,
  296. instance->common.name,
  297. instance->common.code_last_count_bit,
  298. code_found_hi,
  299. code_found_lo,
  300. instance->common.btn,
  301. CNT_TO_DIP(instance->common.cnt));
  302. }
  303. bool subghz_protocol_came_twee_to_save_file(
  304. SubGhzProtocolCameTwee* instance,
  305. FlipperFile* flipper_file) {
  306. return subghz_protocol_common_to_save_file((SubGhzProtocolCommon*)instance, flipper_file);
  307. }
  308. bool subghz_protocol_came_twee_to_load_protocol_from_file(
  309. FlipperFile* flipper_file,
  310. SubGhzProtocolCameTwee* instance,
  311. const char* file_path) {
  312. if(subghz_protocol_common_to_load_protocol_from_file(
  313. (SubGhzProtocolCommon*)instance, flipper_file)) {
  314. subghz_protocol_came_twee_remote_controller(instance);
  315. return true;
  316. }
  317. return false;
  318. }
  319. void subghz_decoder_came_twee_to_load_protocol(SubGhzProtocolCameTwee* instance, void* context) {
  320. furi_assert(context);
  321. furi_assert(instance);
  322. SubGhzProtocolCommonLoad* data = context;
  323. instance->common.code_last_found = data->code_found;
  324. instance->common.code_last_count_bit = data->code_count_bit;
  325. subghz_protocol_came_twee_remote_controller(instance);
  326. }