Add new SubGHz protocol: Hormann BiSecur (#118)

This commit is contained in:
Vencislav Atanasov
2024-05-06 12:08:53 +03:00
committed by GitHub
parent e982c31d06
commit 45999b4416
7 changed files with 831 additions and 1 deletions

View File

@@ -0,0 +1,9 @@
Filetype: Flipper SubGhz Key File
Version: 1
Frequency: 868276000
Preset: FuriHalSubGhzPresetCustom
Custom_preset_module: CC1101
Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 40 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00
Protocol: Hormann BiSecur
Bit: 176
Key: 70 08 0E D9 69 CA EE 02 6C F1 0E CB 11 5E F5 F8 17 02 6D EC 16 4B

View File

@@ -0,0 +1,9 @@
Filetype: Flipper SubGhz Key File
Version: 1
Frequency: 868276000
Preset: FuriHalSubGhzPresetCustom
Custom_preset_module: CC1101
Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 40 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00
Protocol: Hormann BiSecur
Bit: 176
Key: 50 1C 84 A5 5B 24 54 0D E5 44 C0 70 69 73 7F 2C 7E B3 43 18 BB 1C

View File

@@ -0,0 +1,12 @@
Filetype: Flipper SubGhz RAW File
Version: 1
Frequency: 868276000
Preset: FuriHalSubGhzPresetCustom
Custom_preset_module: CC1101
Custom_preset_data: 02 0D 0B 06 08 32 07 04 14 00 13 02 12 04 11 83 10 67 15 40 18 18 19 16 1D 91 1C 00 1B 07 20 FB 22 10 21 56 00 00 C0 00 00 00 00 00 00 00
Protocol: RAW
RAW_Data: 79 -2076 51 -3114 103 -2248 161 -965 73 -2342 75 -988 57 -2430 77 -4254 55 -6822 53 -5266 73 -100 75 -7402 51 -3408 79 -2944 79 -7165 53 -220 79 -588 51 -2601 75 -5294 53 -6492 53 -990 55 -54 75 -876 51 -748 51 -102 51 -132 133 -4051 51 -5733 111 -1706 87 -982 79 -3369 71 -482 51 -3250 81 -8724 73 -466 73 -2758 53 -1731 119 -740 285 -180 147 -258 359 -176 101 -940 79 -386 105 -750 271 -82 109 -200 55 -196 81 -78 105 -152 75 -72 175 -348 75 -302 173 -144 71 -178 119 -192 143 -122 561 -922 75 -360 51 -220 53 -80 105 -130 171 -452 53 -2048 55 -674 85 -86 111 -1604 79 -504 95 -9810 55 -19223 85 -25037 53 -5391 77 -21762 55 -9772 135 -5916 53 -5510 73 -10526 79 -3127 51 -35898 55 -24991 53 -2826 51 -2560 55 -48108 57 -21894 75 -1214 85 -5151 73 -1758 51 -414 137 -3918 75 -1846 51 -3632 53 -1672 51 -4863 110 -1260 55 -3780 51 -246 147 -5061 87 -8068 51 -14435 53 -1444 51 -6360 81 -816 85 -32352 83 -15921 71 -2022 113 -20263 57 -1256 71 -33812 51 -12556 71 -21101 71 -5255 81 -4828 55 -4343 75 -13401 79 -848 71 -336 57 -954 57 -5652 103 -7743 79 -2534 71 -7208 81 -8077 95 -3718 55 -1228 81 -1328 51 -1756 51 -340 73 -5828 55 -10248 57 -6800 99 -2618 85 -14952 79 -1106 57 -646 85 -9458 55 -10124 81 -2056 51 -2052 57 -22758 51 -1505 53 -1488 83 -2238 75 -30877 75 -14241 73 -1460 55 -500 75 -31790 57 -932 51 -4492 53 -5062 77 -4516 57 -1770 57 -7641 81 -9324 135 -4246 119 -1390 87 -14753 51 -672 53 -1366 81 -13153 125 -10510 55 -5672 95 -3761 71 -12991 81 -10183 57 -614 57 -15108 85 -21998 53 -45234 187 -812 55 -3940 94 -402 57 -2174 53 -1920 77 -22299 75 -6066 81 -2436 57 -10350 30785 -342 79 -11938 57 -8226 113 -4088 51 -4686 103 -7615 79 -31444 3097 -130 261 -182 233 -182 233 -184 233 -182 207 -208 207 -208 207 -210 207 -208 207 -210 207 -208 207 -208 207 -208 207 -210 1671 -414 415 -414 415 -208 417 -416 415 -416 209 -208 207 -208 207 -210 207 -208 207 -208 207 -208 415 -210 207 -208 207 -418 207 -208 415 -418 207 -208 207 -208 207 -208 415 -418 207 -208 417 -416 417 -416 207 -208 417 -416 417 -416 415 -416 415 -210 207 -416 417 -208 207 -416 209 -208 415 -416 207 -210 415 -416 209 -208 207 -208 415 -418 415 -416 415 -418 207 -208 207 -210 207 -208 205 -208 209 -208 415 -208 209 -416 417 -208 207 -208 207 -210 207 -416 207 -208 441 -390 417 -416 417 -416 207 -210 207 -208 415 -418
RAW_Data: 207 -208 415 -208 209 -416 207 -208 207 -208 209 -208 207 -208 207 -210 207 -208 415 -208 207 -210 207 -416 207 -210 207 -208 207 -208 207 -208 441 -182 209 -416 415 -418 207 -208 417 -416 417 -208 207 -208 207 -416 209 -208 415 -208 209 -416 415 -208 207 -210 207 -208 207 -208 209 -208 207 -208 207 -416 209 -208 415 -418 415 -208 207 -416 207 -208 207 -210 415 -208 209 -208 207 -208 207 -210 207 -208 207 -416 417 -416 415 -210 207 -416 207 -208 415 -208 207 -418 415 -418 207 -208 207 -210 205 -208 417 -208 207 -418 207 -208 207 -208 415 -210 207 -416 207 -210 207 -208 415 -416 417 -208 207 -208 209 -416 415 -208 207 -418 207 -208 207 -208 441 -182 235 -182 233 -390 209 -208 547 -160 113 -86 173 -86 111 -56 393 -284 77 -82 133 -328 291 -846 239 -106 79 -136 161 -206 71 -192 710 -78 715 -482 99 -268 175 -106 127 -102 231 -102 51 -152 173 -292 161 -128 216 -176 53 -254 345 -78 327 -232 51 -452 191 -136 81 -428 427 -76 103 -626 109 -88 169 -248 189 -78 163 -425 159 -258 153 -338 227 -98 295 -52 281 -146 123 -202 151 -146 191 -358 201 -170 123 -372 458 -110 55 -56 183 -52 293 -110 111 -88 85 -254 57 -256 107 -154 133 -82 53 -136 139 -84 83 -82 494 -304 107 -110 244 -184 165 -202 81 -288 277 -1685 103 -80 139 -558 79 -162 57 -448 53 -1166 53 -1030 51 -593 97 -120 71 -1543 53 -596 105 -244 109 -374 55 -543 185 -322 75 -6226 77 -2590 71 -4204 73 -8415 55 -4322 83 -19410 51 -3480 51 -27206 85 -1958 53 -8814 81 -6334 75 -16618 83 -2582 51 -1108 71 -5276 97 -3026 75 -648 85 -2320 85 -1372 79 -2068 51 -6490 73 -28316 53 -734 71 -9899 135 -6061 55 -4128 79 -6944 75 -2674 79 -5785 71 -5214 81 -52183 55 -13423 199 -10114 71 -2950 71 -729 77 -3808 57 -48956 85 -34604 143 -24899 1833 -128 259 -180 233 -182 235 -182 233 -182 235 -182 207 -208 207 -210 207 -208 207 -208 209 -208 207 -208 207 -208 207 -210 207 -208 207 -208 209 -208 1665 -416 417 -416 415 -208 417 -416 417 -416 207 -208 207 -208 207 -208 207 -210 207 -208 207 -210 415 -208 207 -210 207 -416 207 -208 415 -416 209 -208 207 -208 207 -210 415 -418 207 -208 415 -418 415 -416 207 -210 413 -418 415 -418 415 -418 415 -208 207 -416 415 -208 209 -416 207 -208 417 -416 209 -206 417 -416 207 -208 209 -208 415 -418 415 -416 415 -418 207 -208 209 -206 207 -210 207 -208 207 -208 417 -208 207 -418 415 -208
RAW_Data: 207 -208 207 -210 207 -416 207 -208 415 -418 415 -416 417 -416 207 -210 207 -208 415 -416 209 -208 415 -208 209 -416 207 -208 207 -208 209 -208 207 -208 207 -210 207 -208 415 -208 207 -210 207 -416 207 -210 207 -208 205 -208 209 -208 415 -208 209 -416 417 -416 207 -208 417 -416 415 -208 209 -208 207 -416 207 -208 417 -208 207 -418 415 -208 207 -210 207 -208 207 -208 207 -208 209 -208 207 -416 209 -208 415 -416 417 -208 207 -416 209 -208 207 -208 415 -208 209 -208 207 -208 207 -210 207 -206 207 -418 415 -416 417 -208 207 -418 207 -208 415 -208 207 -418 415 -418 207 -208 207 -208 207 -208 417 -208 207 -418 207 -208 207 -208 415 -208 207 -418 207 -208 207 -210 415 -418 415 -208 207 -210 207 -416 417 -208 207 -414 209 -208 207 -208 417 -208 207 -208 209 -416 207 -208 747 -276 175 -190 143 -202 293 -242 277 -205 103 -426 109 -214 51 -52 135 -244 109 -112 223 -76 149 -168 121 -445 305 -102 101 -344 191 -187 53 -132 215 -478 239 -132 137 -112 333 -246 81 -246 81 -210 155 -138 135 -268 51 -268 79 -104 81 -366 113 -192 77 -382 75 -150 75 -124 282 -209 105 -381 105 -110 523 -182 77 -102 123 -168 97 -144 125 -182 151 -218 51 -180 95 -339 53 -54 79 -108 157 -1350 394 -96 71 -80 361 -126 145 -310 79 -104 79 -182 103 -110 115 -468 73 -72 95 -76 73 -214 133 -312 191 -54 386 -172 163 -256 75 -124 123 -148 147 -146 73 -176 103 -286 401 -132 79 -140 325 -102 77 -134 107 -430 197 -52 153 -721 205 -390 291 -318 243 -218 153 -282 135 -282 261 -154 225 -150 249 -194 427 -80 261 -612 175 -446 323 -80 187 -270 175 -124 99 -414 79 -424 139 -310 107 -350 267 -212 239 -389 145 -100 103 -80 101 -232 77 -207 155 -54 105 -236 101 -280 77 -138 247 -773 167 -170 57 -162 311 -264 203 -100 77 -184 223 -116 199 -710 161 -136 107 -198 165 -429 107 -268 107 -170 141 -140 195 -574 83 -758 209 -426 81 -212 71 -122 71 -344 127 -84 57 -248 79 -134 125 -144 191 -96 171 -72 71 -208 75 -320 121 -72 119 -388 157 -240 492 -540 164 -196 143 -692 53 -80 109 -110 81 -104 242 -338 171 -440 79 -248 113 -501 165 -82 135 -56 115 -308 107 -400 293 -286 337 -350 219 -554 51 -110 111 -200 85 -550 73 -749 105 -766 55 -218 55 -388 103 -1120 51 -937 99 -126 51 -126 73 -294 51 -240 105 -4634 55 -11507 79 -24839 77 -15207 53 -112 57 -826 101 -27414 121 -22931
RAW_Data: 53 -5250 83 -8124 73 -8480 101 -14351 55 -616 73 -8023 53 -39675 53 -5785 81 -30062 53 -46124 71 -17422 75 -16448 55 -894 53 -4894 81 -6404 135 -10767 71 -14220 51 -14102 55 -1190 51 -1826 83 -480 81 -5010 51 -6102 1865 -130 259 -182 235 -182 233 -182 235 -180 207 -210 207 -208 207 -208 209 -208 207 -208 209 -206 207 -208 207 -210 207 -208 207 -208 209 -208 207 -208 1667 -416 415 -418 415 -210 413 -418 415 -416 209 -208 205 -208 207 -210 207 -208 207 -208 209 -208 415 -210 207 -208 207 -418 207 -208 415 -418 207 -206 207 -210 207 -208 415 -418 207 -208 417 -416 417 -416 207 -208 415 -416 417 -416 415 -418 415 -210 207 -416 415 -208 209 -416 207 -208 417 -416 209 -206 417 -416 209 -208 205 -208 417 -416 417 -416 415 -418 207 -208 207 -208 207 -208 207 -208 209 -208 415 -210 207 -416 417 -208 207 -208 207 -210 207 -416 207 -208 417 -416 415 -416 417 -416 207 -210 207 -206 417 -416 209 -208 415 -208 209 -416 207 -208 207 -208 207 -208 207 -210 207 -208 207 -208 417 -208 207 -210 207 -416 207 -208 207 -208 209 -208 207 -208 417 -208 207 -418 413 -418 207 -208 415 -418 415 -208 207 -210 207 -416 209 -208 439 -182 209 -416 415 -210 207 -208 207 -208 209 -208 207 -208 209 -208 207 -416 207 -208 415 -418 415 -208 207 -418 207 -208 207 -210 415 -208 209 -208 207 -208 207 -208 207 -208 209 -416 415 -416 417 -208 207 -418 207 -208 415 -208 207 -418 415 -418 207 -208 207 -208 207 -208 417 -208 207 -418 207 -206 207 -208 417 -208 207 -418 207 -208 207 -210 415 -416 415 -210 207 -208 207 -418 415 -208 207 -418 207 -206 207 -210 415 -208 207 -210 207 -416 209 -208 1375 -596 79 -80 323 -166 199 -220 79 -186 187 -223 217 -148 99 -76 119 -268 103 -178 283 -52 319 -246 225 -128 169 -162 107 -106 53 -136 161 -708 445 -238 101 -124 143 -98 414 -114 111 -56 53 -108 263 -468 79 -256 135 -108 323 -188 105 -272 83 -86 75 -155 107 -164 369 -114 137 -108 135 -513 179 -148 161 -216 79 -54 133 -168 135 -313 195 -136 258 -294 103 -78 219 -98 121 -619 75 -384 77 -147 199 -459 75 -102 127 -222 667 -160 259 -130 53 -78 51 -130 121 -276 133 -160 153 -142 147 -180 131 -170 85 -84 241 -207 125 -176 269 -452 562 -256 139 -610 113 -144 255 -272 419 -136 227 -82 243 -86 279 -290 710 -546 51 -106 133 -194 251 -166 199 -202 163 -160 183 -86 495 -84 301 -212 255 -124 449 -256 73 -494
RAW_Data: 101 -274 725 -295 111 -306 1001 -76 307 -96 127 -476 1005 -166 135 -272 75 -156 157 -114 55 -84 53 -394 127 -54 221 -56 55 -110 79 -134 77 -214 157 -102 251 -116 141 -382 103 -304 167 -72 295 -228 105 -279 311 -302 57 -86 103 -486 101 -590 283 -158 107 -114 57 -542 81 -80 195 -190 157 -210 183 -1081 77 -52 77 -82 345 -216 79 -210 101 -362 79 -192 245 -170 215 -130 57 -336 693 -142 356 -108 337 -557 137 -160 99 -522 55 -108 199 -714 485 -74 73 -78 271 -84 351 -514 97 -98 75 -206 51 -104 97 -72 534 -290 213 -277 53 -106 181 -54 105 -132 133 -244 83 -136 199 -298 73 -126 529 -194 51 -560 73 -340 51 -286 81 -106 97 -72 177 -244 337 -424 79 -164 139 -436 139 -84 81 -270 107 -106 75 -130 135 -84 83 -164 53 -188 215 -54 161 -58 113 -446 301 -304 51 -164 215 -216 163 -665 123 -311 275 -76 399 -164 113 -96 103 -102 127 -174 267 -244 147 -296 77 -106 131 -532 135 -142 71 -298 329 -992 105 -456 348 -190 113 -920 53 -136 81 -110 109 -238 79 -780 111 -56 151 -78 347 -991 101 -546 217 -488 103 -412 101 -98 203 -258 173 -128 520 -100 143 -120 97 -132 79 -172 143 -244 51 -150 101 -216 173 -82 609 -108 105 -170 137 -214 259 -78 336 -1512 195 -168 341 -116 167 -56 53 -78 51 -154 51 -52 53 -282 51 -628 185 -154 73 -96 101 -184 55 -226 219 -156 103 -330 79 -146 71 -192 71 -144 95 -96 415 -74 179 -306 165 -82 55 -252 107 -112 85 -274 55 -318 141 -410 55 -86 221 -358 83 -110 53 -346 131 -460 121 -204 51 -470 53 -760 119 -192 97 -218 221 -654 131 -2268 73 -10119 83 -5418 77 -21747 57 -21352 55 -7803 73 -26982 57 -1488 83 -11525 51 -36422 57 -2518 83 -830 57 -1992 53 -16422 57 -11071 57 -30333 53 -29789 57 -20172 53 -5084 73 -42452 51 -32675 53 -13515 73 -3209 107 -11190 75 -5028 51 -640 79 -10332 125 -2304 81 -7548 83 -47108 97 -10065 71 -9242 71 -23984 81 -12781 57 -2756 83 -13518 51 -20342 73 -7060 51 -7332 51 -1828 71 -20154 73 -2180 51 -13482

View File

@@ -0,0 +1,687 @@
#include "hormann_bisecur.h"
#include <lib/flipper_format/flipper_format_i.h>
#include <lib/toolbox/manchester_decoder.h>
#include <lib/toolbox/manchester_encoder.h>
#include <lib/toolbox/stream/stream.h>
#include "../blocks/const.h"
#include "../blocks/decoder.h"
#include "../blocks/encoder.h"
#include "../blocks/generic.h"
#include "../blocks/math.h"
#define TAG "SubGhzProtocolHormannBiSecur"
static const SubGhzBlockConst subghz_protocol_hormann_bisecur_const = {
.te_short = 208,
.te_long = 416,
.te_delta = 104,
.min_count_bit_for_found = 176,
};
struct SubGhzProtocolDecoderHormannBiSecur {
SubGhzProtocolDecoderBase base;
SubGhzBlockDecoder decoder;
SubGhzBlockGeneric generic;
uint8_t sync_cnt;
ManchesterState manchester_saved_state;
uint8_t type;
uint8_t data[22];
uint8_t crc;
};
struct SubGhzProtocolEncoderHormannBiSecur {
SubGhzProtocolEncoderBase base;
SubGhzProtocolBlockEncoder encoder;
SubGhzBlockGeneric generic;
uint8_t data[22];
};
typedef enum {
HormannBiSecurDecoderStepReset = 0,
HormannBiSecurDecoderStepFoundPreambleAlternatingShort,
HormannBiSecurDecoderStepFoundPreambleHighVeryLong,
HormannBiSecurDecoderStepFoundPreambleAlternatingLong,
HormannBiSecurDecoderStepFoundData,
} HormannBiSecurDecoderStep;
const SubGhzProtocolDecoder subghz_protocol_hormann_bisecur_decoder = {
.alloc = subghz_protocol_decoder_hormann_bisecur_alloc,
.free = subghz_protocol_decoder_hormann_bisecur_free,
.feed = subghz_protocol_decoder_hormann_bisecur_feed,
.reset = subghz_protocol_decoder_hormann_bisecur_reset,
.get_hash_data = NULL,
.get_hash_data_long = subghz_protocol_decoder_hormann_bisecur_get_hash_data,
.serialize = subghz_protocol_decoder_hormann_bisecur_serialize,
.deserialize = subghz_protocol_decoder_hormann_bisecur_deserialize,
.get_string = subghz_protocol_decoder_hormann_bisecur_get_string,
};
const SubGhzProtocolEncoder subghz_protocol_hormann_bisecur_encoder = {
.alloc = subghz_protocol_encoder_hormann_bisecur_alloc,
.free = subghz_protocol_encoder_hormann_bisecur_free,
.deserialize = subghz_protocol_encoder_hormann_bisecur_deserialize,
.stop = subghz_protocol_encoder_hormann_bisecur_stop,
.yield = subghz_protocol_encoder_hormann_bisecur_yield,
};
const SubGhzProtocol subghz_protocol_hormann_bisecur = {
.name = SUBGHZ_PROTOCOL_HORMANN_BISECUR_NAME,
.type = SubGhzProtocolTypeDynamic,
.flag = SubGhzProtocolFlag_868 | SubGhzProtocolFlag_FM | SubGhzProtocolFlag_Decodable |
SubGhzProtocolFlag_Load | SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
.decoder = &subghz_protocol_hormann_bisecur_decoder,
.encoder = &subghz_protocol_hormann_bisecur_encoder,
};
// there is a problem with the function in lib/toolbox/manchester_decoder, so it is reimplemented
// thanks to CodeAllNight (https://github.com/jamisonderek) for sharing his fixed version
static const ManchesterState manchester_reset_state = ManchesterStateMid1;
bool manchester_advance_alt(
ManchesterState state,
ManchesterEvent event,
ManchesterState* next_state,
bool* data) {
bool result = false;
ManchesterState new_state = manchester_reset_state;
if(event == ManchesterEventReset) {
new_state = manchester_reset_state;
} else if(state == ManchesterStateStart1) {
if(event == ManchesterEventShortLow) {
new_state = ManchesterStateMid1;
result = true;
if(data) *data = false;
} else if(event == ManchesterEventLongLow) {
new_state = ManchesterStateStart0;
result = true;
if(data) *data = false;
} else {
new_state = manchester_reset_state;
}
} else if(state == ManchesterStateMid1) {
if(event == ManchesterEventShortHigh) {
new_state = ManchesterStateStart1;
} else if(event == ManchesterEventShortLow) {
new_state = ManchesterStateStart0;
} else {
new_state = manchester_reset_state;
}
} else if(state == ManchesterStateStart0) {
if(event == ManchesterEventShortHigh) {
new_state = ManchesterStateMid0;
result = true;
if(data) *data = true;
} else if(event == ManchesterEventLongHigh) {
new_state = ManchesterStateStart1;
result = true;
if(data) *data = true;
} else {
new_state = manchester_reset_state;
}
} else if(state == ManchesterStateMid0) {
if(event == ManchesterEventShortLow) {
new_state = ManchesterStateStart0;
} else if(event == ManchesterEventShortHigh) {
new_state = ManchesterStateStart1;
} else {
new_state = manchester_reset_state;
}
}
*next_state = new_state;
return result;
}
/**
* Calculates the next LevelDuration in an upload
* @param result ManchesterEncoderResult
* @return LevelDuration
*/
static LevelDuration
subghz_protocol_encoder_hormann_bisecur_add_duration_to_upload(ManchesterEncoderResult result);
/**
* Calculates CRC from the raw demodulated bytes
* @param instance Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
*/
static uint8_t
subghz_protocol_decoder_hormann_bisecur_crc(SubGhzProtocolDecoderHormannBiSecur* instance);
/**
* Checks if the raw demodulated data has correct CRC
* @param instance Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
* @return if CRC is valid or not
*/
static bool subghz_protocol_decoder_hormann_bisecur_check_crc(
SubGhzProtocolDecoderHormannBiSecur* instance);
/**
* Add the next bit to the decoding result
* @param instance Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
* @param level Level of the next bit
*/
static void subghz_protocol_decoder_hormann_bisecur_add_bit(
SubGhzProtocolDecoderHormannBiSecur* instance,
bool level);
/**
* Parses the raw data into separate fields
* @param instance Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
*/
static void
subghz_protocol_hormann_bisecur_parse_data(SubGhzProtocolDecoderHormannBiSecur* instance);
void* subghz_protocol_encoder_hormann_bisecur_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolEncoderHormannBiSecur* instance =
malloc(sizeof(SubGhzProtocolEncoderHormannBiSecur));
instance->base.protocol = &subghz_protocol_hormann_bisecur;
instance->generic.protocol_name = instance->base.protocol->name;
// TODO insert 504.3ms carrier off delay between repeats
// subghz framework does not support this for FM encoders
// sending either frequency constantly also seems to work
// instance->encoder.repeat = 3; //original remote does 3 repeats
instance->encoder.repeat = 1;
instance->encoder.size_upload =
21 * 2 + 2 * 2 + subghz_protocol_hormann_bisecur_const.min_count_bit_for_found * 2 + 1;
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
instance->encoder.is_running = false;
return instance;
}
void subghz_protocol_encoder_hormann_bisecur_free(void* context) {
furi_assert(context);
SubGhzProtocolEncoderHormannBiSecur* instance = context;
free(instance->encoder.upload);
free(instance);
}
/**
* Generating an upload from data.
* @param instance Pointer to a SubGhzProtocolEncoderHormannBiSecur instance
* @return true On success
*/
static bool subghz_protocol_encoder_hormann_bisecur_get_upload(
SubGhzProtocolEncoderHormannBiSecur* instance) {
furi_assert(instance);
size_t index = 0;
ManchesterEncoderState enc_state;
manchester_encoder_reset(&enc_state);
ManchesterEncoderResult result;
uint32_t duration_short = (uint32_t)subghz_protocol_hormann_bisecur_const.te_short;
uint32_t duration_long = (uint32_t)subghz_protocol_hormann_bisecur_const.te_long;
uint32_t duration_half_short = duration_short / 2;
// Send preamble
for(uint8_t i = 0; i < 21; i++) {
uint32_t duration_low = duration_short;
uint32_t duration_high = duration_short;
if(i == 0) {
duration_low += duration_half_short;
}
if(i == 20) {
duration_high = duration_long * 4;
}
instance->encoder.upload[index++] = level_duration_make(false, duration_low);
instance->encoder.upload[index++] = level_duration_make(true, duration_high);
}
for(uint8_t i = 0; i < 2; i++) {
instance->encoder.upload[index++] = level_duration_make(false, duration_long);
instance->encoder.upload[index++] = level_duration_make(true, duration_long);
}
// Send key data
uint8_t max_byte_index = instance->generic.data_count_bit / 8 - 1;
for(uint8_t i = instance->generic.data_count_bit; i > 0; i--) {
uint8_t bit_index = i - 1;
uint8_t byte_index = max_byte_index - bit_index / 8;
bool bit_is_set = !bit_read(instance->data[byte_index], bit_index & 0x07);
if(!manchester_encoder_advance(&enc_state, bit_is_set, &result)) {
instance->encoder.upload[index++] =
subghz_protocol_encoder_hormann_bisecur_add_duration_to_upload(result);
manchester_encoder_advance(&enc_state, bit_is_set, &result);
}
instance->encoder.upload[index++] =
subghz_protocol_encoder_hormann_bisecur_add_duration_to_upload(result);
}
LevelDuration last_level_duration =
subghz_protocol_encoder_hormann_bisecur_add_duration_to_upload(
manchester_encoder_finish(&enc_state));
last_level_duration.duration += duration_short + duration_half_short;
instance->encoder.upload[index++] = last_level_duration;
instance->encoder.size_upload = index;
return true;
}
SubGhzProtocolStatus subghz_protocol_encoder_hormann_bisecur_deserialize(
void* context,
FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolEncoderHormannBiSecur* instance = context;
SubGhzProtocolStatus ret =
subghz_block_generic_deserialize(&instance->generic, flipper_format);
if(ret != SubGhzProtocolStatusOk) {
return ret;
}
// Generic key is too small, so we reset it and rewind to get real, longer, data
instance->generic.data = 0;
if(instance->generic.data_count_bit !=
subghz_protocol_hormann_bisecur_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
return SubGhzProtocolStatusErrorValueBitCount;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
return SubGhzProtocolStatusErrorParserOthers;
}
size_t key_length = instance->generic.data_count_bit / 8;
if(!flipper_format_read_hex(flipper_format, "Key", instance->data, key_length)) {
FURI_LOG_E(TAG, "Unable to read Key in encoder");
return SubGhzProtocolStatusErrorParserKey;
}
// optional parameter
flipper_format_read_uint32(flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
if(!subghz_protocol_encoder_hormann_bisecur_get_upload(instance)) {
return SubGhzProtocolStatusErrorEncoderGetUpload;
}
instance->encoder.is_running = true;
return SubGhzProtocolStatusOk;
}
void subghz_protocol_encoder_hormann_bisecur_stop(void* context) {
SubGhzProtocolEncoderHormannBiSecur* instance = context;
instance->encoder.is_running = false;
}
LevelDuration subghz_protocol_encoder_hormann_bisecur_yield(void* context) {
SubGhzProtocolEncoderHormannBiSecur* instance = context;
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
instance->encoder.is_running = false;
return level_duration_reset();
}
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
if(++instance->encoder.front == instance->encoder.size_upload) {
instance->encoder.repeat--;
instance->encoder.front = 0;
}
return ret;
}
void* subghz_protocol_decoder_hormann_bisecur_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
SubGhzProtocolDecoderHormannBiSecur* instance =
malloc(sizeof(SubGhzProtocolDecoderHormannBiSecur));
instance->base.protocol = &subghz_protocol_hormann_bisecur;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}
void subghz_protocol_decoder_hormann_bisecur_free(void* context) {
furi_assert(context);
SubGhzProtocolDecoderHormannBiSecur* instance = context;
free(instance);
}
void subghz_protocol_decoder_hormann_bisecur_reset(void* context) {
furi_assert(context);
SubGhzProtocolDecoderHormannBiSecur* instance = context;
instance->decoder.parser_step = HormannBiSecurDecoderStepReset;
memset(instance->data, 0, 22);
instance->generic.data_count_bit = 0;
instance->manchester_saved_state = 0;
}
void subghz_protocol_decoder_hormann_bisecur_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
SubGhzProtocolDecoderHormannBiSecur* instance = context;
uint32_t duration_short = (uint32_t)subghz_protocol_hormann_bisecur_const.te_short;
uint32_t duration_long = (uint32_t)subghz_protocol_hormann_bisecur_const.te_long;
uint32_t duration_delta = (uint32_t)subghz_protocol_hormann_bisecur_const.te_delta;
uint32_t duration_half_short = duration_short / 2;
ManchesterEvent event = ManchesterEventReset;
switch(instance->decoder.parser_step) {
case HormannBiSecurDecoderStepReset:
if(!level &&
DURATION_DIFF(duration, duration_short + duration_half_short) < duration_delta) {
instance->decoder.parser_step = HormannBiSecurDecoderStepFoundPreambleAlternatingShort;
}
break;
case HormannBiSecurDecoderStepFoundPreambleAlternatingShort:
if(DURATION_DIFF(duration, duration_short) < duration_delta) {
// stay on the same step, the pattern repeats around 21 times
break;
}
if(level && DURATION_DIFF(duration, duration_long * 4) < duration_delta) {
instance->decoder.parser_step = HormannBiSecurDecoderStepFoundPreambleHighVeryLong;
break;
}
instance->decoder.parser_step = HormannBiSecurDecoderStepReset;
break;
case HormannBiSecurDecoderStepFoundPreambleHighVeryLong:
if(!level && DURATION_DIFF(duration, duration_long) < duration_delta) {
instance->sync_cnt = 3;
instance->decoder.parser_step = HormannBiSecurDecoderStepFoundPreambleAlternatingLong;
break;
}
instance->decoder.parser_step = HormannBiSecurDecoderStepReset;
break;
case HormannBiSecurDecoderStepFoundPreambleAlternatingLong:
if(level == (instance->sync_cnt-- & 1) &&
DURATION_DIFF(duration, duration_long) < duration_delta) {
if(!instance->sync_cnt) {
manchester_advance_alt(
instance->manchester_saved_state,
event,
&instance->manchester_saved_state,
NULL);
instance->decoder.parser_step = HormannBiSecurDecoderStepFoundData;
}
// stay on the same step, or advance to the next if enough transitions are found
break;
}
instance->decoder.parser_step = HormannBiSecurDecoderStepReset;
break;
case HormannBiSecurDecoderStepFoundData:
if(DURATION_DIFF(duration, duration_short) < duration_delta ||
(
// the last bit can be arbitrary long, but it is parsed as a short
instance->generic.data_count_bit ==
subghz_protocol_hormann_bisecur_const.min_count_bit_for_found - 1 &&
duration > duration_short)) {
event = !level ? ManchesterEventShortHigh : ManchesterEventShortLow;
}
if(DURATION_DIFF(duration, duration_long) < duration_delta) {
event = !level ? ManchesterEventLongHigh : ManchesterEventLongLow;
}
if(event == ManchesterEventReset) {
subghz_protocol_decoder_hormann_bisecur_reset(instance);
} else {
bool new_level;
if(manchester_advance_alt(
instance->manchester_saved_state,
event,
&instance->manchester_saved_state,
&new_level)) {
subghz_protocol_decoder_hormann_bisecur_add_bit(instance, new_level);
}
}
break;
}
}
uint32_t subghz_protocol_decoder_hormann_bisecur_get_hash_data(void* context) {
furi_assert(context);
SubGhzProtocolDecoderHormannBiSecur* instance = context;
union {
uint32_t full;
uint8_t split[4];
} hash = {0};
size_t key_length = instance->generic.data_count_bit / 8;
for(size_t i = 0; i < key_length; i++) {
hash.split[i % sizeof(hash)] ^= instance->data[i];
}
return hash.full;
}
SubGhzProtocolStatus subghz_protocol_decoder_hormann_bisecur_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
SubGhzProtocolDecoderHormannBiSecur* instance = context;
SubGhzProtocolStatus res = SubGhzProtocolStatusError;
do {
res = subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
if(res != SubGhzProtocolStatusOk) {
break;
}
// Generic key is too small, so it writes empty and we update here with real, longer, data
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
res = SubGhzProtocolStatusErrorParserOthers;
break;
}
uint16_t key_length = instance->generic.data_count_bit / 8;
if(!flipper_format_update_hex(flipper_format, "Key", instance->data, key_length)) {
FURI_LOG_E(TAG, "Unable to update Key");
res = SubGhzProtocolStatusErrorParserKey;
break;
}
} while(false);
return res;
}
SubGhzProtocolStatus subghz_protocol_decoder_hormann_bisecur_deserialize(
void* context,
FlipperFormat* flipper_format) {
furi_assert(context);
SubGhzProtocolDecoderHormannBiSecur* instance = context;
SubGhzProtocolStatus ret =
subghz_block_generic_deserialize(&instance->generic, flipper_format);
if(ret != SubGhzProtocolStatusOk) {
return ret;
}
// Generic key is too small, so we reset it and rewind to get real, longer, data
instance->generic.data = 0;
if(instance->generic.data_count_bit !=
subghz_protocol_hormann_bisecur_const.min_count_bit_for_found) {
FURI_LOG_E(TAG, "Wrong number of bits in key");
return SubGhzProtocolStatusErrorValueBitCount;
}
if(!flipper_format_rewind(flipper_format)) {
FURI_LOG_E(TAG, "Rewind error");
return SubGhzProtocolStatusErrorParserOthers;
}
size_t key_length = instance->generic.data_count_bit / 8;
if(!flipper_format_read_hex(flipper_format, "Key", instance->data, key_length)) {
FURI_LOG_E(TAG, "Unable to read Key in decoder");
return SubGhzProtocolStatusErrorParserKey;
}
subghz_protocol_hormann_bisecur_parse_data(instance);
return SubGhzProtocolStatusOk;
}
void subghz_protocol_decoder_hormann_bisecur_get_string(void* context, FuriString* output) {
furi_assert(context);
SubGhzProtocolDecoderHormannBiSecur* instance = context;
bool valid_crc = subghz_protocol_decoder_hormann_bisecur_check_crc(instance);
furi_string_cat_printf(
output,
"%s\r\n"
"%dbit CRC:0x%02X %s\r\n"
"Type:0x%02X Sn:0x%08lX\r\n"
"Key:%016llX\r\n"
"Key:%016llX\r\n",
instance->generic.protocol_name,
instance->generic.data_count_bit,
instance->crc,
valid_crc ? "OK" : "WRONG",
instance->type,
instance->generic.serial,
instance->generic.data,
instance->generic.data_2);
}
static LevelDuration subghz_protocol_encoder_hormann_bisecur_add_duration_to_upload(
ManchesterEncoderResult result) {
LevelDuration data = {.duration = 0, .level = 0};
switch(result) {
case ManchesterEncoderResultShortLow:
data.duration = subghz_protocol_hormann_bisecur_const.te_short;
data.level = false;
break;
case ManchesterEncoderResultLongLow:
data.duration = subghz_protocol_hormann_bisecur_const.te_long;
data.level = false;
break;
case ManchesterEncoderResultLongHigh:
data.duration = subghz_protocol_hormann_bisecur_const.te_long;
data.level = true;
break;
case ManchesterEncoderResultShortHigh:
data.duration = subghz_protocol_hormann_bisecur_const.te_short;
data.level = true;
break;
default:
furi_crash("SubGhz: ManchesterEncoderResult is incorrect.");
break;
}
return level_duration_make(data.level, data.duration);
}
static uint8_t
subghz_protocol_decoder_hormann_bisecur_crc(SubGhzProtocolDecoderHormannBiSecur* instance) {
furi_assert(instance);
switch(instance->type) {
case 0x50:
return ~(subghz_protocol_blocks_crc8(instance->data + 1, 20, 0x07, 0x00) ^ 0x55);
case 0x70:
return subghz_protocol_blocks_crc8le(instance->data, 21, 0x07, 0xFF);
}
FURI_LOG_E(TAG, "Unknown type 0x%02X", instance->type);
return 0;
}
static bool subghz_protocol_decoder_hormann_bisecur_check_crc(
SubGhzProtocolDecoderHormannBiSecur* instance) {
furi_assert(instance);
if(instance->type != 0x50 && instance->type != 0x70) {
FURI_LOG_W(TAG, "Unknown type 0x%02X", instance->type);
return false;
}
return subghz_protocol_decoder_hormann_bisecur_crc(instance) == instance->crc;
}
static void
subghz_protocol_hormann_bisecur_parse_data(SubGhzProtocolDecoderHormannBiSecur* instance) {
furi_assert(instance);
instance->type = instance->data[0];
instance->generic.serial = 0;
for(uint8_t i = 1; i < 5; i++) {
instance->generic.serial = instance->generic.serial << 8 | instance->data[i];
}
instance->generic.data = 0;
for(uint8_t i = 5; i < 13; i++) {
instance->generic.data = instance->generic.data << 8 | instance->data[i];
}
instance->generic.data_2 = 0;
for(uint8_t i = 13; i < 21; i++) {
instance->generic.data_2 = instance->generic.data_2 << 8 | instance->data[i];
}
instance->crc = instance->data[21];
}
static void subghz_protocol_decoder_hormann_bisecur_add_bit(
SubGhzProtocolDecoderHormannBiSecur* instance,
bool level) {
furi_assert(instance);
if(instance->generic.data_count_bit >=
subghz_protocol_hormann_bisecur_const.min_count_bit_for_found) {
return;
}
if(level) {
uint8_t byte_index = instance->generic.data_count_bit / 8;
uint8_t bit_index = instance->generic.data_count_bit % 8;
instance->data[byte_index] |= 1 << (7 - bit_index);
}
instance->generic.data_count_bit++;
if(instance->generic.data_count_bit >=
subghz_protocol_hormann_bisecur_const.min_count_bit_for_found) {
if(instance->base.callback) {
instance->base.callback(&instance->base, instance->base.context);
} else {
subghz_protocol_decoder_hormann_bisecur_reset(instance);
}
}
}

