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