4 * Decode DSC security contact messages
6 * Copyright (C) 2015 Tommy Vestermark
7 * Copyright (C) 2015 Robert C. Terzi
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * DSC - Digital Security Controls 433 Mhz Wireless Security Contacts
14 * doors, windows, smoke, CO2, water,
16 * Protcol Description available in this FCC Report for FCC ID F5300NB912
17 * https://apps.fcc.gov/eas/GetApplicationAttachment.html?id=100988
19 * General Packet Description
20 * - Packets are 26.5 mS long
21 * - Packets start with 2.5 mS of constant modulation for most sensors
22 * Smoke/CO2/Fire sensors start with 5.6 mS of constant modulation
23 * - The length of a bit is 500 uS, broken into two 250 uS segments.
24 * A logic 0 is 500 uS (2 x 250 uS) of no signal.
25 * A logic 1 is 250 uS of no signal followed by 250 uS of signal/keying
26 * - Then there are 4 sync logic 1 bits.
27 * - There is a sync/start 1 bit in between every 8 bits.
28 * - A zero byte would be 8 x 500 uS of no signal (plus the 250 uS of
29 * silence for the first half of the next 1 bit) for a maximum total
30 * of 4,250 uS (4.25 mS) of silence.
31 * - The last byte is a CRC with nothing after it, no stop/sync bit, so
32 * if there was a CRC byte of 0, the packet would wind up being short
33 * by 4 mS and up to 8 bits (48 bits total).
35 * There are 48 bits in the packet including the leading 4 sync 1 bits.
36 * This makes the packet 48 x 500 uS bits long plus the 2.5 mS preamble
37 * for a total packet length of 26.5 ms. (smoke will be 3.1 ms longer)
40 * Check intermessage start / sync bits, every 8 bits
41 * Byte 0 Byte 1 Byte 2 Byte 3 Byte 4 Byte 5
43 * SSSSdddd ddddSddd dddddSdd ddddddSd dddddddS cccccccc Sync,data,crc
44 * 01234567 89012345 67890123 45678901 23456789 01234567 Received Bit No.
45 * 84218421 84218421 84218421 84218421 84218421 84218421 Received Bit Pos.
47 # SSSS S S S S Synb bit positions
48 * ssss ssss ttt teeee ee eeeeee e eeeeeee cccccccc type
49 * tttt tttt yyy y1111 22 223333 4 4445555 rrrrrrrr
51 * Bits: 0,1,2,3,12,21,30,39 should == 1
53 * Status (st) = 8 bits, open, closed, tamper, repeat
54 * Type (ty) = 4 bits, Sensor type, really first nybble of ESN
55 * ESN (e1-5) = 20 bits, Electronic Serial Number: Sensor ID.
56 * CRC (cr) = 8 bits, CRC, type/polynom to be determined
58 * The ESN in practice is 24 bits, The type + remaining 5 nybbles,
60 * The CRC is 8 bit, "little endian", Polynomial 0xf5, Inital value 0x3d
62 * CRC algorithm found with CRC reveng (reveng.sourceforge.net)
64 * CRC Model Parameters:
65 * width=8 poly=0xf5 init=0x3d refin=true refout=true xorout=0x00 check=0xfd name=(none)
72 #define DSC_CT_MSGLEN 5
73 #define DSC_CT_CRC_POLY 0xf5
74 #define DSC_CT_CRC_INIT 0x3d
77 static int DSC_callback(bitbuffer_t *bitbuffer) {
78 bitrow_t *bb = bitbuffer->bb;
80 char time_str[LOCAL_TIME_BUFLEN];
82 if (debug_output > 1) {
83 fprintf(stderr,"Possible DSC Contact: ");
84 bitbuffer_print(bitbuffer);
87 for (int row = 0; row < bitbuffer->num_rows; row++) {
88 if (debug_output > 1 && bitbuffer->bits_per_row[row] > 0 ) {
89 fprintf(stderr,"row %d bit count %d\n", row,
90 bitbuffer->bits_per_row[row]);
93 // Number of bits in the packet should be 48 but due to the
94 // encoding of trailing zeros is a guess based on reset_limit /
95 // long_limit (bit period). With current values up to 10 zero
96 // bits could be added, so it is normal to get a 58 bit packet.
98 // If the limits are changed for some reason, the max number of bits
99 // will need to be changed as there may be more zero bit padding
100 if (bitbuffer->bits_per_row[row] < 48 ||
101 bitbuffer->bits_per_row[row] > 70) { // should be 48 at most
102 if (debug_output > 1 && bitbuffer->bits_per_row[row] > 0) {
103 fprintf(stderr,"DSC row %d invalid bit count %d\n",
104 row, bitbuffer->bits_per_row[row]);
109 // Validate Sync/Start bits == 1 and are in the right position
110 if (!((bb[row][0] & 0xF0) && // First 4 bits are start/sync bits
111 (bb[row][1] & 0x08) && // Another sync/start bit between
112 (bb[row][2] & 0x04) && // every 8 data bits
113 (bb[row][3] & 0x02) &&
114 (bb[row][4] & 0x01))) {
115 if (debug_output > 1) {
117 "DSC Invalid start/sync bits %02x %02x %02x %02x %02x\n",
130 uint8_t crcc1, crcc2, crcc3, crcc4, crcc5, crcc6, crcc7, crcc8;
132 bytes[0] = ((bb[row][0] & 0x0F) << 4) | ((bb[row][1] & 0xF0) >> 4);
133 bytes[1] = ((bb[row][1] & 0x07) << 5) | ((bb[row][2] & 0xF8) >> 3);
134 bytes[2] = ((bb[row][2] & 0x03) << 6) | ((bb[row][3] & 0xFC) >> 2);
135 bytes[3] = ((bb[row][3] & 0x01) << 7) | ((bb[row][4] & 0xFE) >> 1);
136 bytes[4] = ((bb[row][5]));
138 // XXX change to debug_output
140 fprintf(stdout, "DSC Contact Raw Data: %02X %02X %02X %02X %02X\n",
141 bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]);
144 esn = (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
147 local_time_str(0, time_str);
149 if (crc8le(bytes, DSC_CT_MSGLEN, DSC_CT_CRC_POLY, DSC_CT_CRC_INIT) == 0) {
150 printf("%s DSC Contact ESN: %06X, Status: %02X, CRC: %02X\n",
151 time_str, esn, status, crc);
153 valid_cnt++; // Have a valid packet.
154 } else if (debug_output) {
155 fprintf(stderr,"%s DSC Contact bad CRC: %06X, Status: %02X, CRC: %02X\n",
156 time_str, esn, status, crc);
169 .name = "DSC Security Contact",
170 .modulation = OOK_PULSE_PCM_RZ,
171 .short_limit = 250, // Pulse length, 250 µs
172 .long_limit = 500, // Bit period, 500 µs
173 .reset_limit = 5000, // Max gap,
174 .json_callback = &DSC_callback,