kedsum_th.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. #include "kedsum_th.h"
  2. #define TAG "WSProtocolKedsumTH"
  3. /*
  4. * Help
  5. * https://github.com/merbanan/rtl_433/blob/master/src/devices/kedsum.c
  6. *
  7. * Frame structure:
  8. *
  9. * Byte: 0 1 2 3 4
  10. * Nibble: 1 2 3 4 5 6 7 8 9 10
  11. * Type: 00 IIIIIIII BBCC++++ ttttTTTT hhhhHHHH FFFFXXXX
  12. *
  13. * - I: unique id. changes on powercycle
  14. * - B: Battery state 10 = Ok, 01 = weak, 00 = bad
  15. * - C: channel, 00 = ch1, 10=ch3
  16. * - + low temp nibble
  17. * - t: med temp nibble
  18. * - T: high temp nibble
  19. * - h: humidity low nibble
  20. * - H: humidity high nibble
  21. * - F: flags
  22. * - X: CRC-4 poly 0x3 init 0x0 xor last 4 bits
  23. */
  24. static const SubGhzBlockConst ws_protocol_kedsum_th_const = {
  25. .te_short = 500,
  26. .te_long = 2000,
  27. .te_delta = 150,
  28. .min_count_bit_for_found = 42,
  29. };
  30. struct WSProtocolDecoderKedsumTH {
  31. SubGhzProtocolDecoderBase base;
  32. SubGhzBlockDecoder decoder;
  33. WSBlockGeneric generic;
  34. uint16_t header_count;
  35. };
  36. struct WSProtocolEncoderKedsumTH {
  37. SubGhzProtocolEncoderBase base;
  38. SubGhzProtocolBlockEncoder encoder;
  39. WSBlockGeneric generic;
  40. };
  41. typedef enum {
  42. KedsumTHDecoderStepReset = 0,
  43. KedsumTHDecoderStepCheckPreambule,
  44. KedsumTHDecoderStepSaveDuration,
  45. KedsumTHDecoderStepCheckDuration,
  46. } KedsumTHDecoderStep;
  47. const SubGhzProtocolDecoder ws_protocol_kedsum_th_decoder = {
  48. .alloc = ws_protocol_decoder_kedsum_th_alloc,
  49. .free = ws_protocol_decoder_kedsum_th_free,
  50. .feed = ws_protocol_decoder_kedsum_th_feed,
  51. .reset = ws_protocol_decoder_kedsum_th_reset,
  52. .get_hash_data = ws_protocol_decoder_kedsum_th_get_hash_data,
  53. .serialize = ws_protocol_decoder_kedsum_th_serialize,
  54. .deserialize = ws_protocol_decoder_kedsum_th_deserialize,
  55. .get_string = ws_protocol_decoder_kedsum_th_get_string,
  56. };
  57. const SubGhzProtocolEncoder ws_protocol_kedsum_th_encoder = {
  58. .alloc = NULL,
  59. .free = NULL,
  60. .deserialize = NULL,
  61. .stop = NULL,
  62. .yield = NULL,
  63. };
  64. const SubGhzProtocol ws_protocol_kedsum_th = {
  65. .name = WS_PROTOCOL_KEDSUM_TH_NAME,
  66. .type = SubGhzProtocolWeatherStation,
  67. .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
  68. SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
  69. .decoder = &ws_protocol_kedsum_th_decoder,
  70. .encoder = &ws_protocol_kedsum_th_encoder,
  71. };
  72. void* ws_protocol_decoder_kedsum_th_alloc(SubGhzEnvironment* environment) {
  73. UNUSED(environment);
  74. WSProtocolDecoderKedsumTH* instance = malloc(sizeof(WSProtocolDecoderKedsumTH));
  75. instance->base.protocol = &ws_protocol_kedsum_th;
  76. instance->generic.protocol_name = instance->base.protocol->name;
  77. return instance;
  78. }
  79. void ws_protocol_decoder_kedsum_th_free(void* context) {
  80. furi_assert(context);
  81. WSProtocolDecoderKedsumTH* instance = context;
  82. free(instance);
  83. }
  84. void ws_protocol_decoder_kedsum_th_reset(void* context) {
  85. furi_assert(context);
  86. WSProtocolDecoderKedsumTH* instance = context;
  87. instance->decoder.parser_step = KedsumTHDecoderStepReset;
  88. }
  89. static bool ws_protocol_kedsum_th_check_crc(WSProtocolDecoderKedsumTH* instance) {
  90. uint8_t msg[] = {
  91. instance->decoder.decode_data >> 32,
  92. instance->decoder.decode_data >> 24,
  93. instance->decoder.decode_data >> 16,
  94. instance->decoder.decode_data >> 8,
  95. instance->decoder.decode_data};
  96. uint8_t crc =
  97. subghz_protocol_blocks_crc4(msg, 4, 0x03, 0); // CRC-4 poly 0x3 init 0x0 xor last 4 bits
  98. crc ^= msg[4] >> 4; // last nibble is only XORed
  99. return (crc == (msg[4] & 0x0F));
  100. }
  101. /**
  102. * Analysis of received data
  103. * @param instance Pointer to a WSBlockGeneric* instance
  104. */
  105. static void ws_protocol_kedsum_th_remote_controller(WSBlockGeneric* instance) {
  106. instance->id = instance->data >> 32;
  107. if((instance->data >> 30) & 0x3) {
  108. instance->battery_low = 0;
  109. } else {
  110. instance->battery_low = 1;
  111. }
  112. instance->channel = ((instance->data >> 28) & 0x3) + 1;
  113. instance->btn = WS_NO_BTN;
  114. uint16_t temp_raw = ((instance->data >> 16) & 0x0f) << 8 |
  115. ((instance->data >> 20) & 0x0f) << 4 | ((instance->data >> 24) & 0x0f);
  116. instance->temp = locale_fahrenheit_to_celsius(((float)temp_raw - 900.0f) / 10.0f);
  117. instance->humidity = ((instance->data >> 8) & 0x0f) << 4 | ((instance->data >> 12) & 0x0f);
  118. }
  119. void ws_protocol_decoder_kedsum_th_feed(void* context, bool level, uint32_t duration) {
  120. furi_assert(context);
  121. WSProtocolDecoderKedsumTH* instance = context;
  122. switch(instance->decoder.parser_step) {
  123. case KedsumTHDecoderStepReset:
  124. if((level) && (DURATION_DIFF(duration, ws_protocol_kedsum_th_const.te_short) <
  125. ws_protocol_kedsum_th_const.te_delta)) {
  126. instance->decoder.parser_step = KedsumTHDecoderStepCheckPreambule;
  127. instance->decoder.te_last = duration;
  128. instance->header_count = 0;
  129. }
  130. break;
  131. case KedsumTHDecoderStepCheckPreambule:
  132. if(level) {
  133. instance->decoder.te_last = duration;
  134. } else {
  135. if((DURATION_DIFF(instance->decoder.te_last, ws_protocol_kedsum_th_const.te_short) <
  136. ws_protocol_kedsum_th_const.te_delta) &&
  137. (DURATION_DIFF(duration, ws_protocol_kedsum_th_const.te_long * 4) <
  138. ws_protocol_kedsum_th_const.te_delta * 4)) {
  139. //Found preambule
  140. instance->header_count++;
  141. } else if(
  142. (DURATION_DIFF(instance->decoder.te_last, ws_protocol_kedsum_th_const.te_short) <
  143. ws_protocol_kedsum_th_const.te_delta) &&
  144. (duration < (ws_protocol_kedsum_th_const.te_long * 2 +
  145. ws_protocol_kedsum_th_const.te_delta * 2))) {
  146. //Found syncPrefix
  147. if(instance->header_count > 0) {
  148. instance->decoder.parser_step = KedsumTHDecoderStepSaveDuration;
  149. instance->decoder.decode_data = 0;
  150. instance->decoder.decode_count_bit = 0;
  151. if((DURATION_DIFF(
  152. instance->decoder.te_last, ws_protocol_kedsum_th_const.te_short) <
  153. ws_protocol_kedsum_th_const.te_delta) &&
  154. (DURATION_DIFF(duration, ws_protocol_kedsum_th_const.te_long) <
  155. ws_protocol_kedsum_th_const.te_delta * 2)) {
  156. subghz_protocol_blocks_add_bit(&instance->decoder, 0);
  157. instance->decoder.parser_step = KedsumTHDecoderStepSaveDuration;
  158. } else if(
  159. (DURATION_DIFF(
  160. instance->decoder.te_last, ws_protocol_kedsum_th_const.te_short) <
  161. ws_protocol_kedsum_th_const.te_delta) &&
  162. (DURATION_DIFF(duration, ws_protocol_kedsum_th_const.te_long * 2) <
  163. ws_protocol_kedsum_th_const.te_delta * 4)) {
  164. subghz_protocol_blocks_add_bit(&instance->decoder, 1);
  165. instance->decoder.parser_step = KedsumTHDecoderStepSaveDuration;
  166. } else {
  167. instance->decoder.parser_step = KedsumTHDecoderStepReset;
  168. }
  169. }
  170. } else {
  171. instance->decoder.parser_step = KedsumTHDecoderStepReset;
  172. }
  173. }
  174. break;
  175. case KedsumTHDecoderStepSaveDuration:
  176. if(level) {
  177. instance->decoder.te_last = duration;
  178. instance->decoder.parser_step = KedsumTHDecoderStepCheckDuration;
  179. } else {
  180. instance->decoder.parser_step = KedsumTHDecoderStepReset;
  181. }
  182. break;
  183. case KedsumTHDecoderStepCheckDuration:
  184. if(!level) {
  185. if(DURATION_DIFF(duration, ws_protocol_kedsum_th_const.te_long * 4) <
  186. ws_protocol_kedsum_th_const.te_delta * 4) {
  187. //Found syncPostfix
  188. if((instance->decoder.decode_count_bit ==
  189. ws_protocol_kedsum_th_const.min_count_bit_for_found) &&
  190. ws_protocol_kedsum_th_check_crc(instance)) {
  191. instance->generic.data = instance->decoder.decode_data;
  192. instance->generic.data_count_bit = instance->decoder.decode_count_bit;
  193. ws_protocol_kedsum_th_remote_controller(&instance->generic);
  194. if(instance->base.callback)
  195. instance->base.callback(&instance->base, instance->base.context);
  196. }
  197. instance->decoder.decode_data = 0;
  198. instance->decoder.decode_count_bit = 0;
  199. instance->decoder.parser_step = KedsumTHDecoderStepReset;
  200. break;
  201. } else if(
  202. (DURATION_DIFF(instance->decoder.te_last, ws_protocol_kedsum_th_const.te_short) <
  203. ws_protocol_kedsum_th_const.te_delta) &&
  204. (DURATION_DIFF(duration, ws_protocol_kedsum_th_const.te_long) <
  205. ws_protocol_kedsum_th_const.te_delta * 2)) {
  206. subghz_protocol_blocks_add_bit(&instance->decoder, 0);
  207. instance->decoder.parser_step = KedsumTHDecoderStepSaveDuration;
  208. } else if(
  209. (DURATION_DIFF(instance->decoder.te_last, ws_protocol_kedsum_th_const.te_short) <
  210. ws_protocol_kedsum_th_const.te_delta) &&
  211. (DURATION_DIFF(duration, ws_protocol_kedsum_th_const.te_long * 2) <
  212. ws_protocol_kedsum_th_const.te_delta * 4)) {
  213. subghz_protocol_blocks_add_bit(&instance->decoder, 1);
  214. instance->decoder.parser_step = KedsumTHDecoderStepSaveDuration;
  215. } else {
  216. instance->decoder.parser_step = KedsumTHDecoderStepReset;
  217. }
  218. } else {
  219. instance->decoder.parser_step = KedsumTHDecoderStepReset;
  220. }
  221. break;
  222. }
  223. }
  224. uint8_t ws_protocol_decoder_kedsum_th_get_hash_data(void* context) {
  225. furi_assert(context);
  226. WSProtocolDecoderKedsumTH* instance = context;
  227. return subghz_protocol_blocks_get_hash_data(
  228. &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
  229. }
  230. SubGhzProtocolStatus ws_protocol_decoder_kedsum_th_serialize(
  231. void* context,
  232. FlipperFormat* flipper_format,
  233. SubGhzRadioPreset* preset) {
  234. furi_assert(context);
  235. WSProtocolDecoderKedsumTH* instance = context;
  236. return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
  237. }
  238. SubGhzProtocolStatus
  239. ws_protocol_decoder_kedsum_th_deserialize(void* context, FlipperFormat* flipper_format) {
  240. furi_assert(context);
  241. WSProtocolDecoderKedsumTH* instance = context;
  242. return ws_block_generic_deserialize_check_count_bit(
  243. &instance->generic, flipper_format, ws_protocol_kedsum_th_const.min_count_bit_for_found);
  244. }
  245. void ws_protocol_decoder_kedsum_th_get_string(void* context, FuriString* output) {
  246. furi_assert(context);
  247. WSProtocolDecoderKedsumTH* instance = context;
  248. furi_string_printf(
  249. output,
  250. "%s %dbit\r\n"
  251. "Key:0x%lX%08lX\r\n"
  252. "Sn:0x%lX Ch:%d Bat:%d\r\n"
  253. "Temp:%3.1f C Hum:%d%%",
  254. instance->generic.protocol_name,
  255. instance->generic.data_count_bit,
  256. (uint32_t)(instance->generic.data >> 32),
  257. (uint32_t)(instance->generic.data),
  258. instance->generic.id,
  259. instance->generic.channel,
  260. instance->generic.battery_low,
  261. (double)instance->generic.temp,
  262. instance->generic.humidity);
  263. }