View File

@@ -0,0 +1,111 @@
#pragma once
#include "base.h"
#define SUBGHZ_PROTOCOL_HORMANN_BISECUR_NAME "Hormann BiSecur"
typedef struct SubGhzProtocolDecoderHormannBiSecur SubGhzProtocolDecoderHormannBiSecur;
typedef struct SubGhzProtocolEncoderHormannBiSecur SubGhzProtocolEncoderHormannBiSecur;
extern const SubGhzProtocolDecoder subghz_protocol_hormann_bisecur_decoder;
extern const SubGhzProtocolEncoder subghz_protocol_hormann_bisecur_encoder;
extern const SubGhzProtocol subghz_protocol_hormann_bisecur;
/**
* Allocate SubGhzProtocolEncoderHormannBiSecur.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolEncoderHormannBiSecur* pointer to a SubGhzProtocolEncoderHormannBiSecur instance
*/
void* subghz_protocol_encoder_hormann_bisecur_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolEncoderHormannBiSecur.
* @param context Pointer to a SubGhzProtocolEncoderHormannBiSecur instance
*/
void subghz_protocol_encoder_hormann_bisecur_free(void* context);
/**
* Deserialize and generating an upload to send.
* @param context Pointer to a SubGhzProtocolEncoderHormannBiSecur instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus subghz_protocol_encoder_hormann_bisecur_deserialize(
void* context,
FlipperFormat* flipper_format);
/**
* Forced transmission stop.
* @param context Pointer to a SubGhzProtocolEncoderHormannBiSecur instance
*/
void subghz_protocol_encoder_hormann_bisecur_stop(void* context);
/**
* Getting the level and duration of the upload to be loaded into DMA.
* @param context Pointer to a SubGhzProtocolEncoderHormannBiSecur instance
* @return LevelDuration
*/
LevelDuration subghz_protocol_encoder_hormann_bisecur_yield(void* context);
/**
* Allocate SubGhzProtocolDecoderHormannBiSecur.
* @param environment Pointer to a SubGhzEnvironment instance
* @return SubGhzProtocolDecoderHormannBiSecur* pointer to a SubGhzProtocolDecoderHormannBiSecur instance
*/
void* subghz_protocol_decoder_hormann_bisecur_alloc(SubGhzEnvironment* environment);
/**
* Free SubGhzProtocolDecoderHormannBiSecur.
* @param context Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
*/
void subghz_protocol_decoder_hormann_bisecur_free(void* context);
/**
* Reset decoder SubGhzProtocolDecoderHormannBiSecur.
* @param context Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
*/
void subghz_protocol_decoder_hormann_bisecur_reset(void* context);
/**
* Parse a raw sequence of levels and durations received from the air.
* @param context Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
* @param level Signal level true-high false-low
* @param duration Duration of this level in, us
*/
void subghz_protocol_decoder_hormann_bisecur_feed(void* context, bool level, uint32_t duration);
/**
* Getting the hash sum of the last randomly received parcel.
* @param context Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
* @return hash Hash sum
*/
uint32_t subghz_protocol_decoder_hormann_bisecur_get_hash_data(void* context);
/**
* Serialize data SubGhzProtocolDecoderHormannBiSecur.
* @param context Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
* @param flipper_format Pointer to a FlipperFormat instance
* @param preset The modulation on which the signal was received, SubGhzRadioPreset
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_hormann_bisecur_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset);
/**
* Deserialize data SubGhzProtocolDecoderHormannBiSecur.
* @param context Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
* @param flipper_format Pointer to a FlipperFormat instance
* @return status
*/
SubGhzProtocolStatus subghz_protocol_decoder_hormann_bisecur_deserialize(
void* context,
FlipperFormat* flipper_format);
/**
* Getting a textual representation of the received data.
* @param context Pointer to a SubGhzProtocolDecoderHormannBiSecur instance
* @param output Resulting text
*/
void subghz_protocol_decoder_hormann_bisecur_get_string(void* context, FuriString* output);

View File

@@ -68,8 +68,9 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = {
&subghz_protocol_bin_raw,
&subghz_protocol_mastercode,
&subghz_protocol_x10,
&subghz_protocol_hormann_bisecur,
};
const SubGhzProtocolRegistry subghz_protocol_registry = {
.items = subghz_protocol_registry_items,
.size = COUNT_OF(subghz_protocol_registry_items)};
.size = COUNT_OF(subghz_protocol_registry_items)};

View File

@@ -69,3 +69,4 @@
#include "bin_raw.h"
#include "mastercode.h"
#include "x10.h"
#include "hormann_bisecur.h"