Index: README.i2c-23017
===================================================================
--- README.i2c-23017	(.../tags/RELEASE_2_1_5)	(nicht existent)
+++ README.i2c-23017	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -0,0 +1,48 @@
+Author: Bernd Wagner
+Datum: 2019-2021
+Version: SRCP 2.1.5
+Licence: GPL v2 for the whole package 
+
+The i2c interface described here is a low-cost self-made interface for the
+control of accessories (GAs).
+
+Basic principle:
+
+
+               ------------          ----------
+              |            |        |    4*    |
+              | MCP23017   |        | ULN2803A |
+I2C-Bus ------| 16-Bit I/O |---16*--|Darlington|----- 16* --- accessories
+              | -Expander  |        |Transistor|              (Maerklin)    
+              |            |        |  Arrays  |
+               ------------          ---------- 
+
+This driver controls GAs (accessories) by the I/O ports of MCP23017
+16Bit-I/O-Expanders driven by the i2c-dev interface of the Linux kernel.
+In order to deliver enough current for the accessories, the outputs are boosted
+by ULN2803A Darlington Transistor Arrays (2 Darlington pairs in parallel for 
+each output).
+
+As this circuitry is DC only, The Maerklin accessories (originally built for AC)
+are DC driven. The ULN2803A provide internal free wheeling diodes for the
+inductive loads.
+
+The MCP23017 can be hardware-wired to have one of the I2C addresses 32, ..., 39.
+The MCP23017's I2C-address is its SRCP-GA address.
+The bits of MCP23017's GPIO Port A correspond to SRCP ports 0, ..., 7,
+the bits of GPIOB correspond to SRCP ports 8, ..., 15.
+
+You may find a more explicit circuit diagram in README_i2c-23017_circuit_diagram.jpeg.
+The original circuits are driven by the i2c bus of a Raspberry Pi.
+
+Warning:
+
+This wiring connects your Raspberry Pi/ your computer galvanically to your model train.
+If there are other such connections, e.g. by a booster, DC isolation may be needed
+(e.g. by opto-couplers), particularly if a DDL generated signal has a
+different Groud Level.
+
+Furthermore, bear in mind to use fuses to prevent for short circuits.
+
+This is a hobbyist hook-up, so all possible disclaimers apply.
+
Index: README_i2c-23017_circuit_diagram.jpeg
===================================================================
Kann nicht anzeigen: Dateityp ist als binär angegeben.
svn:mime-type = application/octet-stream
Index: README_i2c-23017_circuit_diagram.jpeg
===================================================================
--- README_i2c-23017_circuit_diagram.jpeg	(.../tags/RELEASE_2_1_5)	(nicht existent)
+++ README_i2c-23017_circuit_diagram.jpeg	(.../branches/bw-i2c-23017)	(Revision 1871)

Eigenschaftsänderungen: README_i2c-23017_circuit_diagram.jpeg
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+application/octet-stream
\ No newline at end of property
Index: configure.ac
===================================================================
--- configure.ac	(.../tags/RELEASE_2_1_5)	(Revision 1759)
+++ configure.ac	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -161,10 +161,23 @@ if test "$with_LOCONET" = "yes"; then
         [AC_MSG_ERROR(getaddrinfo support missing)])
 fi
 
+dnl Option to disable I2C23017 support
+AC_ARG_ENABLE(i2c23017,
+    AC_HELP_STRING([--disable-i2c23017], [do not compile i2c-23017 module]),
+    [with_I2C23017="$enableval"], [with_I2C23017=yes])
+if test "$with_I2C23017" = "yes"; then
+   AC_DEFINE(USE_I2C23017,1, [define to 1 if you want i2c-23017 support])
+   NUM_MODULES=`expr $NUM_MODULES + 1`
+fi
+AM_CONDITIONAL(USE_I2C23017, test "$with_I2C23017" = yes)
 
 dnl Checks for host dependend libraries.
 case $host in
   *-*-linux*)
+    if test "$with_I2C23017" = "yes"; then
+      AC_CHECK_LIB(i2c, i2c_smbus_read_byte, , AC_MSG_WARN(library i2c is missing))
+    fi
+
     ;;
   *-*-cygwin*)
     if test "$with_DDLS88" = "yes"; then
@@ -196,12 +209,22 @@ case $host in
           AC_CHECK_HEADERS(sys/io.h, ,
                        AC_MSG_ERROR(essential header file is missing))
     fi
