Completed DS2413 device code and driver.

Wed, 01 Apr 2015 15:20:05 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Wed, 01 Apr 2015 15:20:05 +0200
changeset 347
0ab5c3fd7c77
parent 346
1043bd00873c
child 348
ffc4b8aa824f

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);

mercurial