From e759401a90088eea8a95daab5fa867bd0bf47a18 Mon Sep 17 00:00:00 2001
From: Oliver Ford <gitconf@oliford.co.uk>
Date: Thu, 25 May 2017 09:39:45 +0200
Subject: [PATCH] I2Cbaro: Allow sharing of I2C bus for multiple devices.  Keep
 a static array of TWIMaster objects and reuse if another instance has already
 initialized the bus.  Use synchronise() blocks to avoid simultaneous use of a
 bus.  Keep a count of the uses of each bus and close when the count goes to
 0.

---
 android/src/I2Cbaro.java | 158 +++++++++++++++++++++++++++--------------------
 1 file changed, 90 insertions(+), 68 deletions(-)

diff --git a/android/src/I2Cbaro.java b/android/src/I2Cbaro.java
index 5043da2..91015a0 100644
--- a/android/src/I2Cbaro.java
+++ b/android/src/I2Cbaro.java
@@ -127,7 +127,6 @@ final class I2Cbaro extends Thread {
 
   static final byte oversampling5611 = CMD5611_ADC_4096;	// I see no reason to use anything else.
 
-  private TwiMaster h_twi;
   private byte i2c_addr;
   private int flags;
   private final Listener listener;
@@ -165,13 +164,26 @@ final class I2Cbaro extends Thread {
 
   private byte[] dummy = new byte [0];
 
-
+  /**
+   * Sharing of the TWI objects to allow multiple sensors on one I2C bus
+   */
+  private static TwiMaster h_twi[] = new TwiMaster[256];
+  private static int twiUseCount[] = new int[256];
+  private int twiIndex;
+  
   public I2Cbaro(IOIO ioio, int twiNum, int _i2c_addr, int _sample_rate, int _flags,
                 Listener _listener)
     throws ConnectionLostException {
     super("I2Cbaro");
+    this.twiIndex = twiNum & 0xff;
+
+    synchronized(twiUseCount){
+      if(twiUseCount[twiIndex] <= 0){
+        h_twi[twiIndex] = ioio.openTwiMaster(twiNum & 0xff, TwiMaster.Rate.RATE_100KHz, false);
+      }
+      twiUseCount[twiIndex]++;
+    }
 
-    h_twi = ioio.openTwiMaster(twiNum & 0xff, TwiMaster.Rate.RATE_100KHz, false);
     listener = _listener;
     if ((twiNum & 0xff00) == 0)
       i2c_addr =  (byte)_i2c_addr;
@@ -191,8 +203,12 @@ final class I2Cbaro extends Thread {
     if (h_eoc != null)
       h_eoc.close();
 
-    if (h_twi != null)
-      h_twi.close();
+    synchronized(twiUseCount){
+      if (h_twi[twiIndex] != null && twiUseCount[twiIndex] <= 1){
+          h_twi[twiIndex].close();
+      }
+      twiUseCount[twiIndex]--;
+    }
 
     interrupt();
 
@@ -217,8 +233,7 @@ final class I2Cbaro extends Thread {
 
   private void reset5611()
     throws ConnectionLostException, InterruptedException {
-
-    h_twi.writeRead(i2c_addr, false, request5611Reset, request5611Reset.length, dummy, 0);
+    h_twi[twiIndex].writeRead(i2c_addr, false, request5611Reset, request5611Reset.length, dummy, 0);
     sleep(5);
   }
 
@@ -226,14 +241,14 @@ final class I2Cbaro extends Thread {
     throws ConnectionLostException, InterruptedException {
     /* is it a BMP085 sensor? */
     byte[] response085ChipID = new byte[1];
-    h_twi.writeRead(i2c_addr, false,
+    h_twi[twiIndex].writeRead(i2c_addr, false,
                   request085ChipID, request085ChipID.length,
                   response085ChipID, response085ChipID.length);
     if (response085ChipID[0] != BMP085_CHIP_ID)
       return false;
 
     /* read the calibration coefficients */
-    h_twi.writeRead(i2c_addr, false,
+    h_twi[twiIndex].writeRead(i2c_addr, false,
                   request085Parameters, request085Parameters.length,
                   response085Parameters, response085Parameters.length);
 
@@ -255,51 +270,55 @@ final class I2Cbaro extends Thread {
 
   private boolean setup5611()
     throws ConnectionLostException, InterruptedException {
+    synchronized(h_twi[twiIndex]){
 
-    int[] prom = new int [8];
+      int[] prom = new int [8];
 
-    reset5611();
+      reset5611();
 
-    /* Untill Checksum is implemented: too many zero results from EEPROM means no barometer present */
-    int zeros = 0;
+      /* Untill Checksum is implemented: too many zero results from EEPROM means no barometer present */
+      int zeros = 0;
 
-    /* Read Caldata from EEPROM */
-    for (int i = 0; i<8; i++) {
-      response5611[0]=0;response5611[1]=0;response5611[2]=0;
-      request5611Caldata[0] = (byte)(CMD5611_PROM_RD + 2*i);
-      h_twi.writeRead(i2c_addr, false, request5611Caldata, request5611Caldata.length, dummy, 0);
-      h_twi.writeRead(i2c_addr, false, dummy, 0, response5611, 2);
-      prom[i] = readU16BE(response5611, 0);
-      if (prom[i] == 0) zeros++;
-    }
+      /* Read Caldata from EEPROM */
+      for (int i = 0; i<8; i++) {
+        response5611[0]=0;response5611[1]=0;response5611[2]=0;
+        request5611Caldata[0] = (byte)(CMD5611_PROM_RD + 2*i);
+        h_twi[twiIndex].writeRead(i2c_addr, false, request5611Caldata, request5611Caldata.length, dummy, 0);
+        h_twi[twiIndex].writeRead(i2c_addr, false, dummy, 0, response5611, 2);
+        prom[i] = readU16BE(response5611, 0);
+        if (prom[i] == 0) zeros++;
+      }
 
-    // TODO: checksum
-    if (zeros > 1)
-        return false;
+      // TODO: checksum
+      if (zeros > 1)
+          return false;
 
-    C1s = ((long)prom[1]) * 32768L;
-    C2s = ((long)prom[2]) * 65536L;
-    C3  = prom[3];
-    C4  = prom[4];
-    C5s = prom[5] * 256;
-    C6  = prom[6];
+      C1s = ((long)prom[1]) * 32768L;
+      C2s = ((long)prom[2]) * 65536L;
+      C3  = prom[3];
+      C4  = prom[4];
+      C5s = prom[5] * 256;
+      C6  = prom[6];
+    }
 
     return true;
   }
 
   private void read085Sensor(byte[] request, byte[] response, int responseLength)
     throws ConnectionLostException, InterruptedException {
-    h_twi.writeRead(i2c_addr, false,
-                  request, request.length, dummy, 0);
-
-     if (h_eoc != null)
-       h_eoc.waitForValue(true);
-     else
-       sleep(26);
-
-    h_twi.writeRead(i2c_addr, false,
-                  request085Value, request085Value.length,
-                  response, responseLength);
+    synchronized(h_twi[twiIndex]){
+      h_twi[twiIndex].writeRead(i2c_addr, false,
+                    request, request.length, dummy, 0);
+
+       if (h_eoc != null)
+         h_eoc.waitForValue(true);
+       else
+         sleep(26);
+
+      h_twi[twiIndex].writeRead(i2c_addr, false,
+                    request085Value, request085Value.length,
+                    response, responseLength);
+    }
   }
 
   private int getB5(int ut) {
@@ -353,15 +372,18 @@ final class I2Cbaro extends Thread {
   private int loop_count085 = 0;
   private int b5_085;
   private void loop085() throws ConnectionLostException, InterruptedException {
-    if (loop_count085 % 10 == 0) {
-      /* Start temp conversion but only every 10th loop. */
-      read085Sensor(read085Temperature, response085, 2);
-      b5_085 = getB5(readU16BE(response085, 0));
-      /* double temperature_c = (double)((b5 + 8) >> 4) / 10.0; */
+    int pressure_pa;
+    synchronized(h_twi[twiIndex]){
+      if (loop_count085 % 10 == 0) {
+        /* Start temp conversion but only every 10th loop. */
+        read085Sensor(read085Temperature, response085, 2);
+        b5_085 = getB5(readU16BE(response085, 0));
+        /* double temperature_c = (double)((b5 + 8) >> 4) / 10.0; */
+      }
+      read085Sensor(read085Pressure, response085, 3);
+      int up = readU24BE(response085, 0) >> (8 - oversampling085);
+      pressure_pa = get085Pressure(up, b5_085);
     }
-    read085Sensor(read085Pressure, response085, 3);
-    int up = readU24BE(response085, 0) >> (8 - oversampling085);
-    int pressure_pa = get085Pressure(up, b5_085);
 
     listener.onI2CbaroValues(85, pressure_pa);
     loop_count085++;
@@ -370,8 +392,8 @@ final class I2Cbaro extends Thread {
 
   private int read5611Sensor()
     throws ConnectionLostException, InterruptedException {
-    h_twi.writeRead(i2c_addr, false, request5611Value, request5611Value.length, dummy, 0);
-    h_twi.writeRead(i2c_addr, false, dummy, 0 , response5611, 3);
+    h_twi[twiIndex].writeRead(i2c_addr, false, request5611Value, request5611Value.length, dummy, 0);
+    h_twi[twiIndex].writeRead(i2c_addr, false, dummy, 0 , response5611, 3);
     return readU24BE(response5611, 0);
   }
 
@@ -379,26 +401,26 @@ final class I2Cbaro extends Thread {
   private int TEMP;
   private long dT;
   private void loop5611() throws ConnectionLostException, InterruptedException {
-
     /* for some reason it does not work using shifts on long variables */
-
     int D1, P=0;
+    synchronized(h_twi[twiIndex]){
+      
+      /* Start temp conversion but only every 10th loop. */
+      if (loop_count5611 % 10 == 0) {
+  	h_twi[twiIndex].writeRead(i2c_addr, false, request5611Temp, request5611Temp.length, dummy, 0);
+          sleep(11);
+          /* Read temp value and compute temperature */
+          dT = read5611Sensor() - C5s;
+          TEMP = (int)(2000L + ((dT * C6) >> 23));
+      }
 
-    /* Start temp conversion but only every 10th loop. */
-    if (loop_count5611 % 10 == 0) {
-	h_twi.writeRead(i2c_addr, false, request5611Temp, request5611Temp.length, dummy, 0);
-        sleep(11);
-        /* Read temp value and compute temperature */
-        dT = read5611Sensor() - C5s;
-        TEMP = (int)(2000L + ((dT * C6) >> 23));
-    }
-
-    /* Start pressure conversion. */
-    h_twi.writeRead(i2c_addr, false, request5611Press, request5611Press.length, dummy, 0);
-    sleep(11);
+      /* Start pressure conversion. */
+      h_twi[twiIndex].writeRead(i2c_addr, false, request5611Press, request5611Press.length, dummy, 0);
+      sleep(11);
 
-    /* Read pressure value */
-    D1 = read5611Sensor();
+      /* Read pressure value */
+      D1 = read5611Sensor();
+    }
 
     long OFF = C2s + (C4 * dT) / 128L;
     long SENS = C1s + (C3 * dT) / 256L;
-- 
2.7.4

