Sat, 25 Apr 2020 20:31:31 +0200
Version 0.9.8. Added extra path to the fonts for Debian buster. Changed the PID to work on Proportional on Measurement. Added loops so that it looks like the PID is running at 100 mSec intervals.
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 |