1 /***************************************************************************** |
|
2 * Copyright (C) 2014..2015 |
|
3 * |
|
4 * Michiel Broek <mbroek at mbse dot eu> |
|
5 * |
|
6 * This file is part of the mbsePi-apps |
|
7 * |
|
8 * This is free software; you can redistribute it and/or modify it |
|
9 * under the terms of the GNU General Public License as published by the |
|
10 * Free Software Foundation; either version 2, or (at your option) any |
|
11 * later version. |
|
12 * |
|
13 * mbsePi-apps is distributed in the hope that it will be useful, but |
|
14 * WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
16 * General Public License for more details. |
|
17 * |
|
18 * You should have received a copy of the GNU General Public License |
|
19 * along with thermferm; see the file COPYING. If not, write to the Free |
|
20 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. |
|
21 *****************************************************************************/ |
|
22 |
|
23 #include "brewco.h" |
|
24 #include "devices.h" |
|
25 #include "util.h" |
|
26 #include "xutil.h" |
|
27 #include "keyboard.h" |
|
28 #include "slcd.h" |
|
29 |
|
30 |
|
31 extern int debug; |
|
32 extern sys_config Config; |
|
33 extern int my_shutdown; |
|
34 extern uint16_t leds; |
|
35 extern int slcdHandle; |
|
36 |
|
37 #ifdef USE_SIMULATOR |
|
38 |
|
39 extern int SIM_hlt_value; |
|
40 extern int SIM_mlt_value; |
|
41 |
|
42 #endif |
|
43 |
|
44 |
|
45 |
|
46 /* |
|
47 * Read one byte from a 1-wire device like a DS2413 |
|
48 */ |
|
49 int read_w1(char *address, char *file) |
|
50 { |
|
51 char *addr = NULL; |
|
52 int fn = -1, rc = -1, retries = 5; |
|
53 uint8_t val; |
|
54 |
|
55 addr = xstrcpy((char *)"/sys/bus/w1/devices/"); |
|
56 addr = xstrcat(addr, address); |
|
57 addr = xstrcat(addr, (char *)"/"); |
|
58 addr = xstrcat(addr, file); |
|
59 |
|
60 if ((fn = open(addr, O_RDONLY)) >= 0) { |
|
61 |
|
62 if ((lseek(fn, 0L, SEEK_SET)) == 0) { |
|
63 |
|
64 while (retries--) { |
|
65 if ((read(fn, &val, 1)) == 1) { |
|
66 rc = (int)val; |
|
67 goto leave; |
|
68 } |
|
69 } |
|
70 syslog(LOG_NOTICE, "read_w1() read %s fatal: %s", addr, strerror(errno)); |
|
71 |
|
72 } else { |
|
73 syslog(LOG_NOTICE, "read_w1() lseek %s: %s", addr, strerror(errno)); |
|
74 } |
|
75 |
|
76 } else { |
|
77 syslog(LOG_NOTICE, "read_w1() open %s: %s", addr, strerror(errno)); |
|
78 } |
|
79 |
|
80 leave: |
|
81 if (fn != -1) { |
|
82 if ((close(fn)) == -1) { |
|
83 syslog(LOG_NOTICE, "read_w1() close %s: %s", addr, strerror(errno)); |
|
84 } |
|
85 } |
|
86 |
|
87 free(addr); |
|
88 return rc; |
|
89 } |
|
90 |
|
91 |
|
92 |
|
93 /* |
|
94 * Write a byte to a 1-wire device like a DS2413 |
|
95 */ |
|
96 int write_w1(char *address, char *file, uint8_t val) |
|
97 { |
|
98 char *addr = NULL; |
|
99 int fn = -1, rc = -1, retries = 5; |
|
100 |
|
101 addr = xstrcpy((char *)"/sys/bus/w1/devices/"); |
|
102 addr = xstrcat(addr, address); |
|
103 addr = xstrcat(addr, (char *)"/"); |
|
104 addr = xstrcat(addr, file); |
|
105 |
|
106 if ((fn = open(addr, O_WRONLY)) >= 0) { |
|
107 |
|
108 if ((lseek(fn, 0L, SEEK_SET)) == 0) { |
|
109 |
|
110 while (retries--) { |
|
111 if ((write(fn, &val, 1)) == 1) { |
|
112 rc = 0; |
|
113 goto leave; |
|
114 } |
|
115 } |
|
116 syslog(LOG_NOTICE, "write_w1() write %s fatal: %s", addr, strerror(errno)); |
|
117 |
|
118 } else { |
|
119 syslog(LOG_NOTICE, "write_w1() lseek %s: %s", addr, strerror(errno)); |
|
120 } |
|
121 |
|
122 } else { |
|
123 syslog(LOG_NOTICE, "write_w1() open %s: %s", addr, strerror(errno)); |
|
124 } |
|
125 |
|
126 leave: |
|
127 if (fn != -1) { |
|
128 if ((close(fn)) == -1) { |
|
129 syslog(LOG_NOTICE, "write_w1() close %s: %s", addr, strerror(errno)); |
|
130 } |
|
131 } |
|
132 |
|
133 free(addr); |
|
134 return rc; |
|
135 } |
|
136 |
|
137 |
|
138 |
|
139 void hlt_heater(int value) |
|
140 { |
|
141 if (value) { |
|
142 leds |= SLED_HLTH; |
|
143 } else { |
|
144 leds &= ~SLED_HLTH; |
|
145 } |
|
146 slcdLEDs(slcdHandle); |
|
147 } |
|
148 |
|
149 |
|
150 |
|
151 void mlt_heater(int value) |
|
152 { |
|
153 if (value) { |
|
154 leds |= SLED_MLTH; |
|
155 } else { |
|
156 leds &= ~SLED_MLTH; |
|
157 } |
|
158 slcdLEDs(slcdHandle); |
|
159 } |
|
160 |
|
161 |
|
162 |
|
163 void mlt_pump(int value) |
|
164 { |
|
165 pump_status(value); |
|
166 if (value) { |
|
167 leds |= SLED_MLTP; |
|
168 } else { |
|
169 leds &= ~SLED_MLTP; |
|
170 } |
|
171 slcdLEDs(slcdHandle); |
|
172 } |
|
173 |
|
174 |
|
175 |
|
176 int device_out(char *uuid, int value) |
|
177 { |
|
178 devices_list *device; |
|
179 time_t now, my_timestamp; |
|
180 int rc, my_value, test_value; |
|
181 |
|
182 if (uuid == NULL) |
|
183 return 0; |
|
184 |
|
185 now = time(NULL); |
|
186 |
|
187 #ifdef HAVE_WIRINGPI_H |
|
188 piLock(LOCK_DEVICES); |
|
189 #endif |
|
190 |
|
191 for (device = Config.devices; device; device = device->next) { |
|
192 if (! strcmp(uuid, device->uuid)) { |
|
193 /* |
|
194 * Execute command if different then the old value. But also |
|
195 * every 2 minutes because commands can have temporary |
|
196 * disconnects, or have radio problems. |
|
197 */ |
|
198 my_timestamp = device->timestamp; |
|
199 my_value = device->value; |
|
200 |
|
201 if ((device->type == DEVTYPE_W1) && (device->direction == DEVDIR_OUT_BIN)) { |
|
202 test_value = (value == 0) ? 0 : 1; |
|
203 } else { |
|
204 test_value = value; |
|
205 } |
|
206 |
|
207 if ((test_value != my_value) || (((int)now - (int)my_timestamp) >= 120)) { |
|
208 |
|
209 #ifdef HAVE_WIRINGPI_H |
|
210 rc = 0; |
|
211 if ((device->type == DEVTYPE_GPIO) && (device->gpiopin != -1) && (device->present == DEVPRESENT_YES)) { |
|
212 |
|
213 } |
|
214 #endif |
|
215 if ((device->type == DEVTYPE_W1) && (device->direction == DEVDIR_OUT_BIN) && (device->present == DEVPRESENT_YES)) { |
|
216 if (strncmp(device->address, (char *)"3a", 2) == 0) { |
|
217 /* |
|
218 * DS2413. First read state so that we can preserve the state of |
|
219 * the "other" PIO channel. To make things a bit more complicated |
|
220 * the bits in the state register differ from the output register. |
|
221 */ |
|
222 uint8_t state, output; |
|
223 |
|
224 if ((rc = read_w1(device->address, (char *)"state")) >= 0) { |
|
225 state = (unsigned int)rc; |
|
226 output = (state & 0x01) + ((state & 0x04) >> 1); |
|
227 |
|
228 if (device->subdevice == 0) { |
|
229 output = (output & 0xfe); |
|
230 output |= (value == 0) ? 0x01 : 0x00; |
|
231 } else if (device->subdevice == 1) { |
|
232 output = (output & 0xfd); |
|
233 output |= (value == 0) ? 0x02 : 0x00; |
|
234 } else { |
|
235 output = 0xff; |
|
236 } |
|
237 |
|
238 if ((write_w1(device->address, (char *)"output", output)) == 0) { |
|
239 syslog(LOG_NOTICE, "DS2413 PIO%c value=%d (%s)", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1, device->comment); |
|
240 if (debug) |
|
241 fprintf(stdout, "DS2413 PIO%c value=%d (%s)\n", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1, device->comment); |
|
242 device->value = (value == 0) ? 0 : 1; |
|
243 device->timestamp = time(NULL); |
|
244 } |
|
245 } |
|
246 } |
|
247 } |
|
248 |
|
249 #ifdef USE_SIMULATOR |
|
250 if ((device->type == DEVTYPE_SIM) && (device->direction == DEVDIR_OUT_BIN) && (device->present == DEVPRESENT_YES)) { |
|
251 if ((strcmp((char *)"SimHLTheater", device->address) == 0) || |
|
252 (strcmp((char *)"SimMLTheater", device->address) == 0) || |
|
253 (strcmp((char *)"SimMLTpump", device->address) == 0)) { |
|
254 device->value = value; |
|
255 if (strcmp((char *)"SimHLTheater", device->address) == 0) { |
|
256 SIM_hlt_value = value; |
|
257 hlt_heater(value); |
|
258 } |
|
259 if (strcmp((char *)"SimMLTheater", device->address) == 0) { |
|
260 SIM_mlt_value = value; |
|
261 mlt_heater(value); |
|
262 } |
|
263 if (strcmp((char *)"SimMLTpump", device->address) == 0) { |
|
264 mlt_pump(value); |
|
265 } |
|
266 } |
|
267 } |
|
268 #endif |
|
269 } else { |
|
270 #ifdef HAVE_WIRINGPI_H |
|
271 piUnlock(LOCK_DEVICES); |
|
272 #endif |
|
273 return 0; |
|
274 } |
|
275 } |
|
276 } |
|
277 #ifdef HAVE_WIRINGPI_H |
|
278 piUnlock(LOCK_DEVICES); |
|
279 #endif |
|
280 |
|
281 return 0; |
|
282 } |
|
283 |
|
284 |
|
285 /* |
|
286 * Returns DEVPRESENT_NO if failed. |
|
287 * Returns DEVPRESENT_YES if success, value contains new value. |
|
288 */ |
|
289 int device_in(char *uuid, int *value) |
|
290 { |
|
291 devices_list *device; |
|
292 int tmp, present; |
|
293 |
|
294 if (uuid == NULL) |
|
295 return 0; |
|
296 |
|
297 #ifdef HAVE_WIRINGPI_H |
|
298 piLock(LOCK_DEVICES); |
|
299 #endif |
|
300 |
|
301 for (device = Config.devices; device; device = device->next) { |
|
302 if (! strcmp(uuid, device->uuid)) { |
|
303 present = device->present; |
|
304 if (present == DEVPRESENT_YES) { |
|
305 tmp = device->value + device->offset; |
|
306 } else { |
|
307 tmp = 0; |
|
308 } |
|
309 #ifdef HAVE_WIRINGPI_H |
|
310 piUnlock(LOCK_DEVICES); |
|
311 #endif |
|
312 *value = tmp; |
|
313 return present; |
|
314 } |
|
315 } |
|
316 |
|
317 #ifdef HAVE_WIRINGPI_H |
|
318 piUnlock(LOCK_DEVICES); |
|
319 #endif |
|
320 |
|
321 return DEVPRESENT_NO; |
|
322 } |
|
323 |
|
324 |
|
325 |
|
326 |
|
327 /* |
|
328 * Auto detect hotplugged or known to be present devices |
|
329 */ |
|
330 int devices_detect(void) |
|
331 { |
|
332 struct dirent *de; |
|
333 DIR *fd; |
|
334 devices_list *device, *ndev; |
|
335 int found, subdevices, ival, i, rc = 0; |
|
336 char buf[40]; |
|
337 uuid_t uu; |
|
338 #ifdef HAVE_WIRINGPI_H |
|
339 int pin; |
|
340 #endif |
|
341 |
|
342 /* |
|
343 * Scan for 1-wire devices |
|
344 */ |
|
345 if ((fd = opendir((char *)"/sys/bus/w1/devices"))) { |
|
346 while ((de = readdir(fd))) { |
|
347 if (de->d_name[0] != '.') { |
|
348 found = FALSE; |
|
349 for (device = Config.devices; device; device = device->next) { |
|
350 if (strcmp(device->address,de->d_name) == 0) { |
|
351 found = TRUE; |
|
352 break; |
|
353 } |
|
354 } |
|
355 |
|
356 if (found == FALSE) { |
|
357 strncpy(buf, de->d_name, 2); |
|
358 buf[2] = '\0'; |
|
359 sscanf(buf, "%02x", &ival); |
|
360 syslog(LOG_NOTICE, "Scan 1-wire %02x %d", ival, ival); |
|
361 subdevices = 1; |
|
362 if (strcmp(buf, (char *)"29") == 0) |
|
363 subdevices = 8; |
|
364 if (strcmp(buf, (char *)"3a") == 0) |
|
365 subdevices = 2; |
|
366 for (i = 0; i < subdevices; i++) { |
|
367 ndev = (devices_list *)malloc(sizeof(devices_list)); |
|
368 ndev->next = NULL; |
|
369 ndev->version = 1; |
|
370 ndev->uuid = malloc(37); |
|
371 uuid_generate(uu); |
|
372 uuid_unparse(uu, ndev->uuid); |
|
373 ndev->type = DEVTYPE_W1; |
|
374 ndev->direction = DEVDIR_UNDEF; |
|
375 if (strcmp(buf, (char *)"10") == 0) { |
|
376 ndev->direction = DEVDIR_IN_ANALOG; |
|
377 ndev->description = xstrcpy((char *)"DS18S20 Digital thermometer"); |
|
378 } else if (strcmp(buf, (char *)"22") == 0) { |
|
379 ndev->direction = DEVDIR_IN_ANALOG; |
|
380 ndev->description = xstrcpy((char *)"DS1820 Digital thermometer"); |
|
381 } else if (strcmp(buf, (char *)"28") == 0) { |
|
382 ndev->direction = DEVDIR_IN_ANALOG; |
|
383 ndev->description = xstrcpy((char *)"DS18B20 Digital thermometer"); |
|
384 } else if (strcmp(buf, (char *)"3a") == 0) { |
|
385 ndev->description = xstrcpy((char *)"DS2413 Dual channel addressable switch"); |
|
386 ndev->direction = DEVDIR_IN_BIN; |
|
387 } else if (strcmp(buf, (char *)"3b") == 0) { |
|
388 ndev->direction = DEVDIR_IN_ANALOG; |
|
389 ndev->description = xstrcpy((char *)"DS1825 Digital thermometer"); |
|
390 } else if (strcmp(buf, (char *)"42") == 0) { |
|
391 ndev->direction = DEVDIR_IN_ANALOG; |
|
392 ndev->description = xstrcpy((char *)"DS28EA00 Digital thermometer"); |
|
393 } else if (strcmp(buf, (char *)"w1") == 0) { |
|
394 ndev->description = xstrcpy((char *)"Master System device"); |
|
395 } else { |
|
396 ndev->description = xstrcpy((char *)"Unknown device family "); |
|
397 ndev->description = xstrcat(ndev->description, buf); |
|
398 } |
|
399 ndev->value = ndev->offset = ndev->inuse = 0; |
|
400 ndev->present = DEVPRESENT_YES; |
|
401 ndev->address = xstrcpy(de->d_name); |
|
402 ndev->subdevice = i; |
|
403 ndev->gpiopin = -1; |
|
404 ndev->comment = xstrcpy((char *)"Auto detected device"); |
|
405 ndev->timestamp = time(NULL); |
|
406 |
|
407 if (Config.devices == NULL) { |
|
408 Config.devices = ndev; |
|
409 } else { |
|
410 for (device = Config.devices; device; device = device->next) { |
|
411 if (device->next == NULL) { |
|
412 device->next = ndev; |
|
413 break; |
|
414 } |
|
415 } |
|
416 } |
|
417 rc++; |
|
418 } |
|
419 } |
|
420 } |
|
421 } |
|
422 closedir(fd); |
|
423 } |
|
424 |
|
425 #ifdef HAVE_WIRINGPI_H |
|
426 if (piBoardRev() == 2) { |
|
427 /* |
|
428 * Support rev B and newer boards only |
|
429 */ |
|
430 found = FALSE; |
|
431 for (device = Config.devices; device; device = device->next) { |
|
432 if (device->type == DEVTYPE_GPIO) { |
|
433 found = TRUE; |
|
434 break; |
|
435 } |
|
436 } |
|
437 |
|
438 if (found == FALSE) { |
|
439 /* |
|
440 * There were no GPIO devices found. |
|
441 */ |
|
442 subdevices = 12; |
|
443 pin = 0; |
|
444 for (i = 0; i < subdevices; i++) { |
|
445 if (i == 8) |
|
446 pin = 17; |
|
447 |
|
448 ndev = (devices_list *)malloc(sizeof(devices_list)); |
|
449 ndev->next = NULL; |
|
450 ndev->version = 1; |
|
451 ndev->uuid = malloc(37); |
|
452 uuid_generate(uu); |
|
453 uuid_unparse(uu, ndev->uuid); |
|
454 ndev->type = DEVTYPE_GPIO; |
|
455 ndev->value = digitalRead(pin); |
|
456 ndev->offset = 0; |
|
457 ndev->present = DEVPRESENT_YES; |
|
458 ndev->address = xstrcpy((char *)"GPIO"); |
|
459 snprintf(buf, 39, "Raspberry GPIO %d", i); |
|
460 ndev->description = xstrcpy(buf); |
|
461 ndev->subdevice = i; |
|
462 ndev->gpiopin = pin; |
|
463 ndev->timestamp = time(NULL); |
|
464 switch (i) { |
|
465 case 0: |
|
466 ndev->direction = DEVDIR_OUT_ANALOG; |
|
467 ndev->inuse = 1; |
|
468 ndev->comment = xstrcpy((char *)"MLT heater SSR"); |
|
469 break; |
|
470 case 1: |
|
471 ndev->direction = DEVDIR_OUT_ANALOG; |
|
472 ndev->inuse = 1; |
|
473 ndev->comment = xstrcpy((char *)"MLT heater PWM"); |
|
474 break; |
|
475 case 2: |
|
476 ndev->direction = DEVDIR_OUT_ANALOG; |
|
477 ndev->inuse = 1; |
|
478 ndev->comment = xstrcpy((char *)"MLT pump relay"); |
|
479 break; |
|
480 case PANEL_RETURN: |
|
481 ndev->direction = DEVDIR_IN_BIN; |
|
482 ndev->inuse = 1; |
|
483 ndev->comment = xstrcpy((char *)"Frontpanel Return"); |
|
484 break; |
|
485 case PANEL_ENTER: |
|
486 ndev->direction = DEVDIR_IN_BIN; |
|
487 ndev->inuse = 1; |
|
488 ndev->comment = xstrcpy((char *)"Frontpanel Enter key"); |
|
489 break; |
|
490 case PANEL_DOWN: |
|
491 ndev->direction = DEVDIR_IN_BIN; |
|
492 ndev->inuse = 1; |
|
493 ndev->comment = xstrcpy((char *)"Frontpanel Down key"); |
|
494 break; |
|
495 case PANEL_UP: |
|
496 ndev->direction = DEVDIR_IN_BIN; |
|
497 ndev->inuse = 1; |
|
498 ndev->comment = xstrcpy((char *)"Frontpanel Up key"); |
|
499 break; |
|
500 case 7: |
|
501 ndev->direction = DEVDIR_INTERN; |
|
502 ndev->inuse = 1; |
|
503 ndev->comment = xstrcpy((char *)"1-Wire bus"); |
|
504 break; |
|
505 case 8: |
|
506 ndev->direction = DEVDIR_OUT_BIN; |
|
507 ndev->inuse = 1; |
|
508 ndev->comment = xstrcpy((char *)"Buzzer"); |
|
509 break; |
|
510 default: |
|
511 ndev->direction = DEVDIR_IN_BIN; |
|
512 ndev->inuse = 0; |
|
513 ndev->comment = xstrcpy((char *)"Raspberry GPIO"); |
|
514 } |
|
515 pin++; |
|
516 |
|
517 if (Config.devices == NULL) { |
|
518 Config.devices = ndev; |
|
519 } else { |
|
520 for (device = Config.devices; device; device = device->next) { |
|
521 if (device->next == NULL) { |
|
522 device->next = ndev; |
|
523 break; |
|
524 } |
|
525 } |
|
526 } |
|
527 rc++; |
|
528 } |
|
529 } |
|
530 } |
|
531 #endif |
|
532 |
|
533 #ifdef USE_SIMULATOR |
|
534 found = FALSE; |
|
535 for (device = Config.devices; device; device = device->next) { |
|
536 if (device->type == DEVTYPE_SIM) { |
|
537 found = TRUE; |
|
538 break; |
|
539 } |
|
540 } |
|
541 |
|
542 if (found == FALSE) { |
|
543 subdevices = 6; |
|
544 for (i = 0; i < subdevices; i++) { |
|
545 ndev = (devices_list *)malloc(sizeof(devices_list)); |
|
546 ndev->next = NULL; |
|
547 ndev->version = 1; |
|
548 ndev->uuid = malloc(37); |
|
549 uuid_generate(uu); |
|
550 uuid_unparse(uu, ndev->uuid); |
|
551 ndev->type = DEVTYPE_SIM; |
|
552 ndev->value = ndev->offset = 0; |
|
553 ndev->present = DEVPRESENT_YES; |
|
554 ndev->subdevice = i; |
|
555 ndev->gpiopin = -1; |
|
556 ndev->comment = xstrcpy((char *)"Auto detected device"); |
|
557 ndev->timestamp = time(NULL); |
|
558 ndev->inuse = 0; |
|
559 switch (i) { |
|
560 case 0: ndev->direction = DEVDIR_IN_ANALOG; |
|
561 ndev->address = xstrcpy((char *)"SimRoomtemp"); |
|
562 ndev->description = xstrcpy((char *)"Simulated room temperature"); |
|
563 break; |
|
564 case 1: ndev->direction = DEVDIR_IN_ANALOG; |
|
565 ndev->address = xstrcpy((char *)"SimHLTtemp"); |
|
566 ndev->description = xstrcpy((char *)"Simulated HLT temperature"); |
|
567 break; |
|
568 case 2: ndev->direction = DEVDIR_IN_ANALOG; |
|
569 ndev->address = xstrcpy((char *)"SimMLTtemp"); |
|
570 ndev->description = xstrcpy((char *)"Simulated MLT temperature"); |
|
571 break; |
|
572 case 3: ndev->direction = DEVDIR_OUT_BIN; |
|
573 ndev->address = xstrcpy((char *)"SimHLTheater"); |
|
574 ndev->description = xstrcpy((char *)"Simulated HLT heater"); |
|
575 break; |
|
576 case 4: ndev->direction = DEVDIR_OUT_BIN; |
|
577 ndev->address = xstrcpy((char *)"SimMLTheater"); |
|
578 ndev->description = xstrcpy((char *)"Simulated MLT heater"); |
|
579 break; |
|
580 case 5: ndev->direction = DEVDIR_OUT_BIN; |
|
581 ndev->address = xstrcpy((char *)"SimMLTpump"); |
|
582 ndev->description = xstrcpy((char *)"Simulated MLT pump"); |
|
583 break; |
|
584 } |
|
585 |
|
586 if (Config.devices == NULL) { |
|
587 Config.devices = ndev; |
|
588 } else { |
|
589 for (device = Config.devices; device; device = device->next) { |
|
590 if (device->next == NULL) { |
|
591 device->next = ndev; |
|
592 break; |
|
593 } |
|
594 } |
|
595 } |
|
596 rc++; |
|
597 } |
|
598 } |
|
599 #endif |
|
600 |
|
601 return rc; |
|
602 } |
|
603 |
|
604 |
|
605 |
|
606 #ifdef HAVE_WIRINGPI_H |
|
607 PI_THREAD (my_devices_loop) |
|
608 #else |
|
609 void *my_devices_loop(void *threadid) |
|
610 #endif |
|
611 { |
|
612 devices_list *device; |
|
613 char *addr = NULL, line[60], *p = NULL; |
|
614 FILE *fp; |
|
615 int temp, rc; |
|
616 |
|
617 syslog(LOG_NOTICE, "Thread my_devices_loop started"); |
|
618 if (debug) |
|
619 fprintf(stdout, "Thread my_devices_loop started\n"); |
|
620 |
|
621 #ifdef HAVE_WIRINGPI_H |
|
622 if ((rc = piHiPri(10))) |
|
623 syslog(LOG_NOTICE, "my_devices_loop: piHiPri(10) rc=%d", rc); |
|
624 #endif |
|
625 |
|
626 /* |
|
627 * Loop forever until the external shutdown variable is set. |
|
628 */ |
|
629 for (;;) { |
|
630 |
|
631 /* |
|
632 * Process all devices. |
|
633 */ |
|
634 for (device = Config.devices; device; device = device->next) { |
|
635 |
|
636 if (my_shutdown) |
|
637 break; |
|
638 |
|
639 switch (device->type) { |
|
640 case DEVTYPE_W1: |
|
641 /* |
|
642 * Only tested with DS18B20 but from the kernel source this |
|
643 * should work with all 1-wire thermometer sensors. |
|
644 */ |
|
645 if ((strncmp(device->address, (char *)"10", 2) == 0) || |
|
646 (strncmp(device->address, (char *)"22", 2) == 0) || |
|
647 (strncmp(device->address, (char *)"28", 2) == 0) || |
|
648 (strncmp(device->address, (char *)"3b", 2) == 0) || |
|
649 (strncmp(device->address, (char *)"42", 2) == 0)) { |
|
650 addr = xstrcpy((char *)"/sys/bus/w1/devices/"); |
|
651 addr = xstrcat(addr, device->address); |
|
652 addr = xstrcat(addr, (char *)"/w1_slave"); |
|
653 if ((fp = fopen(addr, "r"))) { |
|
654 if (device->present != DEVPRESENT_YES) { |
|
655 syslog(LOG_NOTICE, "sensor %s is back", device->address); |
|
656 #ifdef HAVE_WIRINGPI_H |
|
657 piLock(LOCK_DEVICES); |
|
658 #endif |
|
659 device->present = DEVPRESENT_YES; |
|
660 #ifdef HAVE_WIRINGPI_H |
|
661 piUnlock(LOCK_DEVICES); |
|
662 #endif |
|
663 } |
|
664 /* |
|
665 * The output looks like: |
|
666 * 72 01 4b 46 7f ff 0e 10 57 : crc=57 YES |
|
667 * 72 01 4b 46 7f ff 0e 10 57 t=23125 |
|
668 */ |
|
669 fgets(line, 50, fp); |
|
670 line[strlen(line)-1] = '\0'; |
|
671 if ((line[36] == 'Y') && (line[37] == 'E')) { |
|
672 /* CRC is Ok, continue */ |
|
673 fgets(line, 50, fp); |
|
674 line[strlen(line)-1] = '\0'; |
|
675 strtok(line, (char *)"="); |
|
676 p = strtok(NULL, (char *)"="); |
|
677 rc = sscanf(p, "%d", &temp); |
|
678 #ifdef HAVE_WIRINGPI_H |
|
679 piLock(LOCK_DEVICES); |
|
680 #endif |
|
681 if ((rc == 1) && (device->value != temp)) { |
|
682 device->value = temp; |
|
683 device->timestamp = time(NULL); |
|
684 } |
|
685 #ifdef HAVE_WIRINGPI_H |
|
686 piUnlock(LOCK_DEVICES); |
|
687 #endif |
|
688 } else { |
|
689 syslog(LOG_NOTICE, "sensor %s CRC error", device->address); |
|
690 #ifdef HAVE_WIRINGPI_H |
|
691 piLock(LOCK_DEVICES); |
|
692 #endif |
|
693 device->present = DEVPRESENT_ERROR; |
|
694 #ifdef HAVE_WIRINGPI_H |
|
695 piUnlock(LOCK_DEVICES); |
|
696 #endif |
|
697 } |
|
698 fclose(fp); |
|
699 } else { |
|
700 if (device->present != DEVPRESENT_NO) { |
|
701 syslog(LOG_NOTICE, "sensor %s is missing", device->address); |
|
702 #ifdef HAVE_WIRINGPI_H |
|
703 piLock(LOCK_DEVICES); |
|
704 #endif |
|
705 device->present = DEVPRESENT_NO; |
|
706 #ifdef HAVE_WIRINGPI_H |
|
707 piUnlock(LOCK_DEVICES); |
|
708 #endif |
|
709 } |
|
710 } |
|
711 free(addr); |
|
712 addr = NULL; |
|
713 } /* if temperature sensor */ |
|
714 /* |
|
715 * DS2413 Dual channel addressable switch |
|
716 */ |
|
717 if (strncmp(device->address, (char *)"3a", 2) == 0) { |
|
718 addr = xstrcpy((char *)"/sys/bus/w1/devices/"); |
|
719 addr = xstrcat(addr, device->address); |
|
720 addr = xstrcat(addr, (char *)"/state"); |
|
721 |
|
722 if ((access(addr, R_OK)) == 0) { |
|
723 if (device->present != DEVPRESENT_YES) { |
|
724 syslog(LOG_NOTICE, "DS2413 %s is back", device->address); |
|
725 #ifdef HAVE_WIRINGPI_H |
|
726 piLock(LOCK_DEVICES); |
|
727 #endif |
|
728 device->present = DEVPRESENT_YES; |
|
729 #ifdef HAVE_WIRINGPI_H |
|
730 piUnlock(LOCK_DEVICES); |
|
731 #endif |
|
732 } |
|
733 /* |
|
734 * First make sure that if this device is configured as input |
|
735 * to drive the output high. |
|
736 */ |
|
737 if (device->direction == DEVDIR_IN_BIN) { |
|
738 uint8_t state, output; |
|
739 |
|
740 if ((rc = read_w1(device->address, (char *)"state")) >= 0) { |
|
741 state = (unsigned int)rc; |
|
742 output = ((state & 0x02) >> 1) + ((state & 0x08) >> 2); /* Both latch states */ |
|
743 if (device->subdevice == 0) { |
|
744 output = (output & 0xfe); |
|
745 output |= 0x01; |
|
746 } else if (device->subdevice == 1) { |
|
747 output = (output & 0xfd); |
|
748 output |= 0x02; |
|
749 } else { |
|
750 output = 0xff; |
|
751 } |
|
752 write_w1(device->address, (char *)"output", output); |
|
753 } |
|
754 } |
|
755 if ((rc = read_w1(device->address, (char *)"state")) >= 0) { |
|
756 #ifdef HAVE_WIRINGPI_H |
|
757 piLock(LOCK_DEVICES); |
|
758 #endif |
|
759 /* |
|
760 * Read PIOA or PIOB pin state bits |
|
761 */ |
|
762 if (device->subdevice == 0) |
|
763 device->value = (rc & 0x01) ? 0 : 1; |
|
764 else if (device->subdevice == 1) |
|
765 device->value = (rc & 0x04) ? 0 : 1; |
|
766 device->timestamp = time(NULL); |
|
767 #ifdef HAVE_WIRINGPI_H |
|
768 piUnlock(LOCK_DEVICES); |
|
769 #endif |
|
770 } |
|
771 } else { |
|
772 if (device->present != DEVPRESENT_NO) { |
|
773 syslog(LOG_NOTICE, "DS2413 %s is missing", device->address); |
|
774 #ifdef HAVE_WIRINGPI_H |
|
775 piLock(LOCK_DEVICES); |
|
776 #endif |
|
777 device->present = DEVPRESENT_NO; |
|
778 #ifdef HAVE_WIRINGPI_H |
|
779 piUnlock(LOCK_DEVICES); |
|
780 #endif |
|
781 } |
|
782 } |
|
783 free(addr); |
|
784 addr = NULL; |
|
785 } |
|
786 |
|
787 break; |
|
788 |
|
789 #ifdef HAVE_WIRINGPI_H |
|
790 case DEVTYPE_GPIO: |
|
791 if (device->direction == DEVDIR_IN_BIN) { |
|
792 piLock(LOCK_DEVICES); |
|
793 device->value = digitalRead(device->gpiopin); |
|
794 device->offset = 0; |
|
795 device->timestamp = time(NULL); |
|
796 piUnlock(LOCK_DEVICES); |
|
797 } |
|
798 break; |
|
799 |
|
800 #endif |
|
801 #ifdef USE_SIMULATOR |
|
802 case DEVTYPE_SIM: |
|
803 #ifdef HAVE_WIRINGPI_H |
|
804 piLock(LOCK_DEVICES); |
|
805 #endif |
|
806 if (Config.simulator) { |
|
807 if (device->subdevice == 0) { |
|
808 device->value = (int)(Config.simulator->room_temperature * 1000); |
|
809 device->timestamp = time(NULL); |
|
810 } else if (device->subdevice == 1) { |
|
811 device->value = (int)(Config.simulator->hlt_temperature * 1000); |
|
812 device->timestamp = time(NULL); |
|
813 } else if (device->subdevice == 2) { |
|
814 device->value = (int)(Config.simulator->mlt_temperature * 1000); |
|
815 device->timestamp = time(NULL); |
|
816 } |
|
817 } |
|
818 #ifdef HAVE_WIRINGPI_H |
|
819 piUnlock(LOCK_DEVICES); |
|
820 #endif |
|
821 break; |
|
822 #endif |
|
823 default: |
|
824 break; |
|
825 } |
|
826 |
|
827 /* |
|
828 * Delay a bit after procesing a device. |
|
829 */ |
|
830 usleep(10000); |
|
831 } |
|
832 |
|
833 if (my_shutdown) |
|
834 break; |
|
835 /* |
|
836 * Delay a bit after all devices |
|
837 */ |
|
838 usleep(100000); |
|
839 } |
|
840 |
|
841 syslog(LOG_NOTICE, "Thread my_devices_loop stopped"); |
|
842 if (debug) |
|
843 fprintf(stdout, "Thread my_devices_loop stopped\n"); |
|
844 return 0; |
|
845 } |
|
846 |
|
847 |
|
848 |
|