mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-13 14:38:35 -07:00
Merge branch 'dev' of https://github.com/Flipper-XFW/Xtreme-Firmware into xfw-new-app-system
This commit is contained in:
@@ -221,7 +221,7 @@ If you like what you're seeing, **please consider donating to us**. We won't eve
|
|||||||
|
|
||||||
- **[Patreon](https://patreon.com/crazyco)**: ❤️ Account needed, subscription with perks across my entire org.
|
- **[Patreon](https://patreon.com/crazyco)**: ❤️ Account needed, subscription with perks across my entire org.
|
||||||
- **[Wire-transfer](https://bunq.me/ClaraK)**: No account needed, one-time
|
- **[Wire-transfer](https://bunq.me/ClaraK)**: No account needed, one-time
|
||||||
- **[Paypal](https://paypal.me/RdX2020)**: Account needed, one-time
|
- **[Paypal](https://paypal.me/ClaraCrazy)**: Account needed, one-time
|
||||||
- **[ko-fi](https://ko-fi.com/cynthialabs)**: No account needed, one-time
|
- **[ko-fi](https://ko-fi.com/cynthialabs)**: No account needed, one-time
|
||||||
- **Monero**: `41kyWeeoVdK4quzQ4M9ikVGs6tCQCLfdx8jLExTNsAu2SF1QAyDqRdjfGM6EL8L9NpXwt89HJeAoGf1aoArk7nDr4AMMV4T`
|
- **Monero**: `41kyWeeoVdK4quzQ4M9ikVGs6tCQCLfdx8jLExTNsAu2SF1QAyDqRdjfGM6EL8L9NpXwt89HJeAoGf1aoArk7nDr4AMMV4T`
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ static void subghz_scene_add_to_history_callback(
|
|||||||
SubGhz* subghz = context;
|
SubGhz* subghz = context;
|
||||||
|
|
||||||
// The check can be moved to /lib/subghz/receiver.c, but may result in false positives
|
// The check can be moved to /lib/subghz/receiver.c, but may result in false positives
|
||||||
if((decoder_base->protocol->flag & subghz->ignore_filter) == 0) {
|
if((decoder_base->protocol->filter & subghz->ignore_filter) == 0) {
|
||||||
SubGhzHistory* history = subghz->history;
|
SubGhzHistory* history = subghz->history;
|
||||||
FuriString* item_name = furi_string_alloc();
|
FuriString* item_name = furi_string_alloc();
|
||||||
FuriString* item_time = furi_string_alloc();
|
FuriString* item_time = furi_string_alloc();
|
||||||
|
|||||||
@@ -3843,3 +3843,172 @@ C670A9AD6066
|
|||||||
722538817225
|
722538817225
|
||||||
# 1k millenium hotels
|
# 1k millenium hotels
|
||||||
132F641C948B
|
132F641C948B
|
||||||
|
############### from https://github.com/Stepzor11/NFC_keys ###############
|
||||||
|
CCCE24102003
|
||||||
|
49414556EF4D
|
||||||
|
1ABC15934F5A
|
||||||
|
0AD6B7E37183
|
||||||
|
C27F5C1A9C2B
|
||||||
|
7C9FB8474242
|
||||||
|
4663ACD2FFFF
|
||||||
|
FF75AFDA5A3C
|
||||||
|
4C44200BC9C5
|
||||||
|
3A4C47757B07
|
||||||
|
18AB07270506
|
||||||
|
A2CA48CA4C05
|
||||||
|
7B173A4E4976
|
||||||
|
8A55194F6587
|
||||||
|
4844426F6E69
|
||||||
|
6A0D531DA1A7
|
||||||
|
9B7C25052FC3
|
||||||
|
193DFE0FA18E
|
||||||
|
6CA761AB6CA7
|
||||||
|
4BB29463DC29
|
||||||
|
00B70875AF1D
|
||||||
|
20525276F443
|
||||||
|
3515AE068CAD
|
||||||
|
5A7D87876EA8
|
||||||
|
81CC25EBBB6A
|
||||||
|
9A677289564D
|
||||||
|
0A1B6C50E04E
|
||||||
|
F3A524B7A7B3
|
||||||
|
B133A4D48757
|
||||||
|
558AAD64EB5B
|
||||||
|
260480290483
|
||||||
|
1417E5671417
|
||||||
|
32F093536677
|
||||||
|
C9BE49675FE4
|
||||||
|
57A18BFEC381
|
||||||
|
AC37E76385F5
|
||||||
|
18E887D625B4
|
||||||
|
6686FADE5566
|
||||||
|
3D6F823FFFFF
|
||||||
|
427553754D47
|
||||||
|
9089B668FFFF
|
||||||
|
6C273F431564
|
||||||
|
34635A313344
|
||||||
|
353038383134
|
||||||
|
EDC317193709
|
||||||
|
75FAB77E2E5B
|
||||||
|
A1AB3A08712C
|
||||||
|
8DFACF11E778
|
||||||
|
6B3B7AF45777
|
||||||
|
45524DACC5E9
|
||||||
|
B1C4A8F7F6E3
|
||||||
|
6A6C80423226
|
||||||
|
537930363139
|
||||||
|
529CF51F05C5
|
||||||
|
374521A38BCC
|
||||||
|
EAB8066C7479
|
||||||
|
576DCFFF2F25
|
||||||
|
505209016A1F
|
||||||
|
186C59E6AFC9
|
||||||
|
8AC04C1A4E15
|
||||||
|
05597810D63D
|
||||||
|
453857395635
|
||||||
|
A1670589B2AF
|
||||||
|
552049EFF3F4
|
||||||
|
FCDDF7767C10
|
||||||
|
4149206E9BAE
|
||||||
|
54546255CDE9
|
||||||
|
C1F6C7B55F5E
|
||||||
|
3F3A534B7B7B
|
||||||
|
204C0D3DCD9A
|
||||||
|
5A2050DA7E3F
|
||||||
|
6B0454D5D3C3
|
||||||
|
2E0F00700000
|
||||||
|
0AD0956DF6EE
|
||||||
|
65B6C3200736
|
||||||
|
4F0E4AE8051A
|
||||||
|
8C187E78EE9C
|
||||||
|
544954CBB2C4
|
||||||
|
97D77FAE77D3
|
||||||
|
64CBADC7A313
|
||||||
|
4B92DF1BF25D
|
||||||
|
AB91BDA25F00
|
||||||
|
3A524B7A7B37
|
||||||
|
A58AB5619631
|
||||||
|
7F796F60FFFF
|
||||||
|
195DC63DB3A3
|
||||||
|
4752533E1965
|
||||||
|
FFF011223358
|
||||||
|
7213B13D02E0
|
||||||
|
76E450094393
|
||||||
|
202011F918A2
|
||||||
|
B793ADA6DB0C
|
||||||
|
F0A3C5182007
|
||||||
|
5A4920FD6F87
|
||||||
|
2900AAC52BC3
|
||||||
|
3C4ABB877EAF
|
||||||
|
80BB8436024C
|
||||||
|
48C8852D15F9
|
||||||
|
45450AC8DCA8
|
||||||
|
A5BB18152EF1
|
||||||
|
A514B797B373
|
||||||
|
C0AA2BBD27CD
|
||||||
|
9D56D83658AC
|
||||||
|
514B797B2F3A
|
||||||
|
0000FFFFFFFF
|
||||||
|
A777B233A4F4
|
||||||
|
F0FE56621A42
|
||||||
|
5044068C5183
|
||||||
|
494446555455
|
||||||
|
336E34CC2177
|
||||||
|
5AF445D2B87A
|
||||||
|
CDE668FDCDBA
|
||||||
|
1AF66F83F5BE
|
||||||
|
52B26C199862
|
||||||
|
593367486137
|
||||||
|
164EE10EFFFF
|
||||||
|
F4CE4AF888AE
|
||||||
|
3351916B5A77
|
||||||
|
E5519E1CC92B
|
||||||
|
04B787B2F3A5
|
||||||
|
EA0CA627FD06
|
||||||
|
2910AFE15C99
|
||||||
|
9D0D0A829F49
|
||||||
|
9AFEE1F65742
|
||||||
|
AE98BA1E6F2C
|
||||||
|
AB19BC885A29
|
||||||
|
E9AE90885C39
|
||||||
|
518108E061E2
|
||||||
|
066F5AF3CCEE
|
||||||
|
B95BFDEBA7E4
|
||||||
|
4B787B273A50
|
||||||
|
0F3A4D48757B
|
||||||
|
8627C10A7014
|
||||||
|
4E4F584D2105
|
||||||
|
707B11FC1481
|
||||||
|
DEDD7688BC38
|
||||||
|
81504133B13C
|
||||||
|
A71E80EA35E1
|
||||||
|
50D4C54FCDF5
|
||||||
|
2612C6DE84CA
|
||||||
|
FF9F11223358
|
||||||
|
738385948494
|
||||||
|
D23A31A4AAB9
|
||||||
|
9FAC23197904
|
||||||
|
AEF617B3D040
|
||||||
|
485242F22BE0
|
||||||
|
DDDAA35A9749
|
||||||
|
05412723F1B6
|
||||||
|
AEF617B3D004
|
||||||
|
7ADD3D735725
|
||||||
|
05C301C8795A
|
||||||
|
001122334455
|
||||||
|
B6803136F5AF
|
||||||
|
FE2A42E85CA8
|
||||||
|
43204334546F
|
||||||
|
16901CB400BC
|
||||||
|
307448829EBC
|
||||||
|
8FD6D76742DC
|
||||||
|
826576A1AB68
|
||||||
|
B3A4C47757B0
|
||||||
|
A6B3F6C8F1D4
|
||||||
|
702C1BF025DD
|
||||||
|
6BE9314930D8
|
||||||
|
777B1F3A4F4A
|
||||||
|
AA4DDA458EBB
|
||||||
|
CA80E51FA52B
|
||||||
|
C2A0105EB028
|
||||||
|
67B1B3A4E497
|
||||||
|
|||||||
357
lib/subghz/protocols/honeywell.c
Normal file
357
lib/subghz/protocols/honeywell.c
Normal file
@@ -0,0 +1,357 @@
|
|||||||
|
#include "honeywell.h"
|
||||||
|
#include <lib/toolbox/manchester_decoder.h>
|
||||||
|
|
||||||
|
//Created by HTotoo 2023-10-30
|
||||||
|
//Got a lot of help from LiQuiDz.
|
||||||
|
//Protocol decoding help from: https://github.com/merbanan/rtl_433/blob/master/src/devices/honeywell.c
|
||||||
|
|
||||||
|
/*
|
||||||
|
64 bit packets, repeated multiple times per open/close event.
|
||||||
|
|
||||||
|
Protocol whitepaper: "DEFCON 22: Home Insecurity" by Logan Lamb.
|
||||||
|
|
||||||
|
Data layout:
|
||||||
|
|
||||||
|
PP PP C IIIII EE SS SS
|
||||||
|
|
||||||
|
- P: 16bit Preamble and sync bit (always ff fe)
|
||||||
|
- C: 4bit Channel
|
||||||
|
- I: 20bit Device serial number / or counter value
|
||||||
|
- E: 8bit Event, where 0x80 = Open/Close, 0x04 = Heartbeat / or id
|
||||||
|
- S: 16bit CRC
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define TAG "SubGhzProtocolHoneywell"
|
||||||
|
|
||||||
|
uint16_t subghz_protocol_honeywell_crc16(
|
||||||
|
uint8_t const message[],
|
||||||
|
unsigned nBytes,
|
||||||
|
uint16_t polynomial,
|
||||||
|
uint16_t init) {
|
||||||
|
uint16_t remainder = init;
|
||||||
|
unsigned byte, bit;
|
||||||
|
|
||||||
|
for(byte = 0; byte < nBytes; ++byte) {
|
||||||
|
remainder ^= message[byte] << 8;
|
||||||
|
for(bit = 0; bit < 8; ++bit) {
|
||||||
|
if(remainder & 0x8000) {
|
||||||
|
remainder = (remainder << 1) ^ polynomial;
|
||||||
|
} else {
|
||||||
|
remainder = (remainder << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_free(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = context;
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_reset(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = context;
|
||||||
|
instance->decoder.decode_data = 0;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_addbit(void* context, bool data) {
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = context;
|
||||||
|
instance->decoder.decode_data = (instance->decoder.decode_data << 1) | data;
|
||||||
|
instance->decoder.decode_count_bit++;
|
||||||
|
|
||||||
|
uint16_t preamble = (instance->decoder.decode_data >> 48) & 0xFFFF;
|
||||||
|
//can be multiple, since flipper can't read it well..
|
||||||
|
if(preamble == 0b0011111111111110 || preamble == 0b0111111111111110 ||
|
||||||
|
preamble == 0b1111111111111110) {
|
||||||
|
uint8_t datatocrc[4];
|
||||||
|
datatocrc[0] = (instance->decoder.decode_data >> 40) & 0xFFFF;
|
||||||
|
datatocrc[1] = (instance->decoder.decode_data >> 32) & 0xFFFF;
|
||||||
|
datatocrc[2] = (instance->decoder.decode_data >> 24) & 0xFFFF;
|
||||||
|
datatocrc[3] = (instance->decoder.decode_data >> 16) & 0xFFFF;
|
||||||
|
uint8_t channel = (instance->decoder.decode_data >> 44) & 0xF;
|
||||||
|
uint16_t crc_calc = 0;
|
||||||
|
if(channel == 0x2 || channel == 0x4 || channel == 0xA) {
|
||||||
|
// 2GIG brand
|
||||||
|
crc_calc = subghz_protocol_honeywell_crc16(datatocrc, 4, 0x8050, 0);
|
||||||
|
} else { // channel == 0x8
|
||||||
|
crc_calc = subghz_protocol_honeywell_crc16(datatocrc, 4, 0x8005, 0);
|
||||||
|
}
|
||||||
|
uint16_t crc = instance->decoder.decode_data & 0xFFFF;
|
||||||
|
if(crc == crc_calc) {
|
||||||
|
//the data is good. process it.
|
||||||
|
instance->generic.data = instance->decoder.decode_data;
|
||||||
|
instance->generic.data_count_bit =
|
||||||
|
instance->decoder
|
||||||
|
.decode_count_bit; //maybe set it to 64, and hack the first 2 bits to 1! will see if replay needs it
|
||||||
|
instance->generic.serial = (instance->decoder.decode_data >> 24) & 0xFFFFF;
|
||||||
|
instance->generic.btn = (instance->decoder.decode_data >> 16) &
|
||||||
|
0xFF; //not exactly button, but can contain btn data too.
|
||||||
|
if(instance->base.callback)
|
||||||
|
instance->base.callback(&instance->base, instance->base.context);
|
||||||
|
instance->decoder.decode_data = 0;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_feed(void* context, bool level, uint32_t duration) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = context;
|
||||||
|
|
||||||
|
ManchesterEvent event = ManchesterEventReset;
|
||||||
|
if(!level) {
|
||||||
|
if(DURATION_DIFF(duration, subghz_protocol_honeywell_const.te_short) <
|
||||||
|
subghz_protocol_honeywell_const.te_delta) {
|
||||||
|
event = ManchesterEventShortLow;
|
||||||
|
} else if(
|
||||||
|
DURATION_DIFF(duration, subghz_protocol_honeywell_const.te_long) <
|
||||||
|
subghz_protocol_honeywell_const.te_delta * 2) {
|
||||||
|
event = ManchesterEventLongLow;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(DURATION_DIFF(duration, subghz_protocol_honeywell_const.te_short) <
|
||||||
|
subghz_protocol_honeywell_const.te_delta) {
|
||||||
|
event = ManchesterEventShortHigh;
|
||||||
|
} else if(
|
||||||
|
DURATION_DIFF(duration, subghz_protocol_honeywell_const.te_long) <
|
||||||
|
subghz_protocol_honeywell_const.te_delta * 2) {
|
||||||
|
event = ManchesterEventLongHigh;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(event != ManchesterEventReset) {
|
||||||
|
bool data;
|
||||||
|
bool data_ok = manchester_advance(
|
||||||
|
instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
|
||||||
|
if(data_ok) {
|
||||||
|
subghz_protocol_decoder_honeywell_addbit(instance, data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
instance->decoder.decode_data = 0;
|
||||||
|
instance->decoder.decode_count_bit = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t subghz_protocol_decoder_honeywell_get_hash_data(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = context;
|
||||||
|
return subghz_protocol_blocks_get_hash_data(
|
||||||
|
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus subghz_protocol_decoder_honeywell_serialize(
|
||||||
|
void* context,
|
||||||
|
FlipperFormat* flipper_format,
|
||||||
|
SubGhzRadioPreset* preset) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = context;
|
||||||
|
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus
|
||||||
|
subghz_protocol_decoder_honeywell_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = context;
|
||||||
|
return subghz_block_generic_deserialize_check_count_bit(
|
||||||
|
&instance->generic,
|
||||||
|
flipper_format,
|
||||||
|
subghz_protocol_honeywell_const.min_count_bit_for_found);
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_get_string(void* context, FuriString* output) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = context;
|
||||||
|
|
||||||
|
uint8_t channel = (instance->generic.data >> 44) & 0xF;
|
||||||
|
uint8_t contact = (instance->generic.btn & 0x80) >> 7;
|
||||||
|
uint8_t tamper = (instance->generic.btn & 0x40) >> 6;
|
||||||
|
uint8_t reed = (instance->generic.btn & 0x20) >> 5;
|
||||||
|
uint8_t alarm = (instance->generic.btn & 0x10) >> 4;
|
||||||
|
uint8_t battery_low = (instance->generic.btn & 0x08) >> 3;
|
||||||
|
uint8_t heartbeat = (instance->generic.btn & 0x04) >> 2;
|
||||||
|
|
||||||
|
furi_string_cat_printf(
|
||||||
|
output,
|
||||||
|
"%s\r\n%dbit "
|
||||||
|
"Sn:%07lu\r\nCh:%u Bat:%d Hb: %d\r\n"
|
||||||
|
"L1: %u, L2: %u, L3: %u, L4: %u\r\n",
|
||||||
|
instance->generic.protocol_name,
|
||||||
|
instance->generic.data_count_bit,
|
||||||
|
instance->generic.serial,
|
||||||
|
channel,
|
||||||
|
battery_low,
|
||||||
|
heartbeat,
|
||||||
|
contact,
|
||||||
|
reed,
|
||||||
|
alarm,
|
||||||
|
tamper);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* subghz_protocol_decoder_honeywell_alloc(SubGhzEnvironment* environment) {
|
||||||
|
UNUSED(environment);
|
||||||
|
SubGhzProtocolDecoderHoneywell* instance = malloc(sizeof(SubGhzProtocolDecoderHoneywell));
|
||||||
|
instance->base.protocol = &subghz_protocol_honeywell;
|
||||||
|
instance->generic.protocol_name = instance->base.protocol->name;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* subghz_protocol_encoder_honeywell_alloc(SubGhzEnvironment* environment) {
|
||||||
|
UNUSED(environment);
|
||||||
|
SubGhzProtocolEncoderHoneywell* instance = malloc(sizeof(SubGhzProtocolEncoderHoneywell));
|
||||||
|
|
||||||
|
instance->base.protocol = &subghz_protocol_honeywell;
|
||||||
|
instance->generic.protocol_name = instance->base.protocol->name;
|
||||||
|
|
||||||
|
instance->encoder.repeat = 3;
|
||||||
|
instance->encoder.size_upload = 64 * 2 + 10;
|
||||||
|
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
|
||||||
|
instance->encoder.is_running = false;
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_protocol_encoder_honeywell_free(void* context) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolEncoderHoneywell* instance = context;
|
||||||
|
free(instance->encoder.upload);
|
||||||
|
free(instance);
|
||||||
|
}
|
||||||
|
static LevelDuration
|
||||||
|
subghz_protocol_encoder_honeywell_add_duration_to_upload(ManchesterEncoderResult result) {
|
||||||
|
LevelDuration data = {.duration = 0, .level = 0};
|
||||||
|
switch(result) {
|
||||||
|
case ManchesterEncoderResultShortLow:
|
||||||
|
data.duration = subghz_protocol_honeywell_const.te_short;
|
||||||
|
data.level = false;
|
||||||
|
break;
|
||||||
|
case ManchesterEncoderResultLongLow:
|
||||||
|
data.duration = subghz_protocol_honeywell_const.te_long;
|
||||||
|
data.level = false;
|
||||||
|
break;
|
||||||
|
case ManchesterEncoderResultLongHigh:
|
||||||
|
data.duration = subghz_protocol_honeywell_const.te_long;
|
||||||
|
data.level = true;
|
||||||
|
break;
|
||||||
|
case ManchesterEncoderResultShortHigh:
|
||||||
|
data.duration = subghz_protocol_honeywell_const.te_short;
|
||||||
|
data.level = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
furi_crash("SubGhz: ManchesterEncoderResult is incorrect.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return level_duration_make(data.level, data.duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
subghz_protocol_encoder_honeywell_get_upload(SubGhzProtocolEncoderHoneywell* instance) {
|
||||||
|
furi_assert(instance);
|
||||||
|
size_t index = 0;
|
||||||
|
|
||||||
|
ManchesterEncoderState enc_state;
|
||||||
|
manchester_encoder_reset(&enc_state);
|
||||||
|
ManchesterEncoderResult result;
|
||||||
|
|
||||||
|
for(uint8_t i = 63; i > 0; i--) {
|
||||||
|
if(!manchester_encoder_advance(
|
||||||
|
&enc_state, bit_read(instance->generic.data, i - 1), &result)) {
|
||||||
|
instance->encoder.upload[index++] =
|
||||||
|
subghz_protocol_encoder_honeywell_add_duration_to_upload(result);
|
||||||
|
manchester_encoder_advance(
|
||||||
|
&enc_state, bit_read(instance->generic.data, i - 1), &result);
|
||||||
|
}
|
||||||
|
instance->encoder.upload[index++] =
|
||||||
|
subghz_protocol_encoder_honeywell_add_duration_to_upload(result);
|
||||||
|
}
|
||||||
|
instance->encoder.upload[index] = subghz_protocol_encoder_honeywell_add_duration_to_upload(
|
||||||
|
manchester_encoder_finish(&enc_state));
|
||||||
|
if(level_duration_get_level(instance->encoder.upload[index])) {
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
instance->encoder.size_upload = index;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubGhzProtocolStatus
|
||||||
|
subghz_protocol_encoder_honeywell_deserialize(void* context, FlipperFormat* flipper_format) {
|
||||||
|
furi_assert(context);
|
||||||
|
SubGhzProtocolEncoderHoneywell* instance = context;
|
||||||
|
SubGhzProtocolStatus res = SubGhzProtocolStatusError;
|
||||||
|
do {
|
||||||
|
if(SubGhzProtocolStatusOk !=
|
||||||
|
subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
|
||||||
|
FURI_LOG_E(TAG, "Deserialize error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//optional parameter parameter
|
||||||
|
flipper_format_read_uint32(
|
||||||
|
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
|
||||||
|
|
||||||
|
subghz_protocol_encoder_honeywell_get_upload(instance);
|
||||||
|
|
||||||
|
if(!flipper_format_rewind(flipper_format)) {
|
||||||
|
FURI_LOG_E(TAG, "Rewind error");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance->encoder.is_running = true;
|
||||||
|
|
||||||
|
res = SubGhzProtocolStatusOk;
|
||||||
|
} while(false);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void subghz_protocol_encoder_honeywell_stop(void* context) {
|
||||||
|
SubGhzProtocolEncoderHoneywell* instance = context;
|
||||||
|
instance->encoder.is_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LevelDuration subghz_protocol_encoder_honeywell_yield(void* context) {
|
||||||
|
SubGhzProtocolEncoderHoneywell* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SubGhzProtocolDecoder subghz_protocol_honeywell_decoder = {
|
||||||
|
.alloc = subghz_protocol_decoder_honeywell_alloc,
|
||||||
|
.free = subghz_protocol_decoder_honeywell_free,
|
||||||
|
.feed = subghz_protocol_decoder_honeywell_feed,
|
||||||
|
.reset = subghz_protocol_decoder_honeywell_reset,
|
||||||
|
.get_hash_data = subghz_protocol_decoder_honeywell_get_hash_data,
|
||||||
|
.serialize = subghz_protocol_decoder_honeywell_serialize,
|
||||||
|
.deserialize = subghz_protocol_decoder_honeywell_deserialize,
|
||||||
|
.get_string = subghz_protocol_decoder_honeywell_get_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubGhzProtocolEncoder subghz_protocol_honeywell_encoder = {
|
||||||
|
.alloc = subghz_protocol_encoder_honeywell_alloc,
|
||||||
|
.free = subghz_protocol_encoder_honeywell_free,
|
||||||
|
.deserialize = subghz_protocol_encoder_honeywell_deserialize,
|
||||||
|
.stop = subghz_protocol_encoder_honeywell_stop,
|
||||||
|
.yield = subghz_protocol_encoder_honeywell_yield,
|
||||||
|
};
|
||||||
|
|
||||||
|
const SubGhzProtocol subghz_protocol_honeywell = {
|
||||||
|
.name = SUBGHZ_PROTOCOL_HONEYWELL_NAME,
|
||||||
|
.type = SubGhzProtocolTypeStatic,
|
||||||
|
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
|
||||||
|
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
|
||||||
|
SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
|
||||||
|
.encoder = &subghz_protocol_honeywell_encoder,
|
||||||
|
.decoder = &subghz_protocol_honeywell_decoder,
|
||||||
|
|
||||||
|
};
|
||||||
61
lib/subghz/protocols/honeywell.h
Normal file
61
lib/subghz/protocols/honeywell.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <lib/subghz/protocols/base.h>
|
||||||
|
|
||||||
|
#include <lib/subghz/blocks/const.h>
|
||||||
|
#include <lib/subghz/blocks/decoder.h>
|
||||||
|
#include <lib/subghz/blocks/encoder.h>
|
||||||
|
#include "base.h"
|
||||||
|
#include "../blocks/generic.h"
|
||||||
|
#include <lib/subghz/blocks/math.h>
|
||||||
|
#include <lib/toolbox/manchester_decoder.h>
|
||||||
|
#include <lib/toolbox/manchester_encoder.h>
|
||||||
|
|
||||||
|
#define SUBGHZ_PROTOCOL_HONEYWELL_NAME "Honeywell Sec"
|
||||||
|
|
||||||
|
typedef struct SubGhzProtocolDecoderHoneywell SubGhzProtocolDecoderHoneywell;
|
||||||
|
typedef struct SubGhzProtocolEncoderHoneywell SubGhzProtocolEncoderHoneywell;
|
||||||
|
|
||||||
|
extern const SubGhzProtocolDecoder subghz_protocol_honeywell_decoder;
|
||||||
|
extern const SubGhzProtocolEncoder subghz_protocol_honeywell_encoder;
|
||||||
|
extern const SubGhzProtocol subghz_protocol_honeywell;
|
||||||
|
|
||||||
|
void* subghz_protocol_decoder_honeywell_alloc(SubGhzEnvironment* environment);
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_free(void* context);
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_reset(void* context);
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_feed(void* context, bool level, uint32_t duration);
|
||||||
|
|
||||||
|
uint8_t subghz_protocol_decoder_honeywell_get_hash_data(void* context);
|
||||||
|
|
||||||
|
SubGhzProtocolStatus subghz_protocol_decoder_honeywell_serialize(
|
||||||
|
void* context,
|
||||||
|
FlipperFormat* flipper_format,
|
||||||
|
SubGhzRadioPreset* preset);
|
||||||
|
|
||||||
|
SubGhzProtocolStatus
|
||||||
|
subghz_protocol_decoder_honeywell_deserialize(void* context, FlipperFormat* flipper_format);
|
||||||
|
|
||||||
|
void subghz_protocol_decoder_honeywell_get_string(void* context, FuriString* output);
|
||||||
|
|
||||||
|
static const SubGhzBlockConst subghz_protocol_honeywell_const = {
|
||||||
|
.te_long = 280,
|
||||||
|
.te_short = 143,
|
||||||
|
.te_delta = 51,
|
||||||
|
.min_count_bit_for_found = 62,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SubGhzProtocolDecoderHoneywell {
|
||||||
|
SubGhzProtocolDecoderBase base;
|
||||||
|
SubGhzBlockGeneric generic;
|
||||||
|
SubGhzBlockDecoder decoder;
|
||||||
|
ManchesterState manchester_saved_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SubGhzProtocolEncoderHoneywell {
|
||||||
|
SubGhzProtocolEncoderBase base;
|
||||||
|
SubGhzBlockGeneric generic;
|
||||||
|
SubGhzProtocolBlockEncoder encoder;
|
||||||
|
};
|
||||||
@@ -10,9 +10,19 @@ static const SubGhzBlockConst pocsag_const = {
|
|||||||
.te_short = 833,
|
.te_short = 833,
|
||||||
.te_delta = 100,
|
.te_delta = 100,
|
||||||
};
|
};
|
||||||
|
static const SubGhzBlockConst pocsag512_const = {
|
||||||
|
.te_short = 1950,
|
||||||
|
.te_long = 1950,
|
||||||
|
.te_delta = 120,
|
||||||
|
};
|
||||||
|
static const SubGhzBlockConst pocsag2400_const = {
|
||||||
|
.te_short = 410,
|
||||||
|
.te_long = 410,
|
||||||
|
.te_delta = 60,
|
||||||
|
};
|
||||||
|
|
||||||
// Minimal amount of sync bits (interleaving zeros and ones)
|
// Minimal amount of sync bits (interleaving zeros and ones)
|
||||||
#define POCSAG_MIN_SYNC_BITS 32
|
#define POCSAG_MIN_SYNC_BITS 24
|
||||||
#define POCSAG_CW_BITS 32
|
#define POCSAG_CW_BITS 32
|
||||||
#define POCSAG_CW_MASK 0xFFFFFFFF
|
#define POCSAG_CW_MASK 0xFFFFFFFF
|
||||||
#define POCSAG_FRAME_SYNC_CODE 0x7CD215D8
|
#define POCSAG_FRAME_SYNC_CODE 0x7CD215D8
|
||||||
@@ -45,6 +55,9 @@ struct SubGhzProtocolDecoderPocsag {
|
|||||||
|
|
||||||
// Done messages, ready to be serialized/deserialized
|
// Done messages, ready to be serialized/deserialized
|
||||||
FuriString* done_msg;
|
FuriString* done_msg;
|
||||||
|
|
||||||
|
SubGhzBlockConst* pocsag_timing;
|
||||||
|
uint32_t version;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct SubGhzProtocolDecoderPocsag SubGhzProtocolDecoderPocsag;
|
typedef struct SubGhzProtocolDecoderPocsag SubGhzProtocolDecoderPocsag;
|
||||||
@@ -64,6 +77,7 @@ void* subghz_protocol_decoder_pocsag_alloc(SubGhzEnvironment* environment) {
|
|||||||
instance->generic.protocol_name = instance->base.protocol->name;
|
instance->generic.protocol_name = instance->base.protocol->name;
|
||||||
instance->msg = furi_string_alloc();
|
instance->msg = furi_string_alloc();
|
||||||
instance->done_msg = furi_string_alloc();
|
instance->done_msg = furi_string_alloc();
|
||||||
|
instance->pocsag_timing = NULL; //not synced yet
|
||||||
if(instance->generic.result_msg == NULL) {
|
if(instance->generic.result_msg == NULL) {
|
||||||
instance->generic.result_msg = furi_string_alloc();
|
instance->generic.result_msg = furi_string_alloc();
|
||||||
}
|
}
|
||||||
@@ -179,6 +193,38 @@ void subghz_protocol_decoder_pocsag_feed(void* context, bool level, uint32_t dur
|
|||||||
// reset state - waiting for 32 bits of interleaving 1s and 0s
|
// reset state - waiting for 32 bits of interleaving 1s and 0s
|
||||||
if(instance->decoder.parser_step == PocsagDecoderStepReset) {
|
if(instance->decoder.parser_step == PocsagDecoderStepReset) {
|
||||||
if(DURATION_DIFF(duration, pocsag_const.te_short) < pocsag_const.te_delta) {
|
if(DURATION_DIFF(duration, pocsag_const.te_short) < pocsag_const.te_delta) {
|
||||||
|
if(instance->pocsag_timing != &pocsag_const) {
|
||||||
|
//timing changed, so reset before, and override
|
||||||
|
subghz_protocol_decoder_pocsag_reset(context);
|
||||||
|
instance->pocsag_timing = (SubGhzBlockConst*)&pocsag_const;
|
||||||
|
instance->version = 1200;
|
||||||
|
}
|
||||||
|
// POCSAG signals are inverted
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, !level);
|
||||||
|
|
||||||
|
if(instance->decoder.decode_count_bit == POCSAG_MIN_SYNC_BITS) {
|
||||||
|
instance->decoder.parser_step = PocsagDecoderStepFoundSync;
|
||||||
|
}
|
||||||
|
} else if(DURATION_DIFF(duration, pocsag512_const.te_short) < pocsag512_const.te_delta) {
|
||||||
|
if(instance->pocsag_timing != &pocsag512_const) {
|
||||||
|
//timing changed, so reset before, and override
|
||||||
|
subghz_protocol_decoder_pocsag_reset(context);
|
||||||
|
instance->pocsag_timing = (SubGhzBlockConst*)&pocsag512_const;
|
||||||
|
instance->version = 512;
|
||||||
|
}
|
||||||
|
// POCSAG signals are inverted
|
||||||
|
subghz_protocol_blocks_add_bit(&instance->decoder, !level);
|
||||||
|
|
||||||
|
if(instance->decoder.decode_count_bit == POCSAG_MIN_SYNC_BITS) {
|
||||||
|
instance->decoder.parser_step = PocsagDecoderStepFoundSync;
|
||||||
|
}
|
||||||
|
} else if(DURATION_DIFF(duration, pocsag2400_const.te_short) < pocsag2400_const.te_delta) {
|
||||||
|
if(instance->pocsag_timing != &pocsag2400_const) {
|
||||||
|
//timing changed, so reset before, and override
|
||||||
|
subghz_protocol_decoder_pocsag_reset(context);
|
||||||
|
instance->pocsag_timing = (SubGhzBlockConst*)&pocsag2400_const;
|
||||||
|
instance->version = 2400;
|
||||||
|
}
|
||||||
// POCSAG signals are inverted
|
// POCSAG signals are inverted
|
||||||
subghz_protocol_blocks_add_bit(&instance->decoder, !level);
|
subghz_protocol_blocks_add_bit(&instance->decoder, !level);
|
||||||
|
|
||||||
@@ -191,12 +237,12 @@ void subghz_protocol_decoder_pocsag_feed(void* context, bool level, uint32_t dur
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bits_count = duration / pocsag_const.te_short;
|
int bits_count = duration / instance->pocsag_timing->te_short;
|
||||||
uint32_t extra = duration - pocsag_const.te_short * bits_count;
|
uint32_t extra = duration - instance->pocsag_timing->te_short * bits_count;
|
||||||
|
|
||||||
if(DURATION_DIFF(extra, pocsag_const.te_short) < pocsag_const.te_delta)
|
if(DURATION_DIFF(extra, instance->pocsag_timing->te_short) < instance->pocsag_timing->te_delta)
|
||||||
bits_count++;
|
bits_count++;
|
||||||
else if(extra > pocsag_const.te_delta) {
|
else if(extra > instance->pocsag_timing->te_delta) {
|
||||||
// in non-reset state we faced the error signal - we reached the end of the packet, flush data
|
// in non-reset state we faced the error signal - we reached the end of the packet, flush data
|
||||||
if(furi_string_size(instance->done_msg) > 0) {
|
if(furi_string_size(instance->done_msg) > 0) {
|
||||||
if(instance->base.callback)
|
if(instance->base.callback)
|
||||||
@@ -305,6 +351,11 @@ SubGhzProtocolStatus subghz_protocol_decoder_pocsag_serialize(
|
|||||||
return SubGhzProtocolStatusError;
|
return SubGhzProtocolStatusError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!flipper_format_write_uint32(flipper_format, "PocsagVer", &instance->version, 1)) {
|
||||||
|
FURI_LOG_E(TAG, "Error adding PocsagVer");
|
||||||
|
return SubGhzProtocolStatusError;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t* s = (uint8_t*)furi_string_get_cstr(instance->done_msg);
|
uint8_t* s = (uint8_t*)furi_string_get_cstr(instance->done_msg);
|
||||||
if(!flipper_format_write_hex(flipper_format, "Msg", s, msg_len)) {
|
if(!flipper_format_write_hex(flipper_format, "Msg", s, msg_len)) {
|
||||||
FURI_LOG_E(TAG, "Error adding Msg");
|
FURI_LOG_E(TAG, "Error adding Msg");
|
||||||
@@ -331,6 +382,9 @@ SubGhzProtocolStatus
|
|||||||
FURI_LOG_E(TAG, "Missing MsgLen");
|
FURI_LOG_E(TAG, "Missing MsgLen");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
//optional, so compatible backwards
|
||||||
|
instance->version = 1200;
|
||||||
|
flipper_format_read_uint32(flipper_format, "PocsagVer", &instance->version, 1);
|
||||||
|
|
||||||
buf = malloc(msg_len);
|
buf = malloc(msg_len);
|
||||||
if(!flipper_format_read_hex(flipper_format, "Msg", buf, msg_len)) {
|
if(!flipper_format_read_hex(flipper_format, "Msg", buf, msg_len)) {
|
||||||
@@ -349,7 +403,9 @@ SubGhzProtocolStatus
|
|||||||
void subhz_protocol_decoder_pocsag_get_string(void* context, FuriString* output) {
|
void subhz_protocol_decoder_pocsag_get_string(void* context, FuriString* output) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
SubGhzProtocolDecoderPocsag* instance = context;
|
SubGhzProtocolDecoderPocsag* instance = context;
|
||||||
furi_string_cat_printf(output, "%s\r\n", instance->generic.protocol_name);
|
furi_string_cat_printf(
|
||||||
|
output, "%s %lu\r\n", instance->generic.protocol_name, instance->version);
|
||||||
|
furi_string_cat_printf(output, "Addr: %lu\r\n", instance->ric);
|
||||||
furi_string_cat(output, instance->done_msg);
|
furi_string_cat(output, instance->done_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = {
|
|||||||
&subghz_protocol_bett,
|
&subghz_protocol_bett,
|
||||||
&subghz_protocol_doitrand,
|
&subghz_protocol_doitrand,
|
||||||
&subghz_protocol_phoenix_v2,
|
&subghz_protocol_phoenix_v2,
|
||||||
|
&subghz_protocol_honeywell,
|
||||||
&subghz_protocol_honeywell_wdb,
|
&subghz_protocol_honeywell_wdb,
|
||||||
&subghz_protocol_magellan,
|
&subghz_protocol_magellan,
|
||||||
&subghz_protocol_intertechno_v3,
|
&subghz_protocol_intertechno_v3,
|
||||||
|
|||||||
@@ -63,4 +63,5 @@
|
|||||||
#include "auriol_ahfl.h"
|
#include "auriol_ahfl.h"
|
||||||
#include "pocsag.h"
|
#include "pocsag.h"
|
||||||
#include "schrader_gg4.h"
|
#include "schrader_gg4.h"
|
||||||
|
#include "honeywell.h"
|
||||||
#include "bin_raw.h"
|
#include "bin_raw.h"
|
||||||
|
|||||||
Reference in New Issue
Block a user