+
     AC_CHECK_HEADERS(linux/serial.h, ,
                  AC_MSG_ERROR(essential header file is missing))
-    if test "$with_I2C" = "yes"; then
+
+    if test "$with_I2C" = "yes" || test "$with_I2C23017" = "yes"; then
     AC_CHECK_HEADERS(linux/i2c-dev.h, ,
                  AC_MSG_ERROR(essential header file is missing))
     fi
+
+    # for some older Raspbian, package libi2c-dev changes linux/i2c-dev.h and moves original one to i2c-dev.h.kernel
+    # for other Raspbians or Ubuntu, package libi2c-dev installs smbus.h
+    if test "$with_I2C23017" = "yes"; then
+      AC_CHECK_HEADERS(i2c/smbus.h, ,
+        AC_MSG_WARN(potentially essential header file i2c/smbus.h missing - \
+        please make sure that the package libi2c-dev is installed))
+    fi
     ;;
   *-*-cygwin*)
     AC_CHECK_HEADERS(sys/io.h, ,
@@ -323,6 +346,7 @@ if test "$with_M605X"     = "yes"; then
 if test "$with_SELECTRIX" = "yes"; then echo "    selectrix"; fi
 if test "$with_ZIMO"      = "yes"; then echo "    zimo"; fi
 if test "$with_DCCAR"     = "yes"; then echo "    dccar"; fi
+if test "$with_I2C23017"  = "yes"; then echo "    i2c-23017"; fi
 echo
 echo "Unsupported devices:"
 if test "$with_DDL"       != "yes"; then echo "    ddl"; fi
@@ -337,6 +361,7 @@ if test "$with_M605X"     != "yes"; then
 if test "$with_SELECTRIX" != "yes"; then echo "    selectrix"; fi
 if test "$with_ZIMO"      != "yes"; then echo "    zimo"; fi
 if test "$with_DCCAR"     != "yes"; then echo "    dccar"; fi
+if test "$with_I2C23017"  != "yes"; then echo "    i2c-23017"; fi
 
 echo
 if test $NUM_MODULES == 0; then
Index: man/de/srcpd.conf.5
===================================================================
--- man/de/srcpd.conf.5	(.../tags/RELEASE_2_1_5)	(Revision 1759)
+++ man/de/srcpd.conf.5	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -736,7 +736,7 @@ Beispiel
 .PP
 Bustreiber für das i2c-dev-Interface des Linux Kernels.  Er kann
 beispielsweise mit der unter http://www.matronix.de/ zu findenden
-Hardware genutzt werden.
+Hardware genutzt werden (auf Basis PCF8574 I/O Expander)).
 .TP
 multiplex_buses
 TODO
@@ -748,6 +748,44 @@ ga_reset_device
 TODO
 .\"
 .\"
+.SS i2c-23017
+.PP
+Dieser Treiber steuert GAs (Zubehör) mittels I/O ports von MCP23017
+16Bit-I/O-Expandern an einem i2c-dev interface des Linux Kernels.
+Um genug Strom zum Antrieb des Zubehörs zu liefern, werden die Ausgänge
+mit ULN2803A Darlington Transistor Arrays verstärkt(je 2 parallel).
+Das Märklin-Zubehör wird mit Gleichstrom betätigt.
+
+Die SRCP GA-Adresse eines MCP23017 ist seine I2C-Adresse
+(32 bis 39 sind möglich). Die Bits des GPIO Port A eines MCP23017
+entsprechen den SRCP Ports 0,...7, die Bits von GPIOB den SRCP Ports
+8, ..., 15.
+.TP
+ga_invert_outputs
+Boolean: alle Ausgänge invertieren.
+.TP
+number_ga
+maximale GA Addresse (Default=40, GA Adressen 32..39 möglich)
+.TP
+i2c_maxrepeat
+Maximale Anzahl der Schreibversuche auf den I2C bus im Fehlerfall. Dies kann mit "verbosity" Level 5 verfolgt werden.
+Voreinstellung 1000.
+.TP
+Beispiel
+.nf
+<bus>
+ 	<auto_power_on>yes</auto_power_on>
+ 	<verbosity>5</verbosity>
+	<device>/dev/i2c-1</device>
+	<i2c-23017>
+		<ga_invert_outputs>false</ga_invert_outputs>
+		<number_ga>40</number_ga>
+        <i2c_maxrepeat>1000</i2c_maxrepeat>
+	</i2c-23017>
+</bus>
+.fi
+.\"
+.\"
 .SS intellibox
 .\"
 .PP
