Wed, 01 Apr 2015 15:20:05 +0200
Completed DS2413 device code and driver.
thermferm/devices.c | file | annotate | diff | comparison | revisions |
--- a/thermferm/devices.c Thu Mar 26 20:58:23 2015 +0100 +++ b/thermferm/devices.c Wed Apr 01 15:20:05 2015 +0200 @@ -162,12 +162,102 @@ #endif +int read_w1(char *address, char *file) +{ + char *addr = NULL; + int fn = -1, rc = -1, retries = 5; + uint8_t val; + + addr = xstrcpy((char *)"/sys/bus/w1/devices/"); + addr = xstrcat(addr, address); + addr = xstrcat(addr, (char *)"/"); + addr = xstrcat(addr, file); + + if ((fn = open(addr, O_RDONLY)) >= 0) { + + if ((lseek(fn, 0L, SEEK_SET)) == 0) { + + while (retries--) { + if ((read(fn, &val, 1)) == 1) { + rc = (int)val; + goto leave; +// } else { +// syslog(LOG_NOTICE, "read_w1() read %s try=%d: %s", addr, retries, strerror(errno)); + } + } + syslog(LOG_NOTICE, "read_w1() read %s fatal: %s", addr, strerror(errno)); + + } else { + syslog(LOG_NOTICE, "read_w1() lseek %s: %s", addr, strerror(errno)); + } + + } else { + syslog(LOG_NOTICE, "read_w1() open %s: %s", addr, strerror(errno)); + } + +leave: + if (fn != -1) { + if ((close(fn)) == -1) { + syslog(LOG_NOTICE, "read_w1() close %s: %s", addr, strerror(errno)); + } + } + + free(addr); + return rc; +} + + + +int write_w1(char *address, char *file, uint8_t val) +{ + char *addr = NULL; + int fn = -1, rc = -1, retries = 5; + + addr = xstrcpy((char *)"/sys/bus/w1/devices/"); + addr = xstrcat(addr, address); + addr = xstrcat(addr, (char *)"/"); + addr = xstrcat(addr, file); + + if ((fn = open(addr, O_WRONLY)) >= 0) { + + if ((lseek(fn, 0L, SEEK_SET)) == 0) { + + while (retries--) { + if ((write(fn, &val, 1)) == 1) { + rc = 0; + goto leave; +// } else { +// syslog(LOG_NOTICE, "write_w1() write %s try=%d: %s", addr, retries, strerror(errno)); + } + } + syslog(LOG_NOTICE, "write_w1() write %s fatal: %s", addr, strerror(errno)); + + } else { + syslog(LOG_NOTICE, "write_w1() lseek %s: %s", addr, strerror(errno)); + } + + } else { + syslog(LOG_NOTICE, "write_w1() open %s: %s", addr, strerror(errno)); + } + +leave: + if (fn != -1) { + if ((close(fn)) == -1) { + syslog(LOG_NOTICE, "write_w1() close %s: %s", addr, strerror(errno)); + } + } + + free(addr); + return rc; +} + + int device_out(char *uuid, int value) { devices_list *device; time_t now, my_timestamp; - int my_value; + int my_value, test_value; #ifdef HAVE_WIRINGPI_H int i, rc; char buf[40]; @@ -191,7 +281,14 @@ */ my_timestamp = device->timestamp; my_value = device->value; - if ((value != my_value) || (((int)now - (int)my_timestamp) > 120)) { + + if ((device->type == DEVTYPE_W1) && (device->direction == DEVDIR_OUT_BIN)) { + test_value = (value == 0) ? 0 : 1; + } else { + test_value = value; + } + + if ((test_value != my_value) || (((int)now - (int)my_timestamp) > 120)) { #ifdef HAVE_WIRINGPI_H rc = 0; @@ -219,8 +316,39 @@ } #endif if ((device->type == DEVTYPE_W1) && (device->direction == DEVDIR_OUT_BIN) && (device->present == DEVPRESENT_YES)) { + if (strncmp(device->address, (char *)"3a", 2) == 0) { + /* + * DS2413. First read state so that we can preserve the state of + * the "other" PIO channel. To make things a bit more complicated + * the bits in the state register differ from the output register. + */ + uint8_t state, output; + if ((rc = read_w1(device->address, (char *)"state")) >= 0) { + state = (unsigned int)rc; + output = (state & 0x01) + ((state & 0x04) >> 1); + + if (device->subdevice == 0) { + output = (output & 0xfe); + output |= (value == 0) ? 0x01 : 0x00; + } else if (device->subdevice == 1) { + output = (output & 0xfd); + output |= (value == 0) ? 0x02 : 0x00; + } else { + output = 0xff; + } + + if ((write_w1(device->address, (char *)"output", output)) == 0) { + syslog(LOG_NOTICE, "DS2413 PIO%c value=%d", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1); + if (debug) + fprintf(stdout, "DS2413 PIO%c value=%d\n", (device->subdevice == 0) ? 'A' : 'B', (value == 0) ? 0 : 1); + device->value = (value == 0) ? 0 : 1; + device->timestamp = time(NULL); + } + } + } } + #ifdef USE_SIMULATOR if ((device->type == DEVTYPE_SIM) && (device->direction == DEVDIR_OUT_BIN) && (device->present == DEVPRESENT_YES)) { @@ -649,13 +777,12 @@ /* * DS2413 Dual channel addressable switch */ - unsigned char state; - if (strncmp(device->address, (char *)"3a", 2) == 0) { addr = xstrcpy((char *)"/sys/bus/w1/devices/"); addr = xstrcat(addr, device->address); addr = xstrcat(addr, (char *)"/state"); - if ((fp = fopen(addr, "r"))) { + + if ((access(addr, R_OK)) == 0) { if (device->present != DEVPRESENT_YES) { syslog(LOG_NOTICE, "DS2413 %s is back", device->address); #ifdef HAVE_WIRINGPI_H @@ -666,7 +793,7 @@ piUnlock(LOCK_DEVICES); #endif } - if ((fread(&state, 1, 1, fp)) == 1) { + if ((rc = read_w1(device->address, (char *)"state")) >= 0) { #ifdef HAVE_WIRINGPI_H piLock(LOCK_DEVICES); #endif @@ -674,15 +801,14 @@ * Read PIOA or PIOB pin state bits */ if (device->subdevice == 0) - device->value = (state & 0x01) ? 0 : 1; + device->value = (rc & 0x01) ? 0 : 1; else if (device->subdevice == 1) - device->value = (state & 0x04) ? 0 : 1; + device->value = (rc & 0x04) ? 0 : 1; device->timestamp = time(NULL); #ifdef HAVE_WIRINGPI_H piUnlock(LOCK_DEVICES); #endif } - fclose(fp); } else { if (device->present != DEVPRESENT_NO) { syslog(LOG_NOTICE, "DS2413 %s is missing", device->address);