subghz_protocol_somfy_telis.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. #include "subghz_protocol_somfy_telis.h"
  2. #include "subghz_protocol_common.h"
  3. #include <lib/toolbox/manchester_decoder.h>
  4. #define TAG "SubGhzSomfyTelis"
  5. struct SubGhzProtocolSomfyTelis {
  6. SubGhzProtocolCommon common;
  7. ManchesterState manchester_saved_state;
  8. };
  9. typedef enum {
  10. SomfyTelisDecoderStepReset = 0,
  11. SomfyTelisDecoderStepCheckPreambula,
  12. SomfyTelisDecoderStepFoundPreambula,
  13. SomfyTelisDecoderStepStartDecode,
  14. SomfyTelisDecoderStepDecoderData,
  15. } SomfyTelisDecoderStep;
  16. SubGhzProtocolSomfyTelis* subghz_protocol_somfy_telis_alloc() {
  17. SubGhzProtocolSomfyTelis* instance = furi_alloc(sizeof(SubGhzProtocolSomfyTelis));
  18. instance->common.name = "Somfy Telis";
  19. instance->common.code_min_count_bit_for_found = 56;
  20. instance->common.te_short = 640;
  21. instance->common.te_long = 1280;
  22. instance->common.te_delta = 250;
  23. instance->common.type_protocol = SubGhzProtocolCommonTypeDynamic;
  24. instance->common.to_string = (SubGhzProtocolCommonToStr)subghz_protocol_somfy_telis_to_str;
  25. instance->common.to_load_protocol =
  26. (SubGhzProtocolCommonLoadFromRAW)subghz_decoder_somfy_telis_to_load_protocol;
  27. return instance;
  28. }
  29. void subghz_protocol_somfy_telis_free(SubGhzProtocolSomfyTelis* instance) {
  30. furi_assert(instance);
  31. free(instance);
  32. }
  33. /** Analysis of received data
  34. *
  35. * @param instance SubGhzProtocolSomfyTelis instance
  36. */
  37. void subghz_protocol_somfy_telis_remote_controller(SubGhzProtocolSomfyTelis* instance) {
  38. //https://pushstack.wordpress.com/somfy-rts-protocol/
  39. /*
  40. * 604 us
  41. * /
  42. * | 2416us | 2416us | 2416us | 2416us | 4550 us | | 67648 us | 30415 us |
  43. *
  44. * +--------+ +--------+ +---...---+
  45. * + +--------+ +--------+ +--+XXXX...XXX+-----...-----
  46. *
  47. * | hw. sync. | soft. | | Inter-frame
  48. * | | sync. | data | gap
  49. *
  50. *
  51. * encrypt | decrypt
  52. *
  53. * package 56 bit cnt key btn|crc cnt serial
  54. * 0xA7232323312222 - 0 => A7 8 0 | 00 00 | 12 13 00
  55. * 0xA7222223312222 - 1 => A7 8 5 | 00 01 | 12 13 00
  56. * 0xA7212123312222 - 2 => A7 8 6 | 00 02 | 12 13 00
  57. *
  58. * Key: “Encryption Key”, Most significant 4-bit are always 0xA, Least Significant bits is
  59. * a linear counter. In the Smoove Origin this counter is increased together with the
  60. * rolling code. But leaving this on a constant value also works. Gerardwr notes that
  61. * for some other types of remotes the MSB is not constant.
  62. * Btn: 4-bit Control codes, this indicates the button that is pressed
  63. * CRC: 4-bit Checksum.
  64. * Ctn: 16-bit rolling code (big-endian) increased with every button press.
  65. * Serial: 24-bit identifier of sending device (little-endian)
  66. *
  67. *
  68. * Decrypt
  69. *
  70. * uint8_t frame[7];
  71. * for (i=1; i < 7; i++) {
  72. * frame[i] = frame[i] ^ frame[i-1];
  73. * }
  74. * or
  75. * uint64 Decrypt = frame ^ (frame>>8);
  76. *
  77. * Btn
  78. *
  79. * Value Button(s) Description
  80. * 0x1 My Stop or move to favourite position
  81. * 0x2 Up Move up
  82. * 0x3 My + Up Set upper motor limit in initial programming mode
  83. * 0x4 Down Move down
  84. * 0x5 My + Down Set lower motor limit in initial programming mode
  85. * 0x6 Up + Down Change motor limit and initial programming mode
  86. * 0x8 Prog Used for (de-)registering remotes, see below
  87. * 0x9 Sun + Flag Enable sun and wind detector (SUN and FLAG symbol on the Telis Soliris RC)
  88. * 0xA Flag Disable sun detector (FLAG symbol on the Telis Soliris RC)
  89. *
  90. * CRC
  91. *
  92. * uint8_t frame[7];
  93. * for (i=0; i < 7; i++) {
  94. * cksum = cksum ^ frame[i] ^ (frame[i] >> 4);
  95. * }
  96. * cksum = cksum & 0xf;
  97. *
  98. */
  99. uint64_t data = instance->common.code_last_found ^ (instance->common.code_last_found >> 8);
  100. instance->common.btn = (data >> 44) & 0xF;
  101. instance->common.cnt = (data >> 24) & 0xFFFF;
  102. instance->common.serial = data & 0xFFFFFF;
  103. }
  104. uint8_t subghz_protocol_somfy_telis_crc(uint64_t data) {
  105. uint8_t crc = 0;
  106. data &= 0xFFF0FFFFFFFFFF;
  107. for(uint8_t i = 0; i < 56; i += 8) {
  108. crc = crc ^ data >> i ^ (data >> (i + 4));
  109. }
  110. return crc & 0xf;
  111. }
  112. const char* subghz_protocol_somfy_telis_get_name_button(uint8_t btn) {
  113. const char* name_btn[0x10] = {
  114. "Unknown",
  115. "My",
  116. "Up",
  117. "My+Up",
  118. "Down",
  119. "My+Down",
  120. "Up+Down",
  121. "0x07",
  122. "Prog",
  123. "Sun+Flag",
  124. "Flag",
  125. "0x0B",
  126. "0x0C",
  127. "0x0D",
  128. "0x0E",
  129. "0x0F"};
  130. return btn <= 0xf ? name_btn[btn] : name_btn[0];
  131. }
  132. void subghz_protocol_somfy_telis_reset(SubGhzProtocolSomfyTelis* instance) {
  133. instance->common.parser_step = SomfyTelisDecoderStepReset;
  134. manchester_advance(
  135. instance->manchester_saved_state,
  136. ManchesterEventReset,
  137. &instance->manchester_saved_state,
  138. NULL);
  139. }
  140. void subghz_protocol_somfy_telis_parse(
  141. SubGhzProtocolSomfyTelis* instance,
  142. bool level,
  143. uint32_t duration) {
  144. ManchesterEvent event = ManchesterEventReset;
  145. switch(instance->common.parser_step) {
  146. case SomfyTelisDecoderStepReset:
  147. if((level) && DURATION_DIFF(duration, instance->common.te_short * 4) <
  148. instance->common.te_delta * 4) {
  149. instance->common.parser_step = SomfyTelisDecoderStepFoundPreambula;
  150. instance->common.header_count++;
  151. }
  152. break;
  153. case SomfyTelisDecoderStepFoundPreambula:
  154. if((!level) && (DURATION_DIFF(duration, instance->common.te_short * 4) <
  155. instance->common.te_delta * 4)) {
  156. instance->common.parser_step = SomfyTelisDecoderStepCheckPreambula;
  157. } else {
  158. instance->common.header_count = 0;
  159. instance->common.parser_step = SomfyTelisDecoderStepReset;
  160. }
  161. break;
  162. case SomfyTelisDecoderStepCheckPreambula:
  163. if(level) {
  164. if(DURATION_DIFF(duration, instance->common.te_short * 4) <
  165. instance->common.te_delta * 4) {
  166. instance->common.parser_step = SomfyTelisDecoderStepFoundPreambula;
  167. instance->common.header_count++;
  168. } else if(
  169. (instance->common.header_count > 1) &&
  170. (DURATION_DIFF(duration, instance->common.te_short * 7) <
  171. instance->common.te_delta * 4)) {
  172. instance->common.parser_step = SomfyTelisDecoderStepDecoderData;
  173. instance->common.code_found = 0;
  174. instance->common.code_count_bit = 0;
  175. instance->common.header_count = 0;
  176. manchester_advance(
  177. instance->manchester_saved_state,
  178. ManchesterEventReset,
  179. &instance->manchester_saved_state,
  180. NULL);
  181. manchester_advance(
  182. instance->manchester_saved_state,
  183. ManchesterEventLongHigh,
  184. &instance->manchester_saved_state,
  185. NULL);
  186. }
  187. }
  188. break;
  189. case SomfyTelisDecoderStepDecoderData:
  190. if(!level) {
  191. if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
  192. event = ManchesterEventShortLow;
  193. } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
  194. event = ManchesterEventLongLow;
  195. } else if(duration >= (instance->common.te_long + instance->common.te_delta)) {
  196. if(instance->common.code_count_bit ==
  197. instance->common.code_min_count_bit_for_found) {
  198. instance->common.code_last_found = instance->common.code_found;
  199. instance->common.code_last_count_bit = instance->common.code_count_bit;
  200. //check crc
  201. uint64_t data_tmp = instance->common.code_last_found ^
  202. (instance->common.code_last_found >> 8);
  203. if(((data_tmp >> 40) & 0xF) == subghz_protocol_somfy_telis_crc(data_tmp)) {
  204. if(instance->common.callback)
  205. instance->common.callback(
  206. (SubGhzProtocolCommon*)instance, instance->common.context);
  207. }
  208. }
  209. instance->common.code_found = 0;
  210. instance->common.code_count_bit = 0;
  211. manchester_advance(
  212. instance->manchester_saved_state,
  213. ManchesterEventReset,
  214. &instance->manchester_saved_state,
  215. NULL);
  216. manchester_advance(
  217. instance->manchester_saved_state,
  218. ManchesterEventLongHigh,
  219. &instance->manchester_saved_state,
  220. NULL);
  221. instance->common.parser_step = SomfyTelisDecoderStepReset;
  222. } else {
  223. instance->common.parser_step = SomfyTelisDecoderStepReset;
  224. }
  225. } else {
  226. if(DURATION_DIFF(duration, instance->common.te_short) < instance->common.te_delta) {
  227. event = ManchesterEventShortHigh;
  228. } else if(DURATION_DIFF(duration, instance->common.te_long) < instance->common.te_delta) {
  229. event = ManchesterEventLongHigh;
  230. } else {
  231. instance->common.parser_step = SomfyTelisDecoderStepReset;
  232. }
  233. }
  234. if(event != ManchesterEventReset) {
  235. bool data;
  236. bool data_ok = manchester_advance(
  237. instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
  238. if(data_ok) {
  239. instance->common.code_found = (instance->common.code_found << 1) | data;
  240. instance->common.code_count_bit++;
  241. }
  242. }
  243. break;
  244. }
  245. }
  246. void subghz_protocol_somfy_telis_to_str(SubGhzProtocolSomfyTelis* instance, string_t output) {
  247. subghz_protocol_somfy_telis_remote_controller(instance);
  248. uint32_t code_found_hi = instance->common.code_last_found >> 32;
  249. uint32_t code_found_lo = instance->common.code_last_found & 0x00000000ffffffff;
  250. string_cat_printf(
  251. output,
  252. "%s %db\r\n"
  253. "Key:0x%lX%08lX\r\n"
  254. "Sn:0x%06lX \r\n"
  255. "Cnt:0x%04X\r\n"
  256. "Btn:%s\r\n",
  257. instance->common.name,
  258. instance->common.code_last_count_bit,
  259. code_found_hi,
  260. code_found_lo,
  261. instance->common.serial,
  262. instance->common.cnt,
  263. subghz_protocol_somfy_telis_get_name_button(instance->common.btn));
  264. }
  265. void subghz_decoder_somfy_telis_to_load_protocol(SubGhzProtocolSomfyTelis* instance, void* context) {
  266. furi_assert(context);
  267. furi_assert(instance);
  268. SubGhzProtocolCommonLoad* data = context;
  269. instance->common.code_last_found = data->code_found;
  270. instance->common.code_last_count_bit = data->code_count_bit;
  271. subghz_protocol_somfy_telis_remote_controller(instance);
  272. }