Index: man/srcpd.conf.5
===================================================================
--- man/srcpd.conf.5	(.../tags/RELEASE_2_1_5)	(Revision 1759)
+++ man/srcpd.conf.5	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -646,7 +646,7 @@ Example
 .SS i2c-dev
 .PP
 Bus driver for i2c-dev interface of the Linux kernel, can be used to
-access hardware found on http://www.matronix.de/.
+access hardware found on http://www.matronix.de/ (based on PCF8574 I/O Expander).
 .TP
 multiplex_buses
 TODO
@@ -658,6 +658,43 @@ ga_reset_device
 TODO
 .\"
 .\"
+.SS i2c-23017
+.PP
+This driver controls GAs (accessories) by the I/O ports of MCP23017
+16Bit-I/O-Expanders driven by the i2c-dev interface of the Linux kernel.
+In order to deliver enough current for the accessories, the outputs are boosted
+by ULN2803A Darlington Transistor Arrays (2 in parallel). The Maerklin
+accessories are DC driven.
+
+The SRCP-GA address of a MCP23017 is its I2C-address (32 to 39 are possible).
+The bits of MCP23017's GPIO Port A correspond to SRCP ports 0, ..., 7,
+the bits of GPIOB correspond to SRCP ports 8, ..., 15.
+.TP
+ga_invert_outputs
+Boolean: globally invert all outputs or not.
+.TP
+number_ga
+maximal GA address (default=40, GA addresses 32..39 are possible)
+.TP
+i2c_maxrepeat
+maximal number of trials to write to I2C bus in case of errors. This can be tracked by setting the verbosity to 5.
+Default 1000.
+.TP
+Example
+.nf
+<bus>
+ 	<auto_power_on>yes</auto_power_on>
+ 	<verbosity>5</verbosity>
+	<device>/dev/i2c-1</device>
+	<i2c-23017>
+		<ga_invert_outputs>false</ga_invert_outputs>
+		<number_ga>40</number_ga>
+        <i2c_maxrepeat>1000</i2c_maxrepeat>
+	</i2c-23017>
+</bus>
+.fi
+.\"
+.\"
 .SS intellibox
 .PP
 This driver supports the Intellibox device from Uhlenbrock (IB) connected
Index: src/Makefile.am
===================================================================
--- src/Makefile.am	(.../tags/RELEASE_2_1_5)	(Revision 1759)
+++ src/Makefile.am	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -46,6 +46,10 @@ if USE_I2C
 srcpd_SOURCES += i2c-dev.c i2c-dev.h
 endif
 
+if USE_I2C23017
+srcpd_SOURCES += i2c-23017.c i2c-23017.h
+endif
+
 if USE_IB
 srcpd_SOURCES += ib.c ib.h
 endif
Index: src/config-srcpd.c
===================================================================
--- src/config-srcpd.c	(.../tags/RELEASE_2_1_5)	(Revision 1759)
+++ src/config-srcpd.c	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -39,6 +39,10 @@
 #include "i2c-dev.h"
 #endif
 
+#if defined USE_I2C23017
+#include "i2c-23017.h"
+#endif
+
 #ifdef USE_IB
 #include "ib.h"
 #endif
@@ -244,6 +248,20 @@ static bus_t register_bus(bus_t busnumbe
                        "Linux (yet).\n");
 #endif
 #else
+            syslog_bus(0, DBG_ERROR, DISABLE_MSG, child->name);
+#endif
+        }
+
+        else if (xmlStrcmp(child->name, BAD_CAST "i2c-23017") == 0) {
+#if defined USE_I2C23017
+
+#ifdef linux
+            busnumber += readconfig_I2C23017(doc, child, busnumber);
+#else
+            syslog_bus(0, DBG_ERROR, "Sorry, I2C-23017 is only available on "
+                       "Linux (yet).\n");
+#endif
+#else
             syslog_bus(0, DBG_ERROR, DISABLE_MSG, child->name);
 #endif
         }
Index: src/config-srcpd.h
===================================================================
--- src/config-srcpd.h	(.../tags/RELEASE_2_1_5)	(Revision 1759)
+++ src/config-srcpd.h	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -56,6 +56,7 @@ typedef unsigned long int sessionid_t;
 #define SERVER_SELECTRIX       11    /* Selectrix-server */
 #define SERVER_LOCONET         12    /* Loconet Gateway */
 #define SERVER_DCCAR           13    /* DC-Car Gateway */
