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