Skip to content

Commit 91d614d

Browse files
committed
1 parent baca599 commit 91d614d

File tree

4 files changed

+420
-0
lines changed

4 files changed

+420
-0
lines changed

lib/subghz/protocols/honeywell.c

+357
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
#include "honeywell.h"
2+
#include <lib/toolbox/manchester_decoder.h>
3+
4+
//Created by HTotoo 2023-10-30
5+
//Got a lot of help from LiQuiDz.
6+
//Protocol decoding help from: https://github.com/merbanan/rtl_433/blob/master/src/devices/honeywell.c
7+
8+
/*
9+
64 bit packets, repeated multiple times per open/close event.
10+
11+
Protocol whitepaper: "DEFCON 22: Home Insecurity" by Logan Lamb.
12+
13+
Data layout:
14+
15+
PP PP C IIIII EE SS SS
16+
17+
- P: 16bit Preamble and sync bit (always ff fe)
18+
- C: 4bit Channel
19+
- I: 20bit Device serial number / or counter value
20+
- E: 8bit Event, where 0x80 = Open/Close, 0x04 = Heartbeat / or id
21+
- S: 16bit CRC
22+
*/
23+
24+
#define TAG "SubGhzProtocolHoneywell"
25+
26+
uint16_t subghz_protocol_honeywell_crc16(
27+
uint8_t const message[],
28+
unsigned nBytes,
29+
uint16_t polynomial,
30+
uint16_t init) {
31+
uint16_t remainder = init;
32+
unsigned byte, bit;
33+
34+
for(byte = 0; byte < nBytes; ++byte) {
35+
remainder ^= message[byte] << 8;
36+
for(bit = 0; bit < 8; ++bit) {
37+
if(remainder & 0x8000) {
38+
remainder = (remainder << 1) ^ polynomial;
39+
} else {
40+
remainder = (remainder << 1);
41+
}
42+
}
43+
}
44+
return remainder;
45+
}
46+
47+
void subghz_protocol_decoder_honeywell_free(void* context) {
48+
furi_assert(context);
49+
SubGhzProtocolDecoderHoneywell* instance = context;
50+
free(instance);
51+
}
52+
53+
void subghz_protocol_decoder_honeywell_reset(void* context) {
54+
furi_assert(context);
55+
SubGhzProtocolDecoderHoneywell* instance = context;
56+
instance->decoder.decode_data = 0;
57+
instance->decoder.decode_count_bit = 0;
58+
}
59+
60+
void subghz_protocol_decoder_honeywell_addbit(void* context, bool data) {
61+
SubGhzProtocolDecoderHoneywell* instance = context;
62+
instance->decoder.decode_data = (instance->decoder.decode_data << 1) | data;
63+
instance->decoder.decode_count_bit++;
64+
65+
uint16_t preamble = (instance->decoder.decode_data >> 48) & 0xFFFF;
66+
//can be multiple, since flipper can't read it well..
67+
if(preamble == 0b0011111111111110 || preamble == 0b0111111111111110 ||
68+
preamble == 0b1111111111111110) {
69+
uint8_t datatocrc[4];
70+
datatocrc[0] = (instance->decoder.decode_data >> 40) & 0xFFFF;
71+
datatocrc[1] = (instance->decoder.decode_data >> 32) & 0xFFFF;
72+
datatocrc[2] = (instance->decoder.decode_data >> 24) & 0xFFFF;
73+
datatocrc[3] = (instance->decoder.decode_data >> 16) & 0xFFFF;
74+
uint8_t channel = (instance->decoder.decode_data >> 44) & 0xF;
75+
uint16_t crc_calc = 0;
76+
if(channel == 0x2 || channel == 0x4 || channel == 0xA) {
77+
// 2GIG brand
78+
crc_calc = subghz_protocol_honeywell_crc16(datatocrc, 4, 0x8050, 0);
79+
} else { // channel == 0x8
80+
crc_calc = subghz_protocol_honeywell_crc16(datatocrc, 4, 0x8005, 0);
81+
}
82+
uint16_t crc = instance->decoder.decode_data & 0xFFFF;
83+
if(crc == crc_calc) {
84+
//the data is good. process it.
85+
instance->generic.data = instance->decoder.decode_data;
86+
instance->generic.data_count_bit =
87+
instance->decoder
88+
.decode_count_bit; //maybe set it to 64, and hack the first 2 bits to 1! will see if replay needs it
89+
instance->generic.serial = (instance->decoder.decode_data >> 24) & 0xFFFFF;
90+
instance->generic.btn = (instance->decoder.decode_data >> 16) &
91+
0xFF; //not exactly button, but can contain btn data too.
92+
if(instance->base.callback)
93+
instance->base.callback(&instance->base, instance->base.context);
94+
instance->decoder.decode_data = 0;
95+
instance->decoder.decode_count_bit = 0;
96+
} else {
97+
return;
98+
}
99+
}
100+
}
101+
102+
void subghz_protocol_decoder_honeywell_feed(void* context, bool level, uint32_t duration) {
103+
furi_assert(context);
104+
SubGhzProtocolDecoderHoneywell* instance = context;
105+
106+
ManchesterEvent event = ManchesterEventReset;
107+
if(!level) {
108+
if(DURATION_DIFF(duration, subghz_protocol_honeywell_const.te_short) <
109+
subghz_protocol_honeywell_const.te_delta) {
110+
event = ManchesterEventShortLow;
111+
} else if(
112+
DURATION_DIFF(duration, subghz_protocol_honeywell_const.te_long) <
113+
subghz_protocol_honeywell_const.te_delta * 2) {
114+
event = ManchesterEventLongLow;
115+
}
116+
} else {
117+
if(DURATION_DIFF(duration, subghz_protocol_honeywell_const.te_short) <
118+
subghz_protocol_honeywell_const.te_delta) {
119+
event = ManchesterEventShortHigh;
120+
} else if(
121+
DURATION_DIFF(duration, subghz_protocol_honeywell_const.te_long) <
122+
subghz_protocol_honeywell_const.te_delta * 2) {
123+
event = ManchesterEventLongHigh;
124+
}
125+
}
126+
if(event != ManchesterEventReset) {
127+
bool data;
128+
bool data_ok = manchester_advance(
129+
instance->manchester_saved_state, event, &instance->manchester_saved_state, &data);
130+
if(data_ok) {
131+
subghz_protocol_decoder_honeywell_addbit(instance, data);
132+
}
133+
} else {
134+
instance->decoder.decode_data = 0;
135+
instance->decoder.decode_count_bit = 0;
136+
}
137+
}
138+
139+
uint8_t subghz_protocol_decoder_honeywell_get_hash_data(void* context) {
140+
furi_assert(context);
141+
SubGhzProtocolDecoderHoneywell* instance = context;
142+
return subghz_protocol_blocks_get_hash_data(
143+
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
144+
}
145+
146+
SubGhzProtocolStatus subghz_protocol_decoder_honeywell_serialize(
147+
void* context,
148+
FlipperFormat* flipper_format,
149+
SubGhzRadioPreset* preset) {
150+
furi_assert(context);
151+
SubGhzProtocolDecoderHoneywell* instance = context;
152+
return subghz_block_generic_serialize(&instance->generic, flipper_format, preset);
153+
}
154+
155+
SubGhzProtocolStatus
156+
subghz_protocol_decoder_honeywell_deserialize(void* context, FlipperFormat* flipper_format) {
157+
furi_assert(context);
158+
SubGhzProtocolDecoderHoneywell* instance = context;
159+
return subghz_block_generic_deserialize_check_count_bit(
160+
&instance->generic,
161+
flipper_format,
162+
subghz_protocol_honeywell_const.min_count_bit_for_found);
163+
}
164+
165+
void subghz_protocol_decoder_honeywell_get_string(void* context, FuriString* output) {
166+
furi_assert(context);
167+
SubGhzProtocolDecoderHoneywell* instance = context;
168+
169+
uint8_t channel = (instance->generic.data >> 44) & 0xF;
170+
uint8_t contact = (instance->generic.btn & 0x80) >> 7;
171+
uint8_t tamper = (instance->generic.btn & 0x40) >> 6;
172+
uint8_t reed = (instance->generic.btn & 0x20) >> 5;
173+
uint8_t alarm = (instance->generic.btn & 0x10) >> 4;
174+
uint8_t battery_low = (instance->generic.btn & 0x08) >> 3;
175+
uint8_t heartbeat = (instance->generic.btn & 0x04) >> 2;
176+
177+
furi_string_cat_printf(
178+
output,
179+
"%s\r\n%dbit "
180+
"Sn:%07lu\r\nCh:%u Bat:%d Hb: %d\r\n"
181+
"L1: %u, L2: %u, L3: %u, L4: %u\r\n",
182+
instance->generic.protocol_name,
183+
instance->generic.data_count_bit,
184+
instance->generic.serial,
185+
channel,
186+
battery_low,
187+
heartbeat,
188+
contact,
189+
reed,
190+
alarm,
191+
tamper);
192+
}
193+
194+
void* subghz_protocol_decoder_honeywell_alloc(SubGhzEnvironment* environment) {
195+
UNUSED(environment);
196+
SubGhzProtocolDecoderHoneywell* instance = malloc(sizeof(SubGhzProtocolDecoderHoneywell));
197+
instance->base.protocol = &subghz_protocol_honeywell;
198+
instance->generic.protocol_name = instance->base.protocol->name;
199+
return instance;
200+
}
201+
202+
void* subghz_protocol_encoder_honeywell_alloc(SubGhzEnvironment* environment) {
203+
UNUSED(environment);
204+
SubGhzProtocolEncoderHoneywell* instance = malloc(sizeof(SubGhzProtocolEncoderHoneywell));
205+
206+
instance->base.protocol = &subghz_protocol_honeywell;
207+
instance->generic.protocol_name = instance->base.protocol->name;
208+
209+
instance->encoder.repeat = 3;
210+
instance->encoder.size_upload = 64 * 2 + 10;
211+
instance->encoder.upload = malloc(instance->encoder.size_upload * sizeof(LevelDuration));
212+
instance->encoder.is_running = false;
213+
return instance;
214+
}
215+
216+
void subghz_protocol_encoder_honeywell_free(void* context) {
217+
furi_assert(context);
218+
SubGhzProtocolEncoderHoneywell* instance = context;
219+
free(instance->encoder.upload);
220+
free(instance);
221+
}
222+
static LevelDuration
223+
subghz_protocol_encoder_honeywell_add_duration_to_upload(ManchesterEncoderResult result) {
224+
LevelDuration data = {.duration = 0, .level = 0};
225+
switch(result) {
226+
case ManchesterEncoderResultShortLow:
227+
data.duration = subghz_protocol_honeywell_const.te_short;
228+
data.level = false;
229+
break;
230+
case ManchesterEncoderResultLongLow:
231+
data.duration = subghz_protocol_honeywell_const.te_long;
232+
data.level = false;
233+
break;
234+
case ManchesterEncoderResultLongHigh:
235+
data.duration = subghz_protocol_honeywell_const.te_long;
236+
data.level = true;
237+
break;
238+
case ManchesterEncoderResultShortHigh:
239+
data.duration = subghz_protocol_honeywell_const.te_short;
240+
data.level = true;
241+
break;
242+
243+
default:
244+
furi_crash("SubGhz: ManchesterEncoderResult is incorrect.");
245+
break;
246+
}
247+
return level_duration_make(data.level, data.duration);
248+
}
249+
250+
static void
251+
subghz_protocol_encoder_honeywell_get_upload(SubGhzProtocolEncoderHoneywell* instance) {
252+
furi_assert(instance);
253+
size_t index = 0;
254+
255+
ManchesterEncoderState enc_state;
256+
manchester_encoder_reset(&enc_state);
257+
ManchesterEncoderResult result;
258+
259+
for(uint8_t i = 63; i > 0; i--) {
260+
if(!manchester_encoder_advance(
261+
&enc_state, bit_read(instance->generic.data, i - 1), &result)) {
262+
instance->encoder.upload[index++] =
263+
subghz_protocol_encoder_honeywell_add_duration_to_upload(result);
264+
manchester_encoder_advance(
265+
&enc_state, bit_read(instance->generic.data, i - 1), &result);
266+
}
267+
instance->encoder.upload[index++] =
268+
subghz_protocol_encoder_honeywell_add_duration_to_upload(result);
269+
}
270+
instance->encoder.upload[index] = subghz_protocol_encoder_honeywell_add_duration_to_upload(
271+
manchester_encoder_finish(&enc_state));
272+
if(level_duration_get_level(instance->encoder.upload[index])) {
273+
index++;
274+
}
275+
instance->encoder.size_upload = index;
276+
}
277+
278+
SubGhzProtocolStatus
279+
subghz_protocol_encoder_honeywell_deserialize(void* context, FlipperFormat* flipper_format) {
280+
furi_assert(context);
281+
SubGhzProtocolEncoderHoneywell* instance = context;
282+
SubGhzProtocolStatus res = SubGhzProtocolStatusError;
283+
do {
284+
if(SubGhzProtocolStatusOk !=
285+
subghz_block_generic_deserialize(&instance->generic, flipper_format)) {
286+
FURI_LOG_E(TAG, "Deserialize error");
287+
break;
288+
}
289+
290+
//optional parameter parameter
291+
flipper_format_read_uint32(
292+
flipper_format, "Repeat", (uint32_t*)&instance->encoder.repeat, 1);
293+
294+
subghz_protocol_encoder_honeywell_get_upload(instance);
295+
296+
if(!flipper_format_rewind(flipper_format)) {
297+
FURI_LOG_E(TAG, "Rewind error");
298+
break;
299+
}
300+
301+
instance->encoder.is_running = true;
302+
303+
res = SubGhzProtocolStatusOk;
304+
} while(false);
305+
306+
return res;
307+
}
308+
309+
void subghz_protocol_encoder_honeywell_stop(void* context) {
310+
SubGhzProtocolEncoderHoneywell* instance = context;
311+
instance->encoder.is_running = false;
312+
}
313+
314+
LevelDuration subghz_protocol_encoder_honeywell_yield(void* context) {
315+
SubGhzProtocolEncoderHoneywell* instance = context;
316+
317+
if(instance->encoder.repeat == 0 || !instance->encoder.is_running) {
318+
instance->encoder.is_running = false;
319+
return level_duration_reset();
320+
}
321+
LevelDuration ret = instance->encoder.upload[instance->encoder.front];
322+
if(++instance->encoder.front == instance->encoder.size_upload) {
323+
instance->encoder.repeat--;
324+
instance->encoder.front = 0;
325+
}
326+
return ret;
327+
}
328+
329+
const SubGhzProtocolDecoder subghz_protocol_honeywell_decoder = {
330+
.alloc = subghz_protocol_decoder_honeywell_alloc,
331+
.free = subghz_protocol_decoder_honeywell_free,
332+
.feed = subghz_protocol_decoder_honeywell_feed,
333+
.reset = subghz_protocol_decoder_honeywell_reset,
334+
.get_hash_data = subghz_protocol_decoder_honeywell_get_hash_data,
335+
.serialize = subghz_protocol_decoder_honeywell_serialize,
336+
.deserialize = subghz_protocol_decoder_honeywell_deserialize,
337+
.get_string = subghz_protocol_decoder_honeywell_get_string,
338+
};
339+
340+
const SubGhzProtocolEncoder subghz_protocol_honeywell_encoder = {
341+
.alloc = subghz_protocol_encoder_honeywell_alloc,
342+
.free = subghz_protocol_encoder_honeywell_free,
343+
.deserialize = subghz_protocol_encoder_honeywell_deserialize,
344+
.stop = subghz_protocol_encoder_honeywell_stop,
345+
.yield = subghz_protocol_encoder_honeywell_yield,
346+
};
347+
348+
const SubGhzProtocol subghz_protocol_honeywell = {
349+
.name = SUBGHZ_PROTOCOL_HONEYWELL_NAME,
350+
.type = SubGhzProtocolTypeStatic,
351+
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
352+
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
353+
SubGhzProtocolFlag_Save | SubGhzProtocolFlag_Send,
354+
.encoder = &subghz_protocol_honeywell_encoder,
355+
.decoder = &subghz_protocol_honeywell_decoder,
356+
357+
};

0 commit comments

Comments
 (0)