+#define SERVER_I2C23017        14    /* I2C-23017-server */
 
 /* generic flags */
 #define USE_WATCHDOG          0x0001 /* use watchdog */
Index: src/i2c-23017.c
===================================================================
--- src/i2c-23017.c	(.../tags/RELEASE_2_1_5)	(nicht existent)
+++ src/i2c-23017.c	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -0,0 +1,467 @@
+/***************************************************************************
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU General Public License as published by  *
+*   the Free Software Foundation; either version 2 of the License, or     *
+*   (at your option) any later version.                                   *
+*                                                                         *
+***************************************************************************/
+/**
+* i2c-23017: i2c bus driver for MCP23017.
+* This driver controls GAs (accessories) by the I/O ports of MCP23017  16Bit-I/O-Expanders 
+* driven by the i2c-dev interface of the Linux kernel. 
+* In order to deliver enough current for the accessories, the outputs are boosted by 
+* ULN2803A Darlington Transistor Arrays (2 in parallel).
+*
+* Measures are taken in case of disturbances on the I2C bus (repetitions in case of write errors, 
+* reinitializations of I2C devices).
+*
+* Copyright (c) 2019-2021 by Bernd Wagner <berwag@users.sourceforge.net>
+*
+**/
+#include "config.h"
+
+#include <errno.h>
+
+#include "config-srcpd.h"
+#include "i2c-23017.h"
+#include "toolbox.h"
+#include "srcp-ga.h"
+#include "srcp-power.h"
+#include "srcp-server.h"
+#include "srcp-info.h"
+#include "srcp-error.h"
+#include "syslogmessage.h"
+#ifdef HAVE_LINUX_I2C_DEV_H
+#include <linux/i2c-dev.h>
+#endif
+#ifdef HAVE_I2C_SMBUS_H
+#include <i2c/smbus.h>
+/*
+  Including libi2c-dev package will allow the following I2C SMBus functions
+  - i2c_smbus_access
+  - i2c_smbus_write_quick
+  - i2c_smbus_read_byte
+  - i2c_smbus_write_byte
+  - i2c_smbus_read_byte_data
+  - i2c_smbus_write_byte_data
+  - i2c_smbus_read_word_data
+  - i2c_smbus_write_word_data
+  - i2c_smbus_process_call
+  - i2c_smbus_read_block_data
+  - i2c_smbus_write_block_data
+  - i2c_smbus_read_i2c_block_data
+  - i2c_smbus_write_i2c_block_data
+  - i2c_smbus_block_process_call
+*/
+#endif
+#include <sys/ioctl.h>
+/*#include <sys/stat.h>*/
+#include <fcntl.h>
+#include <unistd.h>
+
+#define __i2c23017 ((I2C23017_DATA*)buses[busnumber].driverdata)
+#define __i2c23017t ((I2C23017_DATA*)buses[btd->bus].driverdata)
+
+int readconfig_I2C23017(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber)
+{
+    syslog_bus(busnumber, DBG_INFO, "Reading configuration for bus '%s'",
+               node->name);
+
+    buses[busnumber].driverdata = malloc(sizeof(struct _I2C23017_DATA));
+
+    if (buses[busnumber].driverdata == NULL) {
+        syslog_bus(busnumber, DBG_ERROR,
+                   "Memory allocation error in module '%s'.", node->name);
+        return 0;
+    }
+
+    buses[busnumber].type = SERVER_I2C23017;
+    buses[busnumber].init_func = &init_bus_I2C23017;
+    buses[busnumber].thr_func = &thr_sendrec_I2C23017;
+    buses[busnumber].init_ga_func = &init_ga_I2C23017;
+    strcpy(buses[busnumber].description,
+           "GA POWER DESCRIPTION");
+
+    buses[busnumber].device.file.fd = 0;
+
+    __i2c23017->number_ga = I2CBUS_ADDRESS_BASE + MAX_23017_DEVICES; /* maximal possible GA address +1 */
+    __i2c23017->ga_invert_outputs = false;
+    __i2c23017->i2c_maxrepeat = 1000;
+
+    xmlNodePtr child = node->children;
+    xmlChar *txt = NULL;
+
+    while (child != NULL) {
+
+        if ((xmlStrncmp(child->name, BAD_CAST "text", 4) == 0) ||
+            (xmlStrncmp(child->name, BAD_CAST "comment", 7) == 0)) {
+            /* just do nothing, it is only formatting text or a comment */
+        }
+
+ /*       else if (xmlStrcmp(child->name, BAD_CAST "number_fb") == 0) {
+            txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+            if (txt != NULL) {
+                __i2c23017->number_fb = atoi((char *) txt);
+                xmlFree(txt);
+            }
+        }
+*/
+        else if (xmlStrcmp(child->name, BAD_CAST "number_ga") == 0) {
+            txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+            if (txt != NULL) {
+                __i2c23017->number_ga = atoi((char *) txt);
+                xmlFree(txt);
+            }
+        }
+        else if (xmlStrcmp(child->name, BAD_CAST "ga_invert_outputs") == 0) {
+            txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+            if (txt != NULL) {
+                __i2c23017->ga_invert_outputs = atoi((char *) txt);
+                xmlFree(txt);
+            }
+        }
+        else if (xmlStrcmp(child->name, BAD_CAST "i2c_maxrepeat") == 0) {
+            txt = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
+            if (txt != NULL) {
+                __i2c23017->i2c_maxrepeat = atoi((char *) txt);
+                xmlFree(txt);
+            }
+        }
+        else
+            syslog_bus(busnumber, DBG_WARN,
+                       "WARNING, unknown tag found: \"%s\"!\n",
+                       child->name);;
+
+        child = child->next;
+    }
+
+    if (init_GA(busnumber, __i2c23017->number_ga)) {
+        __i2c23017->number_ga = 0;
+        syslog_bus(busnumber, DBG_ERROR,
+                   "Can't create array for accessoires");
+    }
+/*
+    if (init_FB(busnumber, __i2c23017->number_fb)) {
+        __i2c23017->number_fb = 0;
+        syslog_bus(busnumber, DBG_ERROR,
+                   "Can't create array for feedback");
+    }
+*/
+    if (__i2c23017->ga_invert_outputs) {
+    	__i2c23017->ga_hw_defaultbyte = (I2CBUS_VALUE)0xff;
+    }
+    else {
+    	__i2c23017->ga_hw_defaultbyte = (I2CBUS_VALUE)0x00;
+    }
+    return (1);
+}
+
+
+
+/**
+ * initGA: modifies the ga data used to initialize the device
+ **/
+int init_ga_I2C23017(ga_data_t * ga)
+{
+/*	syslog(LOG_INFO,
+        "found protocol %s for i2c-23017", ga->protocol);*/
+
+    if (ga->protocol == 'P') return SRCP_OK;
+    return SRCP_UNSUPPORTEDDEVICEPROTOCOL;
+}
+
+static int status_i2cdevice(bus_t busnumber, I2CBUS_ADDR i2caddress)
+{   int rc, gpioa, iodira, gpiob, iodirb;
+
+	rc = 0;
+
+    if (ioctl(buses[busnumber].device.file.fd, I2C_SLAVE, i2caddress) < 0)
+    	   syslog_bus(busnumber, DBG_INFO, "status_i2cdevice: ioctl() I2C_SLAVE failed at address 0x%x", i2caddress);
+    else
+    {
+        gpioa = i2c_smbus_read_byte_data(buses[busnumber].device.file.fd, I2C23017_GPIOA);
+        iodira = i2c_smbus_read_byte_data(buses[busnumber].device.file.fd, I2C23017_IODIRA);
+        gpiob = i2c_smbus_read_byte_data(buses[busnumber].device.file.fd, I2C23017_GPIOB);
+        iodirb = i2c_smbus_read_byte_data(buses[busnumber].device.file.fd, I2C23017_IODIRB);
+        syslog_bus(busnumber, DBG_DEBUG, "status_i2cdevice address=0x%x,  GPIOA=0x%x,  IODIRA=0x%x,  GPIOB=0x%x, IODIRB=0x%x\n",
+        		i2caddress, gpioa, iodira, gpiob, iodirb);
+        if ((iodira != 0) || (iodirb !=0))
+			{
+        	rc = 1;
+			}
+    }
+    return rc;
+}
+
+
+static int 	write_byte(bus_t busnumber, I2CBUS_ADDR address, I2CBUS_REGISTER reg, I2CBUS_VALUE value)
+{
+	int rc, i;
+
+    if (ioctl(buses[busnumber].device.file.fd, I2C_SLAVE, address) < 0) {
+     	   syslog_bus(busnumber, DBG_INFO, "write_byte: ioctl() I2C_SLAVE failed at address 0x%x", address);
+   	       return(1);
+   }
+
+	i=0;
+
+	do {
+		rc=i2c_smbus_write_byte_data(buses[busnumber].device.file.fd, reg, value);
+		i++;
+	}	while ( (rc < 0) && (i < __i2c23017->i2c_maxrepeat));
+
+	if ( i > 1 )
+		syslog_bus(busnumber, DBG_DEBUG, "%d write errors to i2c-device 0x%x", i, address);
+
+	if (rc < 0)
+	    {
+		syslog_bus(busnumber, DBG_ERROR, "failed writing to i2c-device 0x%x", address);
+	    }
+	return 0;
+}
+
+static int init_i2cdevice(bus_t busnumber, I2CBUS_ADDR address)
+{
+	int rc, dev;
+
+	syslog_bus(busnumber, DBG_INFO, "initializing i2c-device 0x%x", address);
+
+ 	rc = write_byte(busnumber, address, I2C23017_GPIOA, __i2c23017->ga_hw_defaultbyte); /* set to non-active state */
+	rc = write_byte(busnumber, address, I2C23017_IODIRA, 0x00);   /* set to output */
+	rc = write_byte(busnumber, address, I2C23017_GPIOB, __i2c23017->ga_hw_defaultbyte); /* set to non-active state */
+	rc = write_byte(busnumber, address, I2C23017_IODIRB, 0x00);   /* set to output */
+
+	return rc;
+
+}
+
+/* initialize bus
+ * called once
+ */
+int init_bus_I2C23017(bus_t busnumber)
+{
+    static char *protocols = "P";
+    I2CBUS_ADDR devices_found;
+    int dev, res;
+
+    buses[busnumber].protocols = protocols;
+
+    syslog_bus(busnumber, DBG_INFO,
+               "i2c-23017 start initialization (verbosity = %d).",
+               buses[busnumber].debuglevel);
+
+    if (buses[busnumber].device.file.fd == 0) {
+        if ((dev = open(buses[busnumber].device.file.path, O_RDWR)) < 0)
+    		    {
+    	        syslog_bus(busnumber, DBG_ERROR, "open() failed");
+    		    exit (1);
+    		    }
+    buses[busnumber].device.file.fd = dev;
+    }
+
+/* scan bus */
+    devices_found = 0;
+    for (I2CBUS_ADDR i2caddress = I2CBUS_ADDRESS_BASE; i2caddress < I2CBUS_ADDRESS_BASE + MAX_23017_DEVICES; i2caddress++)
+        {
+        if (ioctl(buses[busnumber].device.file.fd, I2C_SLAVE, i2caddress) < 0)
+        	   syslog_bus(busnumber, DBG_INFO, "init_bus_I2C23017: ioctl() I2C_SLAVE failed at address 0x%x", i2caddress);
+        else
+          {
+          /* test reading */
+          res = i2c_smbus_read_byte(buses[busnumber].device.file.fd);
+          if (res >= 0) {
+        	  __i2c23017->i2cdevices[devices_found]=i2caddress;
+         	  devices_found++;
+      	      syslog_bus(busnumber, DBG_INFO, "i2c chip found at: 0x%x, val = 0x%x\n", i2caddress, res);
+			  }
+          }
+        }
+
+    __i2c23017->i2cdevices[devices_found]=0;
+
+    for (I2CBUS_ADDR i = 0; __i2c23017->i2cdevices[i] > 0; i++)
+		{
+    	init_i2cdevice(busnumber, __i2c23017->i2cdevices[i]);
+		}
+
+    syslog_bus(busnumber, DBG_INFO, "i2c-23017 initialization done.");
+    return 0;
+}
+
+static int send_pulse(bus_t busnumber, I2CBUS_ADDR address, unsigned int port, unsigned int delay)
+{
+	int rc;
+	I2CBUS_REGISTER reg;
+	I2CBUS_VALUE val;
+
+	if ((port < 0) || ( port >15) )
+		{
+		syslog_bus(busnumber, DBG_ERROR, "invalid port %d", port);
+		return 1;
+		}
+
+	if (port <8 )
+		reg = I2C23017_GPIOA;
+	else
+		reg = I2C23017_GPIOB;
+
+	port = port % 8;
+
+	val = __i2c23017->ga_hw_defaultbyte ^ (1 << port)  ;
+
+	if (status_i2cdevice(busnumber, address)!=0)
+		init_i2cdevice(busnumber, address);    /* reinitialize i2c device */
+
+	rc = write_byte(busnumber, address, reg, val) ;
+
+	usleep(1000*delay);
+
+	rc = write_byte(busnumber, address, reg, __i2c23017->ga_hw_defaultbyte) ;
+
+}
+
+static void handle_power_command(bus_t bus)
+{
+    syslog_bus(bus, DBG_INFO, "handling power command for bus");
+
+    buses[bus].power_changed = 0;
+    char msg[110];
+
+    infoPower(bus, msg);
+    enqueueInfoMessage(msg);
+    buses[bus].watchdog++;
+}
+
+
+static void handle_ga_command(bus_t busnumber)
+{
+    ga_data_t gatmp;
+    int address, i;
+    struct timeval akt_time;
+
+    dequeueNextGA(busnumber, &gatmp);
+    address = gatmp.id;
+
+    syslog_bus(busnumber, DBG_INFO, "handling GA command address=0x%x, action=%d, port=%d, activetime=%d", address, gatmp.action, gatmp.port, gatmp.activetime);
+    send_pulse(busnumber, address, gatmp.port, gatmp.activetime);
+
+    buses[busnumber].watchdog++;
+}
+
+
+/*thread cleanup routine for this bus*/
+static void end_bus_thread(bus_thread_t * btd)
+{
+    int result;
+
+    syslog_bus(btd->bus, DBG_INFO, "i2c-23017 bus terminated.");
+
+    result = pthread_mutex_destroy(&buses[btd->bus].transmit_mutex);
+    if (result != 0) {
+        syslog_bus(btd->bus, DBG_WARN,
+                   "pthread_mutex_destroy() failed: %s (errno = %d).",
+                   strerror(result), result);
+    }
+
+    result = pthread_cond_destroy(&buses[btd->bus].transmit_cond);
+    if (result != 0) {
+        syslog_bus(btd->bus, DBG_WARN,
+                   "pthread_mutex_init() failed: %s (errno = %d).",
+                   strerror(result), result);
+    }
+
+    free(buses[btd->bus].driverdata);
+    free(btd);
+}
+
+/*main thread routine for this bus*/
+void *thr_sendrec_I2C23017(void *v)
+{
+    int addr, ctr;
+    struct timeval akt_time, cmp_time;
+    ga_data_t gatmp;
+    int last_cancel_state, last_cancel_type;
+
+    bus_thread_t *btd = (bus_thread_t *) malloc(sizeof(bus_thread_t));
+
+    if (btd == NULL)
+        pthread_exit((void *) 1);
+    btd->bus = (bus_t) v;
+    btd->fd = -1;
+
+    pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &last_cancel_state);
+    pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &last_cancel_type);
+
+    /*register cleanup routine */
+    pthread_cleanup_push((void *) end_bus_thread, (void *) btd);
+
+    /* initialize tga-structure */
+    for (ctr = 0; ctr < 50; ctr++)
+        __i2c23017t->tga[ctr].id = 0;
+
+    syslog_bus(btd->bus, DBG_INFO, "i2c-23017 bus started (device = %s).",
+               buses[btd->bus].device.file.path);
+
+    /*enter endless loop to process work tasks */
+    while (true) {
+
+        buses[btd->bus].watchdog = 1;
+
+        /*POWER action arrived */
+        if (buses[btd->bus].power_changed == 1)
+            handle_power_command(btd->bus);
+
+        /* loop shortcut to prevent processing of GA, GL (and FB)
+         * without power on; arriving commands will flood the command
+         * queue */
+        if (buses[btd->bus].power_state == 0) {
+
+            /* wait 1 ms */
+            if (usleep(1000) == -1) {
+                syslog_bus(btd->bus, DBG_ERROR,
+                           "usleep() failed: %s (errno = %d)\n",
+                           strerror(errno), errno);
+            }
+            continue;
+        }
+
+
+        /* handle delayed switching of GAs (there is a better place) */
+        gettimeofday(&akt_time, NULL);
+        for (ctr = 0; ctr < 50; ctr++) {
+            if (__i2c23017t->tga[ctr].id) {
+                cmp_time = __i2c23017t->tga[ctr].t;
+
+                /* switch off time reached? */
+                if (cmpTime(&cmp_time, &akt_time)) {
+                    gatmp = __i2c23017t->tga[ctr];
+                    addr = gatmp.id;
+                    gatmp.action = 0;
+                    setGA(btd->bus, addr, gatmp);
+                    __i2c23017t->tga[ctr].id = 0;
+                }
+            }
+        }
+
+        /*GA action arrived */
+        if (!queue_GA_isempty(btd->bus))
+            handle_ga_command(btd->bus);
+
+        /*FB action arrived */
+        /* currently nothing to do here */
+        buses[btd->bus].watchdog++;
+
+        /* busy wait and continue loop */
+        /* wait 1 ms */
+        if (usleep(1000) == -1) {
+            syslog_bus(btd->bus, DBG_ERROR,
+                       "usleep() failed: %s (errno = %d)\n",
+                       strerror(errno), errno);
+        }
+    }
+
+    /*run the cleanup routine */
+    pthread_cleanup_pop(1);
+    return NULL;
+}
Index: src/i2c-23017.h
===================================================================
--- src/i2c-23017.h	(.../tags/RELEASE_2_1_5)	(nicht existent)
+++ src/i2c-23017.h	(.../branches/bw-i2c-23017)	(Revision 1871)
@@ -0,0 +1,61 @@
+/***************************************************************************
+*                                                                         *
+*   This program is free software; you can redistribute it and/or modify  *
+*   it under the terms of the GNU General Public License as published by  *
+*   the Free Software Foundation; either version 2 of the License, or     *
+*   (at your option) any later version.                                   *
+*                                                                         *
+***************************************************************************/
+
+/**
+* i2c-23017: i2c bus driver for MCP23017.
+* This driver controls GAs (accessories) by the I/O ports of MCP23017  16Bit-I/O-Expanders 
+* driven by the i2c-dev interface of the Linux kernel. 
+* In order to deliver enough current for the accessories, the outputs are boosted by 
+* ULN2803A Darlington Transistor Arrays (2 in parallel).
+*
+* Copyright  (c) 2019-2021 by Bernd Wagner <berwag@users.sourceforge.net>
+*
+**/
+#ifndef _I2C23017_H
+#define _I2C23017_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define MAX_23017_DEVICES  8            /* MC23017 has 3 I2C-Address-Bits */
+#define I2CBUS_ADDRESS_BASE 0x20      /* MC23017 can have i2c addresses 0x20 .. 0x27 */
+
+typedef uint8_t  I2CBUS_VALUE;
+typedef uint8_t  I2CBUS_ADDR;
+typedef uint8_t  I2CBUS_REGISTER;
+
+#define I2C23017_IODIRA  0x00 /* IO direction register for GPA */
+#define I2C23017_IODIRB  0x01 /* IO direction register for GPB */
+#define I2C23017_OLATA  0x1A /* output latch register (GPA) */
+#define I2C23017_OLATB  0x15 /* output latch register (GPB) */
+#define I2C23017_GPIOA  0x12 /* IO register GPA */
+#define I2C23017_GPIOB  0x13 /* IO register (GPB) */
+
+
+#include <libxml/tree.h> /*xmlDocPtr, xmlNodePtr*/
+
+typedef struct _I2C23017_DATA {
+    unsigned int number_ga;
+    bool ga_invert_outputs; /* flag */
+    unsigned int i2c_maxrepeat;      /* max number of repetitions in case of write error */
+    ga_data_t tga[50];
+    I2CBUS_ADDR i2cdevices[MAX_23017_DEVICES+1] ;
+    I2CBUS_VALUE ga_hw_defaultbyte ; /* 0x00 or 0xff dependent of ga_invert_outputs */
+/*    I2CBUS_VALUE dataBuffer[MAX_23017_DEVICES*2]; //MCP23017 delivers 2 Byte */
+} I2C23017_DATA;
+
+
+int readconfig_I2C23017(xmlDocPtr doc, xmlNodePtr node, bus_t busnumber);
+int init_bus_I2C23017(bus_t );
+/* int init_gl_I2C23017(gl_data_t *);*/
+int init_ga_I2C23017(ga_data_t *);
+/* int getDescription_I2C23017(char *reply); */
+void* thr_sendrec_I2C23017(void *);
+
+#endif
Index: .
===================================================================
--- .	(.../tags/RELEASE_2_1_5)	(Revision 1759)
+++ .	(.../branches/bw-i2c-23017)	(Revision 1871)

Eigenschaftsänderungen: .
___________________________________________________________________
Added: svn:mergeinfo
## -0,0 +0,2 ##
   Zusammengeführt /branches/RELEASE_2_1_5_I2C-23017:r1795-1803
   Zusammengeführt /tags/RELEASE_2_1_5:r1760-1794
