Wed, 13 Aug 2014 21:48:57 +0200
Bumped to version 0.1.0
180 | 1 | /***************************************************************************** |
2 | * Copyright (C) 2014 | |
3 | * | |
4 | * Michiel Broek <mbroek at mbse dot eu> | |
5 | * | |
6 | * This file is part of the mbsePi-apps | |
7 | * | |
8 | * Based on the Arduino libary for remote control outlet switches. | |
9 | * Project home: http://code.google.com/p/rc-switch/ | |
10 | * | |
11 | * This is free software; you can redistribute it and/or modify it | |
12 | * under the terms of the GNU General Public License as published by the | |
13 | * Free Software Foundation; either version 2, or (at your option) any | |
14 | * later version. | |
15 | * | |
16 | * mbsePi-apps is distributed in the hope that it will be useful, but | |
17 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 | * General Public License for more details. | |
20 | * | |
21 | * You should have received a copy of the GNU General Public License | |
213
2317b8d644fa
Code cleanup, streamlined error messages.
Michiel Broek <mbroek@mbse.eu>
parents:
180
diff
changeset
|
22 | * along with ThermFerm; see the file COPYING. If not, write to the Free |
180 | 23 | * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
24 | *****************************************************************************/ | |
25 | ||
26 | #include "thermferm.h" | |
27 | #include "xutil.h" | |
28 | #include "rc-switch.h" | |
29 | ||
30 | #ifdef HAVE_WIRINGPI_H | |
31 | ||
32 | ||
33 | #define TYPE_UNDEF 0 | |
34 | #define TYPE_MINIMUM 0 | |
35 | #define TYPE_A 1 | |
36 | #define TYPE_B 2 | |
37 | #define TYPE_C 3 | |
38 | #define TYPE_D 4 | |
39 | #define TYPE_E 3 // TODO: Which Protocol does REV use? | |
40 | #define TYPE_MAXIMUM 4 | |
41 | ||
42 | // Number of maximum High/Low changes per packet. | |
43 | // We can handle up to (unsigned long) => 32 bit * 2 H/L changes per bit + 2 for sync | |
44 | #define RCSWITCH_MAX_CHANGES 67 | |
45 | ||
46 | // i.e. ProtocolCount + 1 (for TYPE_UNDEF) | |
47 | #define MAX_PROTOCOLS 5 | |
48 | ||
49 | #define PROTOCOL_A_SYNC_FACTOR 31 | |
50 | #define PROTOCOL_A_ZERO_FIRST_CYCLES 1 | |
51 | #define PROTOCOL_A_ZERO_SECOND_CYCLES 3 | |
52 | #define PROTOCOL_A_ONE_FIRST_CYCLES 3 | |
53 | #define PROTOCOL_A_ONE_SECOND_CYCLES 1 | |
54 | #define PROTOCOL_A_HIGH_FIRST TRUE | |
55 | ||
56 | #define PROTOCOL_B_SYNC_FACTOR 10 | |
57 | #define PROTOCOL_B_ZERO_FIRST_CYCLES 1 | |
58 | #define PROTOCOL_B_ZERO_SECOND_CYCLES 2 | |
59 | #define PROTOCOL_B_ONE_FIRST_CYCLES 2 | |
60 | #define PROTOCOL_B_ONE_SECOND_CYCLES 1 | |
61 | #define PROTOCOL_B_HIGH_FIRST TRUE | |
62 | ||
63 | #define PROTOCOL_C_SYNC_FACTOR 71 | |
64 | #define PROTOCOL_C_ZERO_FIRST_CYCLES 4 | |
65 | #define PROTOCOL_C_ZERO_SECOND_CYCLES 11 | |
66 | #define PROTOCOL_C_ONE_FIRST_CYCLES 9 | |
67 | #define PROTOCOL_C_ONE_SECOND_CYCLES 6 | |
68 | #define PROTOCOL_C_HIGH_FIRST TRUE | |
69 | ||
70 | // I think, this will work for receive, however, I haven't tested, as I don't own a receiver... | |
71 | // As Type D doesn't sync acc. to https://github.com/d-a-n/433-codes/blob/master/database.md#quigg | |
72 | // the sync factor is totally undetermined. | |
73 | // Malte Diers, 22.11.2013 | |
74 | #define PROTOCOL_D_SYNC_FACTOR 1 | |
75 | #define PROTOCOL_D_ZERO_FIRST_CYCLES 1 | |
76 | #define PROTOCOL_D_ZERO_SECOND_CYCLES 2 | |
77 | #define PROTOCOL_D_ONE_FIRST_CYCLES 2 | |
78 | #define PROTOCOL_D_ONE_SECOND_CYCLES 1 | |
79 | #define PROTOCOL_D_HIGH_FIRST FALSE | |
80 | ||
81 | ||
82 | #define PROTOCOL3_SYNC_FACTOR 71 | |
83 | #define PROTOCOL3_0_HIGH_CYCLES 4 | |
84 | #define PROTOCOL3_0_LOW_CYCLES 11 | |
85 | #define PROTOCOL3_1_HIGH_CYCLES 9 | |
86 | #define PROTOCOL3_1_LOW_CYCLES 6 | |
87 | ||
88 | ||
89 | ||
90 | unsigned long rcReceivedValue = 0; | |
91 | unsigned int rcReceivedBitlength = 0; | |
92 | unsigned int rcReceivedDelay = 0; | |
93 | unsigned int rcReceivedProtocol = 0; | |
94 | int rcReceiveTolerance = 60; | |
95 | int rcReceiverInterruptPin = -1; | |
96 | ||
97 | unsigned int timings[RCSWITCH_MAX_CHANGES]; | |
98 | int rcTransmitterPin = -1; | |
99 | int rcPulseLength = 350; // thermometers 2.4 msec = 2400 | |
100 | int rcRepeatTransmit = 10; | |
101 | int rcProtocol = 1; | |
102 | ||
103 | int backupProtocol; | |
104 | int backupPulseLength; | |
105 | int backupRepeatTransmit; | |
106 | ||
107 | ||
108 | //const char TYPE_A_CODE[ 6][6] = { "00000", "10000", "01000", "00100", "00010", "00001"}; | |
109 | const char TYPE_B_CODE[ 5][5] = { "FFFF", "0FFF", "F0FF", "FF0F", "FFF0" }; | |
110 | const char TYPE_C_CODE[16][5] = { "0000", "F000", "0F00", "FF00", "00F0", "F0F0", "0FF0", "FFF0", | |
111 | "000F", "F00F", "0F0F", "FF0F", "00FF", "F0FF", "0FFF", "FFFF" }; | |
112 | const char TYPE_D_CODE[5][2][9] = { { "11100001", "11110000" }, { "00000000", "00010001" }, { "10000010", "10010011" }, | |
113 | { "11000011", "11010010" }, { "01000001", "01010000" } }; | |
114 | /* Type A Type D */ | |
115 | const int PULSE_LENGTH[MAX_PROTOCOLS] = { 0, 350, 650, 100, 666, }; | |
116 | const int REPEAT_TRANSMIT[MAX_PROTOCOLS] = { 0, 10, 10, 10, 4, }; | |
117 | const int SYNC_FACTOR[MAX_PROTOCOLS] = { 0, PROTOCOL_A_SYNC_FACTOR, PROTOCOL_B_SYNC_FACTOR, PROTOCOL_C_SYNC_FACTOR, PROTOCOL_D_SYNC_FACTOR, }; | |
118 | const int ZERO_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_FIRST_CYCLES, PROTOCOL_B_ZERO_FIRST_CYCLES, PROTOCOL_C_ZERO_FIRST_CYCLES, PROTOCOL_D_ZERO_FIRST_CYCLES, }; | |
119 | const int ZERO_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ZERO_SECOND_CYCLES, PROTOCOL_B_ZERO_SECOND_CYCLES, PROTOCOL_C_ZERO_SECOND_CYCLES, PROTOCOL_D_ZERO_SECOND_CYCLES, }; | |
120 | const int ONE_FIRST_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_FIRST_CYCLES, PROTOCOL_B_ONE_FIRST_CYCLES, PROTOCOL_C_ONE_FIRST_CYCLES, PROTOCOL_D_ONE_FIRST_CYCLES, }; | |
121 | const int ONE_SECOND_CYCLES[MAX_PROTOCOLS] = { 0, PROTOCOL_A_ONE_SECOND_CYCLES, PROTOCOL_B_ONE_SECOND_CYCLES, PROTOCOL_C_ONE_SECOND_CYCLES, PROTOCOL_D_ONE_SECOND_CYCLES, }; | |
122 | const int HIGH_FIRST[MAX_PROTOCOLS] = { 0, PROTOCOL_A_HIGH_FIRST, PROTOCOL_B_HIGH_FIRST, PROTOCOL_C_HIGH_FIRST, PROTOCOL_D_HIGH_FIRST, }; | |
123 | ||
124 | ||
125 | char *getCodeWordA(char*, char*, int); | |
126 | char *getCodeWordB(int, int, int); | |
127 | char *getCodeWordC(char, int, int, int); | |
128 | ||
129 | char *getCodeWordE(char, int, int); | |
130 | void sendTriState(char*); | |
131 | void transmit(int, int, int); | |
132 | void send0(void); | |
133 | void send1(void); | |
134 | void sendT0(void); | |
135 | void sendT1(void); | |
136 | void sendTF(void); | |
137 | void sendSync(void); | |
138 | int receiveProtocol(int, unsigned int); | |
139 | void handleInterrupt(void); | |
140 | char *dec2binWcharfill(unsigned long, unsigned int, char); | |
141 | ||
142 | void setReceiveTolerance(int); | |
143 | void setProtocol(int); | |
144 | ||
145 | void saveProtocol(int); | |
146 | void loadProtocol(void); | |
147 | ||
148 | ||
149 | ||
150 | /* | |
151 | * Sets the protocol to send. | |
152 | */ | |
153 | void setProtocol(int nProtocol) { | |
154 | ||
155 | if ((nProtocol < TYPE_MINIMUM) || (nProtocol > TYPE_MAXIMUM)) { | |
156 | return; | |
157 | } | |
158 | ||
159 | rcProtocol = nProtocol; | |
160 | rcPulseLength = PULSE_LENGTH[nProtocol]; | |
161 | rcRepeatTransmit = REPEAT_TRANSMIT[nProtocol]; | |
162 | } | |
163 | ||
164 | ||
165 | ||
166 | /* | |
167 | * Set Receiving Tolerance | |
168 | */ | |
169 | void setReceiveTolerance(int nPercent) { | |
170 | rcReceiveTolerance = nPercent; | |
171 | } | |
172 | ||
173 | ||
174 | ||
175 | /* | |
176 | * Enable transmissions | |
177 | * | |
178 | * @param nTransmitterPin Pin to which the sender is connected to | |
179 | */ | |
180 | void enableTransmit(int nTransmitterPin) { | |
181 | rcTransmitterPin = nTransmitterPin; | |
182 | pinMode(rcTransmitterPin, OUTPUT); | |
183 | } | |
184 | ||
185 | ||
186 | ||
187 | /* | |
188 | * Disable transmissions | |
189 | */ | |
190 | void disableTransmit(void) { | |
191 | rcTransmitterPin = -1; | |
192 | } | |
193 | ||
194 | ||
195 | ||
196 | /* | |
197 | * Toggle switch, a command looks like B,3,2,1 which means switch type B, | |
198 | * group 3, device 2, status on. | |
199 | */ | |
200 | int toggleSwitch(char *command) | |
201 | { | |
202 | static char *cmd = NULL; | |
203 | char *s, cType; | |
204 | int rc, iGroup, iDevice, iState; | |
205 | ||
206 | cmd = xstrcpy(command); | |
207 | s = strtok(cmd, ",\0"); | |
208 | cType = s[0]; | |
209 | ||
210 | if (cType == 'A') { | |
211 | ||
212 | } else if (cType == 'B') { | |
213 | s = strtok(NULL, ",\0"); | |
214 | rc = sscanf(s, "%d", &iGroup); | |
215 | if (rc != 1) | |
216 | return 1; | |
217 | s = strtok(NULL, ",\0"); | |
218 | rc = sscanf(s, "%d", &iDevice); | |
219 | if (rc != 1) | |
220 | return 1; | |
221 | s = strtok(NULL, ",\0"); | |
222 | rc = sscanf(s, "%d", &iState); | |
223 | if (rc != 1) | |
224 | return 1; | |
225 | free(cmd); | |
226 | return toggleTypeB(iGroup, iDevice, iState); | |
227 | } | |
228 | ||
229 | free(cmd); | |
230 | return 1; | |
231 | } | |
232 | ||
233 | ||
234 | ||
235 | /* | |
236 | * Switch a remote switch on (Type E REV) | |
237 | * | |
238 | * @param sGroup Code of the switch group (A,B,C,D) | |
239 | * @param nDevice Number of the switch itself (1..3) | |
240 | * @param bStatus Status to toggle to | |
241 | */ | |
242 | int toggleTypeE(char sGroup, int nDevice, int bStatus) { | |
243 | sendTriState( getCodeWordE(sGroup, nDevice, bStatus) ); | |
244 | return 0; | |
245 | } | |
246 | ||
247 | ||
248 | ||
249 | /* | |
250 | * Switch a remote switch on (Type C Intertechno) | |
251 | * | |
252 | * @param sFamily Familycode (a..f) | |
253 | * @param nGroup Number of group (1..4) | |
254 | * @param nDevice Number of device (1..4) | |
255 | * @param bStatus Status to toggle to | |
256 | */ | |
257 | int toggleTypeC(char sFamily, int nGroup, int nDevice, int bStatus) { | |
258 | char *str = xstrcpy(getCodeWordC(sFamily, nGroup, nDevice, bStatus)); | |
259 | ||
260 | if (strlen(str) == 0) | |
261 | return 1; | |
262 | ||
263 | saveProtocol(TYPE_A); // ??? | |
264 | sendTriState( str ); | |
265 | loadProtocol(); | |
266 | free(str); | |
267 | return 0; | |
268 | } | |
269 | ||
270 | ||
271 | ||
272 | /* | |
273 | * Switch a remote switch on/off (Type B with two rotary/sliding switches) | |
274 | * | |
275 | * @param iGroup Number of the switch group (1..4) | |
276 | * @param iDevice Number of the switch itself (1..4) | |
277 | * @param bStatus Status to toggle to | |
278 | */ | |
279 | int toggleTypeB(int iGroup, int iDevice, int bStatus) | |
280 | { | |
281 | char *str = xstrcpy(getCodeWordB(iGroup, iDevice, bStatus)); | |
282 | ||
283 | if (strlen(str) == 0) | |
284 | return 1; | |
285 | ||
286 | saveProtocol(TYPE_A); // They do better with protocol A timings. | |
287 | sendTriState( str ); | |
288 | loadProtocol(); | |
289 | free(str); | |
290 | return 0; | |
291 | } | |
292 | ||
293 | ||
294 | ||
295 | /* | |
296 | * Switch a remote switch on (Type A with 10 pole DIP switches) | |
297 | * | |
298 | * @param sGroup Code of the switch group (refers to DIP switches 1..5 where "1" = on and "0" = off, if all DIP switches are on it's "11111") | |
299 | * @param sDevice Code of the switch device (refers to DIP switches 6..10 (A..E) where "1" = on and "0" = off, if all DIP switches are on it's "11111") | |
300 | * @param bStatus Status to toggle to | |
301 | */ | |
302 | int toggleTypeA(char* sGroup, char* sDevice, int bStatus) { | |
303 | char *str = xstrcpy(getCodeWordA(sGroup, sDevice, bStatus)); | |
304 | ||
305 | if (strlen(str) == 0) | |
306 | return 1; | |
307 | ||
308 | saveProtocol(TYPE_A); | |
309 | sendTriState( str ); | |
310 | loadProtocol(); | |
311 | free(str); | |
312 | return 0; | |
313 | } | |
314 | ||
315 | ||
316 | ||
317 | /* | |
318 | * Returns a char[13], representing the Code Word to be send. | |
319 | * A Code Word consists of 9 address bits, 3 data bits and one sync bit but in our case only the first 8 address bits and the last 2 data bits were used. | |
320 | * A Code Bit can have 4 different states: "F" (floating), "0" (low), "1" (high), "S" (synchronous bit) | |
321 | * | |
322 | * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ | |
323 | * | 4 bits address (switch group) | 4 bits address (switch number) | 1 bit address (not used, so never mind) | 1 bit address (not used, so never mind) | 2 data bits (on|off) | 1 sync bit | | |
324 | * | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | F | F | on=FF off=F0 | S | | |
325 | * +-------------------------------+--------------------------------+-----------------------------------------+-----------------------------------------+----------------------+------------+ | |
326 | * | |
327 | * @param nAddressCode Number of the switch group (1..4) | |
328 | * @param nChannelCode Number of the switch itself (1..4) | |
329 | * @param bStatus Wether to switch on (true) or off (false) | |
330 | * | |
331 | * @return char[13] | |
332 | */ | |
333 | char *getCodeWordB(int nAddressCode, int nChannelCode, int bStatus) | |
334 | { | |
335 | int i, nReturnPos = 0; | |
336 | static char sReturn[13]; | |
337 | ||
338 | if (nAddressCode < 1 || nAddressCode > 4 || nChannelCode < 1 || nChannelCode > 4) { | |
339 | return '\0'; | |
340 | } | |
341 | for (i = 0; i<4; i++) { | |
342 | sReturn[nReturnPos++] = TYPE_B_CODE[nAddressCode][i]; | |
343 | } | |
344 | ||
345 | for (i = 0; i<4; i++) { | |
346 | sReturn[nReturnPos++] = TYPE_B_CODE[nChannelCode][i]; | |
347 | } | |
348 | ||
349 | sReturn[nReturnPos++] = 'F'; | |
350 | sReturn[nReturnPos++] = 'F'; | |
351 | sReturn[nReturnPos++] = 'F'; | |
352 | sReturn[nReturnPos++] = bStatus ? 'F' : '0'; | |
353 | sReturn[nReturnPos] = '\0'; | |
354 | ||
355 | return sReturn; | |
356 | } | |
357 | ||
358 | ||
359 | ||
360 | /* | |
361 | * Returns a char[13], representing the Code Word to be send. | |
362 | * | |
363 | * getCodeWordA(char*, char*) | |
364 | * | |
365 | */ | |
366 | char *getCodeWordA(char* sGroup, char* sDevice, int bOn) | |
367 | { | |
368 | static char sDipSwitches[13]; | |
369 | int i, j = 0; | |
370 | ||
371 | for (i=0; i < 5; i++) { | |
372 | sDipSwitches[j++] = (sGroup[i] == '0') ? 'F' : '0'; | |
373 | } | |
374 | ||
375 | for (i=0; i < 5; i++) { | |
376 | sDipSwitches[j++] = (sDevice[i] == '0') ? 'F' : '0'; | |
377 | } | |
378 | ||
379 | if ( bOn ) { | |
380 | sDipSwitches[j++] = '0'; | |
381 | sDipSwitches[j++] = 'F'; | |
382 | } else { | |
383 | sDipSwitches[j++] = 'F'; | |
384 | sDipSwitches[j++] = '0'; | |
385 | } | |
386 | ||
387 | sDipSwitches[j] = '\0'; | |
388 | return sDipSwitches; | |
389 | } | |
390 | ||
391 | ||
392 | ||
393 | /* | |
394 | * Like getCodeWord (Type C = Intertechno) | |
395 | */ | |
396 | char *getCodeWordC(char sFamily, int nGroup, int nDevice, int bStatus) | |
397 | { | |
398 | static char sReturn[13]; | |
399 | int i, nReturnPos = 0; | |
400 | ||
401 | if (sFamily < 'a') { | |
402 | // To also enable capital 'A' to 'F' | |
403 | sFamily += 32; | |
404 | } | |
405 | ||
406 | if ( sFamily < 'a' || sFamily > 'f' || nGroup < 1 || nGroup > 4 || nDevice < 1 || nDevice > 4) { | |
407 | return '\0'; | |
408 | } | |
409 | ||
410 | for (i = 0; i<4; i++) { | |
411 | sReturn[nReturnPos++] = TYPE_C_CODE[ sFamily - 'a' ][i]; | |
412 | } | |
413 | ||
414 | char *sDeviceGroupCode = dec2binWzerofill( (nDevice-1) + (nGroup-1)*4, 4 ); | |
415 | for (i = 0; i<4; i++) { | |
416 | sReturn[nReturnPos++] = (sDeviceGroupCode[3-i] == '1' ? 'F' : '0'); | |
417 | } | |
418 | ||
419 | sReturn[nReturnPos++] = '0'; | |
420 | sReturn[nReturnPos++] = 'F'; | |
421 | sReturn[nReturnPos++] = 'F'; | |
422 | sReturn[nReturnPos++] = bStatus ? 'F' : '0'; | |
423 | sReturn[nReturnPos] = '\0'; | |
424 | ||
425 | return sReturn; | |
426 | } | |
427 | ||
428 | ||
429 | ||
430 | /* | |
431 | * Decoding for the Quigg Switch Type | |
432 | * | |
433 | * Returns a char[22], representing the States to be send. | |
434 | * A Code Word consists of 1 start bit, 12 address bits and 8 command data bits. | |
435 | * A Code Bit can have 2 different states: "0" (low), "1" (high) | |
436 | * | |
437 | * +--------------+--------------------------------+------------------------------+ | |
438 | * | 1 bits start | 12 bits address (device group) | 8 bits (command/switch data) | | |
439 | * | 1 | 110011001100 | 00010001 | | |
440 | * +--------------+--------------------------------+------------------------------+ | |
441 | * | |
442 | * Source: https://github.com/d-a-n/433-codes/blob/master/database.md#quigg | |
443 | * | |
444 | * @param sGroup 12-bit Binary ID of the Device Group | |
445 | * @param nDevice Number of the switch itself (1..4, or 0 to switch the entire Group) | |
446 | * @param bStatus Wether to switch on (true) or off (false) | |
447 | * | |
448 | * @return char[22] | |
449 | */ | |
450 | char *getCodeWordD(char *sGroup, int nDevice, int bStatus) | |
451 | { | |
452 | static char sReturn[22]; | |
453 | int i, nReturnPos = 0; | |
454 | ||
455 | /* Startbit */ | |
456 | sReturn[nReturnPos++] = '1'; | |
457 | ||
458 | /* 12 bit Group */ | |
459 | for (i = 0; i < 12; ++i) { | |
460 | sReturn[nReturnPos++] = sGroup[i]; | |
461 | } | |
462 | ||
463 | /* 8 Bit Device Identifier + Status (undividable!) */ | |
464 | for (i = 0; i < 8; ++i) { | |
465 | sReturn[nReturnPos++] = TYPE_D_CODE[nDevice][bStatus][i]; | |
466 | } | |
467 | sReturn[nReturnPos] = 0; | |
468 | ||
469 | return sReturn; | |
470 | } | |
471 | ||
472 | ||
473 | ||
474 | /* | |
475 | * Decoding for the REV Switch Type | |
476 | * | |
477 | * Returns a char[13], representing the Tristate to be send. | |
478 | * A Code Word consists of 7 address bits and 5 command data bits. | |
479 | * A Code Bit can have 3 different states: "F" (floating), "0" (low), "1" (high) | |
480 | * | |
481 | * +-------------------------------+--------------------------------+-----------------------+ | |
482 | * | 4 bits address (switch group) | 3 bits address (device number) | 5 bits (command data) | | |
483 | * | A=1FFF B=F1FF C=FF1F D=FFF1 | 1=0FFF 2=F0FF 3=FF0F 4=FFF0 | on=00010 off=00001 | | |
484 | * +-------------------------------+--------------------------------+-----------------------+ | |
485 | * | |
486 | * Source: http://www.the-intruder.net/funksteckdosen-von-rev-uber-arduino-ansteuern/ | |
487 | * | |
488 | * @param sGroup Name of the switch group (A..D, resp. a..d) | |
489 | * @param nDevice Number of the switch itself (1..3) | |
490 | * @param bStatus Wether to switch on (true) or off (false) | |
491 | * | |
492 | * @return char[13] | |
493 | */ | |
494 | char *getCodeWordE(char sGroup, int nDevice, int bStatus){ | |
495 | static char sReturn[13]; | |
496 | int i, nReturnPos = 0; | |
497 | ||
498 | // Building 4 bits address | |
499 | // (Potential problem if dec2binWcharfill not returning correct string) | |
500 | char *sGroupCode; | |
501 | switch(sGroup){ | |
502 | case 'a': | |
503 | case 'A': | |
504 | sGroupCode = dec2binWcharfill(8, 4, 'F'); break; | |
505 | case 'b': | |
506 | case 'B': | |
507 | sGroupCode = dec2binWcharfill(4, 4, 'F'); break; | |
508 | case 'c': | |
509 | case 'C': | |
510 | sGroupCode = dec2binWcharfill(2, 4, 'F'); break; | |
511 | case 'd': | |
512 | case 'D': | |
513 | sGroupCode = dec2binWcharfill(1, 4, 'F'); break; | |
514 | default: | |
515 | return '\0'; | |
516 | } | |
517 | ||
518 | for (i = 0; i<4; i++) { | |
519 | sReturn[nReturnPos++] = sGroupCode[i]; | |
520 | } | |
521 | ||
522 | ||
523 | // Building 3 bits address | |
524 | // (Potential problem if dec2binWcharfill not returning correct string) | |
525 | char *sDevice; | |
526 | switch(nDevice) { | |
527 | case 1: | |
528 | sDevice = dec2binWcharfill(4, 3, 'F'); break; | |
529 | case 2: | |
530 | sDevice = dec2binWcharfill(2, 3, 'F'); break; | |
531 | case 3: | |
532 | sDevice = dec2binWcharfill(1, 3, 'F'); break; | |
533 | default: | |
534 | return '\0'; | |
535 | } | |
536 | ||
537 | for (i = 0; i<3; i++) | |
538 | sReturn[nReturnPos++] = sDevice[i]; | |
539 | ||
540 | // fill up rest with zeros | |
541 | for (i = 0; i<5; i++) | |
542 | sReturn[nReturnPos++] = '0'; | |
543 | ||
544 | // encode on or off | |
545 | if (bStatus) | |
546 | sReturn[10] = '1'; | |
547 | else | |
548 | sReturn[11] = '1'; | |
549 | ||
550 | // last position terminate string | |
551 | sReturn[12] = '\0'; | |
552 | return sReturn; | |
553 | ||
554 | } | |
555 | ||
556 | ||
557 | ||
558 | /* | |
559 | * @param sCodeWord /^[10FS]*$/ -> see getCodeWord | |
560 | */ | |
561 | void sendTriState(char* sCodeWord) { | |
562 | int nRepeat; | |
563 | ||
564 | for (nRepeat = 0; nRepeat < rcRepeatTransmit; nRepeat++) { | |
565 | int i = 0; | |
566 | while (sCodeWord[i] != '\0') { | |
567 | switch(sCodeWord[i]) { | |
568 | case '0': | |
569 | sendT0(); | |
570 | break; | |
571 | case 'F': | |
572 | sendTF(); | |
573 | break; | |
574 | case '1': | |
575 | sendT1(); | |
576 | break; | |
577 | } | |
578 | i++; | |
579 | } | |
580 | sendSync(); | |
581 | } | |
582 | } | |
583 | ||
584 | ||
585 | ||
586 | void transmit(int nFirstPulses, int nSecondPulses, int bHighFirst) | |
587 | { | |
588 | int disabled_Receive = FALSE; | |
589 | int nReceiverInterrupt_backup = rcReceiverInterruptPin; | |
590 | ||
591 | if (rcTransmitterPin != -1) { | |
592 | if (rcReceiverInterruptPin != -1) { | |
593 | disableReceive(); | |
594 | disabled_Receive = TRUE; | |
595 | } | |
596 | digitalWrite(rcTransmitterPin, bHighFirst ? HIGH : LOW); | |
597 | delayMicroseconds( rcPulseLength * nFirstPulses); | |
598 | digitalWrite(rcTransmitterPin, bHighFirst ? LOW : HIGH); | |
599 | delayMicroseconds( rcPulseLength * nSecondPulses); | |
600 | ||
601 | if (disabled_Receive) { | |
602 | enableReceiveIRQ(nReceiverInterrupt_backup); | |
603 | } | |
604 | } | |
605 | } | |
606 | ||
607 | ||
608 | ||
609 | /* | |
610 | * Sends a Tri-State "0" Bit | |
611 | * _ _ | |
612 | * Waveform: | |___| |___ | |
613 | */ | |
614 | void sendT0(void) { | |
615 | transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); | |
616 | transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); | |
617 | } | |
618 | ||
619 | ||
620 | ||
621 | /* | |
622 | * Sends a Tri-State "1" Bit | |
623 | * ___ ___ | |
624 | * Waveform: | |_| |_ | |
625 | */ | |
626 | void sendT1(void) { | |
627 | transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); | |
628 | transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); | |
629 | } | |
630 | ||
631 | ||
632 | ||
633 | /* | |
634 | * Sends a Tri-State "F" Bit | |
635 | * _ ___ | |
636 | * Waveform: | |___| |_ | |
637 | */ | |
638 | void sendTF(void) { | |
639 | transmit(ZERO_FIRST_CYCLES[rcProtocol], ZERO_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); | |
640 | transmit(ONE_FIRST_CYCLES[rcProtocol], ONE_SECOND_CYCLES[rcProtocol], HIGH_FIRST[rcProtocol]); | |
641 | } | |
642 | ||
643 | ||
644 | ||
645 | /* | |
646 | * Sends a "Sync" Bit | |
647 | * _ | |
648 | * Waveform Protocol 1: | |_______________________________ | |
649 | * _ | |
650 | * Waveform Protocol 2: | |__________ | |
651 | * ____ | |
652 | * Waveform Protocol 3: | |_______________________________________________________________________ | |
653 | * | |
654 | * Waveform Protocol D: (none, just pause 80 msecs) | |
655 | */ | |
656 | void sendSync(void) { | |
657 | ||
658 | if (rcProtocol == TYPE_A) { | |
659 | transmit(1,31,TRUE); | |
660 | } else if (rcProtocol == TYPE_B) { | |
661 | transmit(1,10,TRUE); | |
662 | } else if (rcProtocol == TYPE_C) { | |
663 | transmit(4,71,TRUE); | |
664 | } else if (rcProtocol == TYPE_D) { | |
665 | transmit(0,1,FALSE); | |
666 | delayMicroseconds(80000); | |
667 | } | |
668 | } | |
669 | ||
670 | ||
671 | ||
672 | /* | |
673 | * Enable receiving data | |
674 | */ | |
675 | void enableReceiveIRQ(int Pin) { | |
676 | rcReceiverInterruptPin = Pin; | |
677 | enableReceive(); | |
678 | } | |
679 | ||
680 | void enableReceive(void) { | |
681 | if (rcReceiverInterruptPin != -1) { | |
682 | rcReceivedValue = 0; | |
683 | rcReceivedBitlength = 0; | |
684 | wiringPiISR(rcReceiverInterruptPin, INT_EDGE_BOTH, &handleInterrupt); | |
685 | } | |
686 | } | |
687 | ||
688 | ||
689 | ||
690 | /* | |
691 | * Disable receiving data | |
692 | */ | |
693 | void disableReceive() { | |
694 | // wiringPi disable interrupts ??? | |
695 | rcReceiverInterruptPin = -1; | |
696 | } | |
697 | ||
698 | ||
699 | ||
700 | int available(void) { | |
701 | return rcReceivedValue != 0; | |
702 | } | |
703 | ||
704 | ||
705 | ||
706 | void resetAvailable(void) { | |
707 | rcReceivedValue = 0; | |
708 | } | |
709 | ||
710 | ||
711 | ||
712 | unsigned long getReceivedValue(void) { | |
713 | return rcReceivedValue; | |
714 | } | |
715 | ||
716 | ||
717 | ||
718 | unsigned int getReceivedBitlength(void) { | |
719 | return rcReceivedBitlength; | |
720 | } | |
721 | ||
722 | ||
723 | ||
724 | unsigned int getReceivedDelay(void) { | |
725 | return rcReceivedDelay; | |
726 | } | |
727 | ||
728 | ||
729 | ||
730 | unsigned int getReceivedProtocol(void) { | |
731 | return rcReceivedProtocol; | |
732 | } | |
733 | ||
734 | ||
735 | ||
736 | unsigned int* getReceivedRawdata(void) { | |
737 | return timings; | |
738 | } | |
739 | ||
740 | ||
741 | ||
742 | /* | |
743 | * ASK protool 1 | |
744 | */ | |
745 | int receiveProtocol(int prot, unsigned int changeCount) | |
746 | { | |
747 | unsigned long code = 0; | |
748 | unsigned long ldelay = timings[0] / SYNC_FACTOR[prot]; | |
749 | unsigned long delayTolerance = ldelay * rcReceiveTolerance * 0.01; | |
750 | int i; | |
751 | ||
752 | if (prot < TYPE_MINIMUM || prot > TYPE_MAXIMUM) { | |
753 | return FALSE; | |
754 | } | |
755 | ||
756 | for (i = 1; i<changeCount ; i=i+2) { | |
757 | ||
758 | if (timings[i] > ldelay * ZERO_FIRST_CYCLES[prot] - delayTolerance && | |
759 | timings[i] < ldelay * ZERO_FIRST_CYCLES[prot] + delayTolerance && | |
760 | timings[i+1] > ldelay * ZERO_SECOND_CYCLES[prot] - delayTolerance && | |
761 | timings[i+1] < ldelay * ZERO_SECOND_CYCLES[prot] + delayTolerance) { | |
762 | code = code << 1; | |
763 | } else if (timings[i] > ldelay * ONE_FIRST_CYCLES[prot] - delayTolerance && | |
764 | timings[i] < ldelay * ONE_FIRST_CYCLES[prot] + delayTolerance && | |
765 | timings[i+1] > ldelay * ONE_SECOND_CYCLES[prot] - delayTolerance && | |
766 | timings[i+1] < ldelay * ONE_SECOND_CYCLES[prot] + delayTolerance) { | |
767 | code+=1; | |
768 | code = code << 1; | |
769 | } else { | |
770 | // Failed | |
771 | i = changeCount; | |
772 | code = 0; | |
773 | } | |
774 | } | |
775 | code = code >> 1; | |
776 | if (changeCount > 6) { // ignore < 4bit values as there are no devices sending 4bit values => noise | |
777 | rcReceivedValue = code; | |
778 | rcReceivedBitlength = changeCount / 2; | |
779 | rcReceivedDelay = ldelay; | |
780 | rcReceivedProtocol = prot; | |
781 | } | |
782 | ||
783 | return (code != 0); | |
784 | } | |
785 | ||
786 | ||
787 | ||
788 | void handleInterrupt() { | |
789 | ||
790 | static unsigned int duration; | |
791 | static unsigned int changeCount; | |
792 | static unsigned long lastTime; | |
793 | static unsigned int repeatCount; | |
794 | ||
795 | ||
796 | long thistime = micros(); | |
797 | duration = thistime - lastTime; | |
798 | ||
799 | if (duration > 5000 && duration > timings[0] - 200 && duration < timings[0] + 200) { | |
800 | repeatCount++; | |
801 | changeCount--; | |
802 | if (repeatCount == 2) { | |
803 | if (receiveProtocol(TYPE_A, changeCount) == FALSE) { | |
804 | if (receiveProtocol(TYPE_B, changeCount) == FALSE) { | |
805 | if (receiveProtocol(TYPE_C, changeCount) == FALSE) { | |
806 | if (receiveProtocol(TYPE_D, changeCount) == FALSE) { | |
807 | //failed | |
808 | } | |
809 | } | |
810 | } | |
811 | } | |
812 | repeatCount = 0; | |
813 | } | |
814 | changeCount = 0; | |
815 | } else if (duration > 5000) { | |
816 | changeCount = 0; | |
817 | } | |
818 | ||
819 | if (changeCount >= RCSWITCH_MAX_CHANGES) { | |
820 | changeCount = 0; | |
821 | repeatCount = 0; | |
822 | } | |
823 | timings[changeCount++] = duration; | |
824 | lastTime = thistime; | |
825 | } | |
826 | ||
827 | ||
828 | ||
829 | /* | |
830 | * Turns a decimal value to its binary representation | |
831 | */ | |
832 | char *dec2binWzerofill(unsigned long Dec, unsigned int bitLength) | |
833 | { | |
834 | return dec2binWcharfill(Dec, bitLength, '0'); | |
835 | } | |
836 | ||
837 | char *dec2binWcharfill(unsigned long Dec, unsigned int bitLength, char fill) | |
838 | { | |
839 | static char bin[64]; | |
840 | unsigned int i = 0, j; | |
841 | ||
842 | while (Dec > 0) { | |
843 | bin[32+i++] = ((Dec & 1) > 0) ? '1' : fill; | |
844 | Dec = Dec >> 1; | |
845 | } | |
846 | ||
847 | for (j = 0; j< bitLength; j++) { | |
848 | if (j >= bitLength - i) { | |
849 | bin[j] = bin[ 31 + i - (j - (bitLength - i)) ]; | |
850 | } else { | |
851 | bin[j] = fill; | |
852 | } | |
853 | } | |
854 | bin[bitLength] = '\0'; | |
855 | ||
856 | return bin; | |
857 | } | |
858 | ||
859 | ||
860 | void saveProtocol(int prot) | |
861 | { | |
862 | backupProtocol = rcProtocol; | |
863 | backupPulseLength = rcPulseLength; | |
864 | backupRepeatTransmit = rcRepeatTransmit; | |
865 | ||
866 | setProtocol(prot); | |
867 | } | |
868 | ||
869 | ||
870 | ||
871 | void loadProtocol(void) | |
872 | { | |
873 | rcProtocol = backupProtocol; | |
874 | rcPulseLength = backupPulseLength; | |
875 | rcRepeatTransmit = backupRepeatTransmit; | |
876 | } | |
877 | ||
878 | ||
879 | #endif | |
880 |