Редизайн на основе текущей ветки мейнстрима + новые устройства.
[rtl-433.git] / src / devices / dsc.c
diff --git a/src/devices/dsc.c b/src/devices/dsc.c
new file mode 100644 (file)
index 0000000..d9fcafd
--- /dev/null
@@ -0,0 +1,180 @@
+/* DSC sensor
+ *
+ *
+ * Decode DSC security contact messages
+ *
+ * Copyright (C) 2015 Tommy Vestermark
+ * Copyright (C) 2015 Robert C. Terzi
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * DSC - Digital Security Controls 433 Mhz Wireless Security Contacts
+ *       doors, windows, smoke, CO2, water, 
+ *
+ * Protcol Description available in this FCC Report for FCC ID F5300NB912
+ *  https://apps.fcc.gov/eas/GetApplicationAttachment.html?id=100988
+ *
+ * General Packet Description
+ * - Packets are 26.5 mS long
+ * - Packets start with 2.5 mS of constant modulation for most sensors
+ *   Smoke/CO2/Fire sensors start with 5.6 mS of constant modulation
+ * - The length of a bit is 500 uS, broken into two 250 uS segments.
+ *    A logic 0 is 500 uS (2 x 250 uS) of no signal.
+ *    A logic 1 is 250 uS of no signal followed by 250 uS of signal/keying
+ * - Then there are 4 sync logic 1 bits.
+ * - There is a sync/start 1 bit in between every 8 bits.
+ * - A zero byte would be 8 x 500 uS of no signal (plus the 250 uS of
+ *   silence for the first half of the next 1 bit) for a maximum total
+ *   of 4,250 uS (4.25 mS) of silence.
+ * - The last byte is a CRC with nothing after it, no stop/sync bit, so
+ *   if there was a CRC byte of 0, the packet would wind up being short
+ *   by 4 mS and up to 8 bits (48 bits total).
+ *
+ * There are 48 bits in the packet including the leading 4 sync 1 bits.
+ * This makes the packet 48 x 500 uS bits long plus the 2.5 mS preamble
+ * for a total packet length of 26.5 ms.  (smoke will be 3.1 ms longer)
+ *
+ * Packet Decoding
+ *    Check intermessage start / sync bits, every 8 bits
+ *    Byte 0   Byte 1   Byte 2   Byte 3   Byte 4   Byte 5
+ *    vvvv         v         v         v         v
+ *    SSSSdddd ddddSddd dddddSdd ddddddSd dddddddS cccccccc  Sync,data,crc
+ *    01234567 89012345 67890123 45678901 23456789 01234567  Received Bit No.
+ *    84218421 84218421 84218421 84218421 84218421 84218421  Received Bit Pos.
+ *
+ #    SSSS         S         S         S         S           Synb bit positions
+ *        ssss ssss ttt teeee ee eeeeee e eeeeeee  cccccccc  type
+ *        tttt tttt yyy y1111 22 223333 4 4445555  rrrrrrrr  
+ *
+ *  Bits: 0,1,2,3,12,21,30,39 should == 1
+ *
+ *  Status (st) = 8 bits, open, closed, tamper, repeat
+ *  Type (ty)   = 4 bits, Sensor type, really first nybble of ESN
+ *  ESN (e1-5)  = 20 bits, Electronic Serial Number: Sensor ID.
+ *  CRC (cr)    = 8 bits, CRC, type/polynom to be determined
+ *
+ * The ESN in practice is 24 bits, The type + remaining 5 nybbles, 
+ *
+ * The CRC is 8 bit, "little endian", Polynomial 0xf5, Inital value 0x3d
+ *
+ * CRC algorithm found with CRC reveng (reveng.sourceforge.net)
+ *
+ * CRC Model Parameters:
+ * width=8  poly=0xf5  init=0x3d  refin=true  refout=true  xorout=0x00  check=0xfd  name=(none)
+ *
+ */
+
+#include "rtl_433.h"
+#include "util.h"
+
+#define DSC_CT_MSGLEN          5       
+#define DSC_CT_CRC_POLY                0xf5
+#define DSC_CT_CRC_INIT                0x3d
+
+
+static int DSC_callback(bitbuffer_t *bitbuffer) {
+    bitrow_t *bb = bitbuffer->bb;
+    int valid_cnt = 0;
+    char time_str[LOCAL_TIME_BUFLEN];
+
+    if (debug_output > 1) {
+       fprintf(stderr,"Possible DSC Contact: ");
+       bitbuffer_print(bitbuffer);
+    }
+
+    for (int row = 0; row < bitbuffer->num_rows; row++) {
+       if (debug_output > 1 && bitbuffer->bits_per_row[row] > 0 ) {
+           fprintf(stderr,"row %d bit count %d\n", row, 
+                   bitbuffer->bits_per_row[row]);
+       }
+
+       // Number of bits in the packet should be 48 but due to the 
+       // encoding of trailing zeros is a guess based on reset_limit / 
+       // long_limit (bit period).  With current values up to 10 zero
+       // bits could be added, so it is normal to get a 58 bit packet.
+       //
+       // If the limits are changed for some reason, the max number of bits
+       // will need to be changed as there may be more zero bit padding
+       if (bitbuffer->bits_per_row[row] < 48 || 
+           bitbuffer->bits_per_row[row] > 70) {  // should be 48 at most
+           if (debug_output > 1 && bitbuffer->bits_per_row[row] > 0) {
+               fprintf(stderr,"DSC row %d invalid bit count %d\n",
+                       row, bitbuffer->bits_per_row[row]);
+           }
+           continue;
+       }
+
+       // Validate Sync/Start bits == 1 and are in the right position
+       if (!((bb[row][0] & 0xF0) &&    // First 4 bits are start/sync bits
+             (bb[row][1] & 0x08) &&    // Another sync/start bit between
+             (bb[row][2] & 0x04) &&    // every 8 data bits
+             (bb[row][3] & 0x02) &&
+             (bb[row][4] & 0x01))) {
+           if (debug_output > 1) {
+               fprintf(stderr,
+                       "DSC Invalid start/sync bits %02x %02x %02x %02x %02x\n",
+                       bb[row][0] & 0xF0,
+                       bb[row][1] & 0x08,
+                       bb[row][2] & 0x04,
+                       bb[row][3] & 0x02,
+                       bb[row][4] & 0x01);
+           }
+           continue;
+       }
+
+       uint8_t bytes[5];
+       uint8_t status,crc;
+       uint32_t esn;
+       uint8_t crcc1, crcc2, crcc3, crcc4, crcc5, crcc6, crcc7, crcc8;
+
+       bytes[0] = ((bb[row][0] & 0x0F) << 4) | ((bb[row][1] & 0xF0) >> 4);
+       bytes[1] = ((bb[row][1] & 0x07) << 5) | ((bb[row][2] & 0xF8) >> 3);
+       bytes[2] = ((bb[row][2] & 0x03) << 6) | ((bb[row][3] & 0xFC) >> 2);
+       bytes[3] = ((bb[row][3] & 0x01) << 7) | ((bb[row][4] & 0xFE) >> 1);
+       bytes[4] = ((bb[row][5]));
+
+       // XXX change to debug_output
+       if (debug_output) 
+           fprintf(stdout, "DSC Contact Raw Data: %02X %02X %02X %02X %02X\n",
+               bytes[0], bytes[1], bytes[2], bytes[3], bytes[4]);
+
+       status = bytes[0];
+       esn = (bytes[1] << 16) | (bytes[2] << 8) | bytes[3]; 
+       crc = bytes[4];
+
+       local_time_str(0, time_str);
+
+       if (crc8le(bytes, DSC_CT_MSGLEN, DSC_CT_CRC_POLY, DSC_CT_CRC_INIT) == 0) {
+           printf("%s DSC Contact ESN: %06X, Status: %02X, CRC: %02X\n",
+                  time_str, esn, status, crc);
+
+           valid_cnt++; // Have a valid packet.
+       } else if (debug_output) {
+           fprintf(stderr,"%s DSC Contact bad CRC: %06X, Status: %02X, CRC: %02X\n",
+                  time_str, esn, status, crc);
+       }
+    }
+
+    if (valid_cnt) {
+       return 1;
+    }
+
+    return 0;
+}
+
+
+r_device DSC = {
+    .name              = "DSC Security Contact",
+    .modulation                = OOK_PULSE_PCM_RZ,
+    .short_limit       = 250,  // Pulse length, 250 µs
+    .long_limit                = 500,  // Bit period, 500 µs
+    .reset_limit       = 5000, // Max gap, 
+    .json_callback     = &DSC_callback,
+    .disabled          = 1,
+    .demod_arg         = 0,
+};
+
+
+