Bugfixes
[rtl-433.git] / src / devices / brennenstuhl_rcs_2044.c
1 #include "rtl_433.h"
2 #include "util.h"
3
4 /*
5  * Brennenstuhl RCS 2044 remote control on 433.92MHz
6  *
7  * Copyright (C) 2015 Paul Ortyl
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 3 as
10  * published by the Free Software Foundation.
11  */
12
13 /*
14  * Receiver for the "RCS 2044 N Comfort Wireless Controller Set" sold under
15  * the "Brennenstuhl" brand.
16  *
17  * The protocol is also implemented for raspi controlled transmitter on 433.92 MHz:
18  * https://github.com/xkonni/raspberry-remote
19  */
20
21
22 static int brennenstuhl_rcs_2044_process_row(int row, const bitbuffer_t *bitbuffer)
23 {
24   const uint8_t *b = bitbuffer->bb[row];
25   const int length = bitbuffer->bits_per_row[row];
26   /* Two bits map to 2 states, 0 1 -> 0 and 1 1 -> 1 */
27   int i;
28   uint8_t nb[3] = {0};
29
30 #if 0
31   {
32     // print raw bit sequence for debug purposes (before exclusion of invalid sequenced is executed)
33     char time_str[LOCAL_TIME_BUFLEN];
34     local_time_str(0, time_str);
35     fprintf(stdout, "%s Brennenstuhl RCS 2044: received RAW bit sequence (%d bits): ", time_str, length);
36     for(int i=0; i<4; i++)
37     {
38       for(int p=7; p>=0; p--)
39         fprintf(stdout, "%d", (b[i]>>p ) & 0x1);
40       fprintf(stdout, " ");
41     }
42     fprintf(stdout, "\n");
43
44     fprintf(stdout, "%s Brennenstuhl RCS 2044: received RAW bit sequence (%d bits): ", time_str, length);
45     for(int i=0; i<4; i++)
46     {
47       for(int p=7; p>=0; p--)
48         if (p%2)
49           fprintf(stdout, ".");
50         else
51           fprintf(stdout, "%d", (b[i]>>p ) & 0x1);
52       fprintf(stdout, " ");
53     }
54     fprintf(stdout, "\n");
55
56   }
57 #endif
58
59   /* Test bit pattern for every second bit being 1 */
60   if ( 25 != length
61        || (b[0]&0xaa) != 0xaa
62        || (b[1]&0xaa) != 0xaa
63        || (b[2]&0xaa) != 0xaa
64        || (b[3]       != 0x80) )
65     return 0; /* something is wrong, exit now */
66
67 #if 0 && !defined(NDEBUG)
68   {
69     // print raw bit sequence for debug purposes (before exclusion of invalid sequenced is executed)
70     char time_str[LOCAL_TIME_BUFLEN];
71     local_time_str(0, time_str);
72     fprintf(stdout, "%s Brennenstuhl RCS 2044: received bit sequence: ", time_str);
73     for(int i=0; i<4; i++)
74     {
75       for(int p=6; p>=0; p-=2)
76         fprintf(stdout, "%d", (b[i]>>p ) & 0x1);
77       fprintf(stdout, " ");
78     }
79     fprintf(stdout, "\n");
80   }
81 #endif
82
83   /* Only odd bits contain information, even bits are set to 1
84    * First 5 odd bits contain system code (the dip switch on the remote),
85    * following 5 odd bits code button row pressed on the remote,
86    * following 2 odd bits code button column pressed on the remote.
87    *
88    * One can press many buttons at a time and the corresponding code will be sent.
89    * In the code below only use of a single button at a time is reported,
90    * all other messages are discarded as invalid.
91    */
92
93   /* extract bits for system code */
94   int system_code[] =
95   {
96       b[0]>>6 & 1,
97       b[0]>>4 & 1,
98       b[0]>>2 & 1,
99       b[0]    & 1,
100       b[1]>>6 & 1
101   };
102
103   /* extract bits for pressed key row */
104   int control_key[] =
105   {
106       b[1]>>4 & 1,  /* Control Key A */
107       b[1]>>2 & 1,  /* Control Key B */
108       b[1]    & 1,  /* Control Key C */
109       b[2]>>6 & 1,  /* Control Key D */
110       b[2]>>4 & 1,  /* Control Key E (does not exists on the remote, but can
111                                         be set and is accepted by receiver) */
112   };
113
114   /* extrat on/off bits (first or second key column on the remote */
115   int on  = b[2]>>2 & 1;
116   int off = b[2]    & 1;
117
118   {
119     /* Test if the message is valid. It is possible to press multiple keys on the
120      * remote at the same time.  As all keys are transmitted orthogonally, this
121      * information can be transmitted.  This use case is not the usual use case
122      * so we can use it for validation of the message:
123      * ONLY ONE KEY AT A TIME IS ACCEPTED.
124      */
125     int found=0;
126     for( size_t i=0; i<sizeof(control_key)/sizeof(*control_key); i++)
127     {
128       if (control_key[i]) {
129         if (found)
130           return 0; /* at least two buttons have been pressed, reject the message */
131         else
132           found = 1;
133       }
134     }
135
136     if (! (on ^ off ) )
137       return 0;  /* Pressing simultaneously ON and OFF key is not useful either */
138   }
139
140   char key = 0;
141   if      (control_key[0]) key = 'A';
142   else if (control_key[1]) key = 'B';
143   else if (control_key[2]) key = 'C';
144   else if (control_key[3]) key = 'D';
145   else if (control_key[4]) key = 'E';
146   else return 0; /* None of the keys has been pressed and we still received a message.
147                     Skip it. It happens sometimes as the last code repetition */
148
149   {
150     /* @todo: remove timestamp printing as soon as the controller takes this task */
151     char time_str[LOCAL_TIME_BUFLEN];
152     local_time_str(0, time_str);
153     fprintf(stdout, "%s Brennenstuhl RCS 2044: system code: %d%d%d%d%d. key: %c, state: %s\n",
154       time_str,
155       system_code[0], system_code[1], system_code[2], system_code[3], system_code[4],
156       key,
157       on ? "ON" : ( off ? "OFF" : "BOTH" ) /* "BOTH" is excluded above, but leave it here for debug purposes */
158     );
159   }
160
161   return 1;
162 }
163
164 static int brennenstuhl_rcs_2044_callback(bitbuffer_t *bitbuffer)
165 {
166   int counter = 0;
167   for(int row=0; row<bitbuffer->num_rows; row++)
168     counter += brennenstuhl_rcs_2044_process_row(row, bitbuffer);
169   return counter;
170 }
171
172 r_device brennenstuhl_rcs_2044 = {
173   .name          = "Brennenstuhl RCS 2044",
174   .modulation    = OOK_PULSE_PWM_RAW,
175   .short_limit   = 600,
176   .long_limit    = 4000,
177   .reset_limit   = 4000,
178   .json_callback = &brennenstuhl_rcs_2044_callback,
179   .disabled      = 1,
180   .demod_arg     = 0,
181 };