From 30185d25fb67e89cea229a7f8f4cc79d856fc250 Mon Sep 17 00:00:00 2001 From: walter Date: Tue, 1 May 2018 23:13:29 +0200 Subject: [PATCH 1/7] This should be the first step... Now to find the I2C details. --- .../contrib/driver/sensehat/BaroTemp.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java new file mode 100644 index 0000000..4010f6e --- /dev/null +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java @@ -0,0 +1,20 @@ +package com.google.android.things.contrib.driver.sensehat; + +import com.google.android.things.pio.I2cDevice; +import com.google.android.things.pio.PeripheralManager; + +import java.io.IOException; + +public class BaroTemp { + private final I2cDevice mDevice; + + /** + * Create a new barometric pressure and temperature sensor driver connected on the given I2C bus. + * @param bus I2C bus the sensor is connected to. + * @throws IOException when a lower level does + */ + public BaroTemp(String bus) throws IOException { + PeripheralManager pioService = PeripheralManager.getInstance(); + mDevice = pioService.openI2cDevice(bus, SenseHat.I2C_LPS25H_ADDRESS); + } +} From 281a22ab7417fdc465e60eb7171a68e60d8b7846 Mon Sep 17 00:00:00 2001 From: walter Date: Tue, 1 May 2018 23:14:36 +0200 Subject: [PATCH 2/7] Changed the names of the constants to be less "selfish". --- .../android/things/contrib/driver/sensehat/LedMatrix.java | 2 +- .../android/things/contrib/driver/sensehat/SenseHat.java | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/LedMatrix.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/LedMatrix.java index 9156138..18a4bfb 100644 --- a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/LedMatrix.java +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/LedMatrix.java @@ -44,7 +44,7 @@ public class LedMatrix implements AutoCloseable { */ public LedMatrix(String bus) throws IOException { PeripheralManager pioService = PeripheralManager.getInstance(); - mDevice = pioService.openI2cDevice(bus, SenseHat.I2C_ADDRESS); + mDevice = pioService.openI2cDevice(bus, SenseHat.I2C_DISPLAY_ADDRESS); } /* package */ LedMatrix(I2cDevice device) { diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java index c3bed66..8e7822f 100644 --- a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java @@ -23,12 +23,13 @@ */ @SuppressWarnings({"unused", "WeakerAccess"}) public class SenseHat { - public static final int I2C_ADDRESS = 0x46; - public static final String BUS_DISPLAY = "I2C1"; + public static final int I2C_DISPLAY_ADDRESS = 0x46; + public static final int I2C_LPS25H_ADDRESS = 0x46; + public static final String BUS_NAME = "I2C1"; public static final int DISPLAY_WIDTH = LedMatrix.WIDTH; public static final int DISPLAY_HEIGHT = LedMatrix.HEIGHT; public static LedMatrix openDisplay() throws IOException { - return new LedMatrix(BUS_DISPLAY); + return new LedMatrix(BUS_NAME); } } From e7c8c2357e167a1ef3e823ddef112ece5defb96a Mon Sep 17 00:00:00 2001 From: walter Date: Fri, 4 May 2018 19:23:21 +0200 Subject: [PATCH 3/7] Should work but can't test. --- .../driver/sensehat/SenseHatDeviceTest.java | 41 +++--- .../contrib/driver/sensehat/BaroTemp.java | 130 +++++++++++++++++- .../contrib/driver/sensehat/SenseHat.java | 4 + 3 files changed, 155 insertions(+), 20 deletions(-) diff --git a/sensehat/src/androidTest/java/com/google/android/things/contrib/driver/sensehat/SenseHatDeviceTest.java b/sensehat/src/androidTest/java/com/google/android/things/contrib/driver/sensehat/SenseHatDeviceTest.java index df80356..646a502 100644 --- a/sensehat/src/androidTest/java/com/google/android/things/contrib/driver/sensehat/SenseHatDeviceTest.java +++ b/sensehat/src/androidTest/java/com/google/android/things/contrib/driver/sensehat/SenseHatDeviceTest.java @@ -26,6 +26,7 @@ import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.util.Log; import org.junit.Test; import org.junit.runner.RunWith; @@ -38,34 +39,38 @@ public class SenseHatDeviceTest { @Test public void senseHat_DisplayColor() throws IOException { // Color the LED matrix. - LedMatrix display = SenseHat.openDisplay(); - - display.draw(Color.MAGENTA); - // Close the display when done. - display.close(); + try (LedMatrix display = SenseHat.openDisplay()) { + display.draw(Color.MAGENTA); + } } @Test public void senseHat_DisplayDrawable() throws IOException { Context context = InstrumentationRegistry.getTargetContext(); // Display a drawable on the LED matrix. - LedMatrix display = SenseHat.openDisplay(); - display.draw(context.getDrawable(android.R.drawable.ic_secure)); - // Close the display when done. - display.close(); + try (LedMatrix display = SenseHat.openDisplay()) { + display.draw(context.getDrawable(android.R.drawable.ic_secure)); + } } @Test public void senseHat_DisplayGradient() throws IOException { // Display a gradient on the LED matrix. - LedMatrix display = SenseHat.openDisplay(); - Bitmap bitmap = Bitmap.createBitmap(SenseHat.DISPLAY_WIDTH, SenseHat.DISPLAY_HEIGHT, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); - paint.setShader(new RadialGradient(4, 4, 4, Color.RED, Color.BLUE, Shader.TileMode.CLAMP)); - canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint); - display.draw(bitmap); - // Close the display when done. - display.close(); + try (LedMatrix display = SenseHat.openDisplay()) { + Bitmap bitmap = Bitmap.createBitmap(SenseHat.DISPLAY_WIDTH, SenseHat.DISPLAY_HEIGHT, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + Paint paint = new Paint(); + paint.setShader(new RadialGradient(4, 4, 4, Color.RED, Color.BLUE, Shader.TileMode.CLAMP)); + canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), paint); + display.draw(bitmap); + } + } + + @Test + public void senseHat_BaroTemp() throws IOException { + try (BaroTemp baroTemp = SenseHat.openBaroTemp()) { + Log.i(BaroTemp.class.getName(),"SenseHat Barotemp raw pressure: "+baroTemp.getBarometerRaw()); + Log.i(BaroTemp.class.getName(),"SenseHat Barotemp raw temperature: "+baroTemp.getTemperatureRaw()); + } } } diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java index 4010f6e..9b848b2 100644 --- a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java @@ -3,18 +3,144 @@ import com.google.android.things.pio.I2cDevice; import com.google.android.things.pio.PeripheralManager; +import java.io.Closeable; import java.io.IOException; -public class BaroTemp { - private final I2cDevice mDevice; +public class BaroTemp implements AutoCloseable { + private I2cDevice mDevice; + // Register addresses + private final int LPS_REF_P_XL = 0x08; // Reference pressure, lowest byte + private final int LPS_REF_P_L = 0x09; // Reference pressure, low byte + private final int LPS_REF_P_H = 0x0A; // Reference pressure, high byte + + private final int LPS_WHO_AM_I = 0x0F; // Returns 0xbd (read only) + + private final int LPS_RES_CONF = 0x10; // Set pressure and temperature resolution + + private final int LPS_CTRL_REG1 = 0x20; // Set device power mode / ODR / BDU + private final int LPS_CTRL_REG2 = 0x21; // FIFO / I2C configuration + private final int LPS_CTRL_REG3 = 0x22; // Interrupt configuration + private final int LPS_CTRL_REG4 = 0x23; // Interrupt configuration + + private final int LPS_INTERRUPT_CFG = 0x24;// Interrupt configuration + private final int LPS_INT_SOURCE = 0x25; // Interrupt source configuration + + private final int LPS_STATUS_REG = 0x27; // Status (new pressure/temperature data available) + + private final int LPS_PRESS_OUT_XL = 0x28; // Pressure output, loweste byte + private final int LPS_PRESS_OUT_L = 0x29; // Pressure output, low byte + private final int LPS_PRESS_OUT_H = 0x2A; // Pressure output, high byte + + private final int LPS_TEMP_OUT_L = 0x2B; // Temperature output, low byte + private final int LPS_TEMP_OUT_H = 0x2C; // Temperature output, high byte + + private final int LPS_FIFO_CTRL = 0x2E; // FIFO control / mode selection + private final int LPS_FIFO_STATUS = 0x2F; // FIFO status + + private final int LPS_THS_P_L = 0x30; // Pressure interrupt threshold, low byte + private final int LPS_THS_P_H = 0x31; // Pressure interrupt threshold, high byte + + // The next two registers need special soldering + private final int LPS_RPDS_L = 0x39;// Pressure offset for differential pressure computing, low byte + private final int LPS_RPDS_H = 0x3A; // Differential offset, high byte /** * Create a new barometric pressure and temperature sensor driver connected on the given I2C bus. + * * @param bus I2C bus the sensor is connected to. * @throws IOException when a lower level does */ public BaroTemp(String bus) throws IOException { PeripheralManager pioService = PeripheralManager.getInstance(); mDevice = pioService.openI2cDevice(bus, SenseHat.I2C_LPS25H_ADDRESS); + // power down first + mDevice.writeRegByte(LPS_CTRL_REG1, (byte) 0); + // power up, data rate 12.5Hz (10110000) + mDevice.writeRegByte(LPS_CTRL_REG1, (byte) 0xb0); + } + + /** + * Closes this resource, relinquishing any underlying resources. + * This method is invoked automatically on objects managed by the + * {@code try}-with-resources statement. + *

+ *

While this interface method is declared to throw {@code + * Exception}, implementers are strongly encouraged to + * declare concrete implementations of the {@code close} method to + * throw more specific exceptions, or to throw no exception at all + * if the close operation cannot fail. + *

+ *

Cases where the close operation may fail require careful + * attention by implementers. It is strongly advised to relinquish + * the underlying resources and to internally mark the + * resource as closed, prior to throwing the exception. The {@code + * close} method is unlikely to be invoked more than once and so + * this ensures that the resources are released in a timely manner. + * Furthermore it reduces problems that could arise when the resource + * wraps, or is wrapped, by another resource. + *

+ *

Implementers of this interface are also strongly advised + * to not have the {@code close} method throw {@link + * InterruptedException}. + *

+ * This exception interacts with a thread's interrupted status, + * and runtime misbehavior is likely to occur if an {@code + * InterruptedException} is {@linkplain Throwable#addSuppressed + * suppressed}. + *

+ * More generally, if it would cause problems for an + * exception to be suppressed, the {@code AutoCloseable.close} + * method should not throw it. + *

+ *

Note that unlike the {@link Closeable#close close} + * method of {@link Closeable}, this {@code close} method + * is not required to be idempotent. In other words, + * calling this {@code close} method more than once may have some + * visible side effect, unlike {@code Closeable.close} which is + * required to have no effect if called more than once. + *

+ * However, implementers of this interface are strongly encouraged + * to make their {@code close} methods idempotent. + * + * @throws Exception if this resource cannot be closed + */ + @Override + public void close() throws IOException { + if (mDevice != null) { + try { + // power down device + mDevice.writeRegByte(LPS_CTRL_REG1, (byte) 0); + } catch (Exception any) { + // we tried + } + try { + mDevice.close(); + } finally { + mDevice = null; + } + } + } + + private int readSigned24(int a0, int a1, int a2) throws IOException { + int ret = mDevice.readRegByte(a0); + ret |= ((int) mDevice.readRegByte(a1)) << 8; + ret |= ((int) mDevice.readRegByte(a2)) << 16; + if (ret < 8388608) return ret; + else return ret - 16777216; + } + + private int readSigned16(int a0, int a1) throws IOException { + int ret = (mDevice.readRegByte(a0) & 0xFF); + ret |= (mDevice.readRegByte(a1) & 0xFF) << 8; + if (ret < 32768) return ret; + else return ret - 65536; + } + + public int getBarometerRaw() throws IOException { + return readSigned24(LPS_PRESS_OUT_XL, LPS_PRESS_OUT_L, LPS_PRESS_OUT_H); + } + + public int getTemperatureRaw() throws IOException { + return readSigned16(LPS_TEMP_OUT_L, LPS_TEMP_OUT_H); } } diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java index 8e7822f..227a8ce 100644 --- a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java @@ -32,4 +32,8 @@ public class SenseHat { public static LedMatrix openDisplay() throws IOException { return new LedMatrix(BUS_NAME); } + + public static BaroTemp openBaroTemp() throws IOException { + return new BaroTemp(BUS_NAME); + } } From 7b94d108aaa8b704a3a73e41c20d7fcee79c5784 Mon Sep 17 00:00:00 2001 From: walter Date: Fri, 4 May 2018 21:08:15 +0200 Subject: [PATCH 4/7] Implemented LPS25H (tested and works). --- .../contrib/driver/sensehat/BaroTemp.java | 128 +++++++++++------- 1 file changed, 76 insertions(+), 52 deletions(-) diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java index 9b848b2..13df1e8 100644 --- a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java @@ -3,9 +3,14 @@ import com.google.android.things.pio.I2cDevice; import com.google.android.things.pio.PeripheralManager; -import java.io.Closeable; import java.io.IOException; +/** + * This class allows access to the LPS25H on the SenseHat. + *

+ * See also: https://www.pololu.com/file/download/LPS25H.pdf?file_id=0J761

+ *

Source code referenced: https://github.com/tkurbad/mipSIE/blob/master/python/AltIMU-10v5/i2c.py

+ */ public class BaroTemp implements AutoCloseable { private I2cDevice mDevice; // Register addresses @@ -40,9 +45,10 @@ public class BaroTemp implements AutoCloseable { private final int LPS_THS_P_L = 0x30; // Pressure interrupt threshold, low byte private final int LPS_THS_P_H = 0x31; // Pressure interrupt threshold, high byte - // The next two registers need special soldering + // The next two registers need special soldering private final int LPS_RPDS_L = 0x39;// Pressure offset for differential pressure computing, low byte private final int LPS_RPDS_H = 0x3A; // Differential offset, high byte + private int milliBarAdjust = 0; /** * Create a new barometric pressure and temperature sensor driver connected on the given I2C bus. @@ -57,53 +63,11 @@ public BaroTemp(String bus) throws IOException { mDevice.writeRegByte(LPS_CTRL_REG1, (byte) 0); // power up, data rate 12.5Hz (10110000) mDevice.writeRegByte(LPS_CTRL_REG1, (byte) 0xb0); + if (0xBD != (mDevice.readRegByte(LPS_WHO_AM_I) & 0xFF)) { + throw new IOException("This does not seem to be a LPS25H"); + } } - /** - * Closes this resource, relinquishing any underlying resources. - * This method is invoked automatically on objects managed by the - * {@code try}-with-resources statement. - *

- *

While this interface method is declared to throw {@code - * Exception}, implementers are strongly encouraged to - * declare concrete implementations of the {@code close} method to - * throw more specific exceptions, or to throw no exception at all - * if the close operation cannot fail. - *

- *

Cases where the close operation may fail require careful - * attention by implementers. It is strongly advised to relinquish - * the underlying resources and to internally mark the - * resource as closed, prior to throwing the exception. The {@code - * close} method is unlikely to be invoked more than once and so - * this ensures that the resources are released in a timely manner. - * Furthermore it reduces problems that could arise when the resource - * wraps, or is wrapped, by another resource. - *

- *

Implementers of this interface are also strongly advised - * to not have the {@code close} method throw {@link - * InterruptedException}. - *

- * This exception interacts with a thread's interrupted status, - * and runtime misbehavior is likely to occur if an {@code - * InterruptedException} is {@linkplain Throwable#addSuppressed - * suppressed}. - *

- * More generally, if it would cause problems for an - * exception to be suppressed, the {@code AutoCloseable.close} - * method should not throw it. - *

- *

Note that unlike the {@link Closeable#close close} - * method of {@link Closeable}, this {@code close} method - * is not required to be idempotent. In other words, - * calling this {@code close} method more than once may have some - * visible side effect, unlike {@code Closeable.close} which is - * required to have no effect if called more than once. - *

- * However, implementers of this interface are strongly encouraged - * to make their {@code close} methods idempotent. - * - * @throws Exception if this resource cannot be closed - */ @Override public void close() throws IOException { if (mDevice != null) { @@ -122,25 +86,85 @@ public void close() throws IOException { } private int readSigned24(int a0, int a1, int a2) throws IOException { - int ret = mDevice.readRegByte(a0); - ret |= ((int) mDevice.readRegByte(a1)) << 8; - ret |= ((int) mDevice.readRegByte(a2)) << 16; + int ret = (mDevice.readRegByte(a0) & 0xFF); + ret += ((int) mDevice.readRegByte(a1) & 0xFF) << 8; + ret += ((int) mDevice.readRegByte(a2) & 0xFF) << 16; if (ret < 8388608) return ret; else return ret - 16777216; } private int readSigned16(int a0, int a1) throws IOException { int ret = (mDevice.readRegByte(a0) & 0xFF); - ret |= (mDevice.readRegByte(a1) & 0xFF) << 8; + ret += (mDevice.readRegByte(a1) & 0xFF) << 8; if (ret < 32768) return ret; else return ret - 65536; } + /** + * The sensor seems to have an offset to the actual pressure. You can find your local "real" pressure quite easily on the web. Get the measured value from the + * sensor and compute the difference. The value obtained can be passed to this method to "calibrate" your board's sensor. + * + * @param hPa difference to actual air pressure + * @throws IOException from I2cDevice + */ + public void setBarometerOffset(double hPa) throws IOException { + this.milliBarAdjust = (int) Math.round(hPa * 4096); + } + + /** + * Fetch raw value, see the data sheet. Note that this call waits for data to be available. + * + * @return The raw sensor value, adjusted by the given offset (if any). + * @throws IOException from I2cDevice + */ public int getBarometerRaw() throws IOException { - return readSigned24(LPS_PRESS_OUT_XL, LPS_PRESS_OUT_L, LPS_PRESS_OUT_H); + // wait for data available + while (0 == (mDevice.readRegByte(LPS_STATUS_REG) & 2)) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + throw new IOException(e); + } + } + return readSigned24(LPS_PRESS_OUT_XL, LPS_PRESS_OUT_L, LPS_PRESS_OUT_H) + milliBarAdjust; } + /** + * Fetch raw value, see the data sheet. Note that this call waits for data to be available. + * + * @return The raw sensor value. + * @throws IOException from I2cDevice + */ public int getTemperatureRaw() throws IOException { + // wait for data available + while (0 == (mDevice.readRegByte(LPS_STATUS_REG) & 1)) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + throw new IOException(e); + } + } return readSigned16(LPS_TEMP_OUT_L, LPS_TEMP_OUT_H); } + + /** + * Fetch air pressure in hPa (milli bar). Note that this call waits for data to be available. + * + * @return The current air pressure, adjusted by the given offset (if any). + * @throws IOException from I2cDevice + */ + public double getBarometer() throws IOException { + return getBarometerRaw() / 4096.0; + } + + /** + * Fetch the temperature in degrees Celcius. Note that the design of the SenseHat makes this more the + * temperature of the board then the actual (room) temperature! + * + * @return The temperature as reported by the sensor. + * @throws IOException from I2cDevice + */ + public double getTemperature() throws IOException { + return 42.5 + getTemperatureRaw() / 480.0; + } } From 3eb7bebeaae7ab79843848eb3c433ef0614a76c9 Mon Sep 17 00:00:00 2001 From: Walter Stroebel <7278535+Walter-Stroebel@users.noreply.github.com> Date: Fri, 4 May 2018 21:24:56 +0200 Subject: [PATCH 5/7] Update README.md Added usage for new BaroTemp sensor class. --- sensehat/README.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/sensehat/README.md b/sensehat/README.md index 97e3c63..8d5c327 100644 --- a/sensehat/README.md +++ b/sensehat/README.md @@ -4,7 +4,7 @@ Sense Hat driver for Android Things This driver provides easy access to the peripherals available on the Raspberry Pi [Sense Hat][product]: - 8x8 LED matrix - TODO: 5 buttons joystick -- TODO: Sensors +- TODO: Sensors other then LPS25H NOTE: these drivers are not production-ready. They are offered as sample @@ -54,6 +54,17 @@ display.draw(bitmap); // Close the display when done. display.close(); ``` +``` + try (BaroTemp bt = SenseHat.openBaroTemp()) { + bt.setBarometerOffset(-6.2); + Log.i(TAG, "PressureRaw: " + bt.getBarometerRaw()); + Log.i(TAG, "TemperatureRaw: " + bt.getTemperatureRaw()); + Log.i(TAG, "Pressure: " + bt.getBarometer()); + Log.i(TAG, "Temperature: " + bt.getTemperature()); + } catch (Exception e) { + Log.e(TAG, "Oops", e); + } +``` License ------- From 1c64936129ed520d5c95245f76c0b177ff47b28b Mon Sep 17 00:00:00 2001 From: walter Date: Sat, 5 May 2018 06:12:55 +0200 Subject: [PATCH 6/7] Fixes based on Fleker's review, with thanks! --- sensehat/README.md | 20 ++++++++++--------- .../contrib/driver/sensehat/SenseHat.java | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/sensehat/README.md b/sensehat/README.md index 8d5c327..09e1b3b 100644 --- a/sensehat/README.md +++ b/sensehat/README.md @@ -55,15 +55,17 @@ display.draw(bitmap); display.close(); ``` ``` - try (BaroTemp bt = SenseHat.openBaroTemp()) { - bt.setBarometerOffset(-6.2); - Log.i(TAG, "PressureRaw: " + bt.getBarometerRaw()); - Log.i(TAG, "TemperatureRaw: " + bt.getTemperatureRaw()); - Log.i(TAG, "Pressure: " + bt.getBarometer()); - Log.i(TAG, "Temperature: " + bt.getTemperature()); - } catch (Exception e) { - Log.e(TAG, "Oops", e); - } + // just a snippet that verifies the device is working + // your actual use would of course be much more awesome + try (BaroTemp bt = SenseHat.openBaroTemp()) { + bt.setBarometerOffset(-6.2); + Log.i(TAG, "PressureRaw: " + bt.getBarometerRaw()); + Log.i(TAG, "TemperatureRaw: " + bt.getTemperatureRaw()); + Log.i(TAG, "Pressure: " + bt.getBarometer()); + Log.i(TAG, "Temperature: " + bt.getTemperature()); + } catch (Exception e) { + Log.e(TAG, "Oops", e); + } ``` License diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java index 227a8ce..8968468 100644 --- a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java @@ -24,7 +24,7 @@ @SuppressWarnings({"unused", "WeakerAccess"}) public class SenseHat { public static final int I2C_DISPLAY_ADDRESS = 0x46; - public static final int I2C_LPS25H_ADDRESS = 0x46; + public static final int I2C_LPS25H_ADDRESS = 0x5C; public static final String BUS_NAME = "I2C1"; public static final int DISPLAY_WIDTH = LedMatrix.WIDTH; public static final int DISPLAY_HEIGHT = LedMatrix.HEIGHT; From 00a6d54017ab44c015754b20dc5837adbe04f6ef Mon Sep 17 00:00:00 2001 From: walter Date: Sat, 5 May 2018 06:12:55 +0200 Subject: [PATCH 7/7] Fixes based on Fleker's review, with thanks! --- sensehat/README.md | 20 ++++---- .../contrib/driver/sensehat/BaroTemp.java | 46 +++++++++++++------ .../contrib/driver/sensehat/SenseHat.java | 32 ++++++++++++- 3 files changed, 75 insertions(+), 23 deletions(-) diff --git a/sensehat/README.md b/sensehat/README.md index 8d5c327..09e1b3b 100644 --- a/sensehat/README.md +++ b/sensehat/README.md @@ -55,15 +55,17 @@ display.draw(bitmap); display.close(); ``` ``` - try (BaroTemp bt = SenseHat.openBaroTemp()) { - bt.setBarometerOffset(-6.2); - Log.i(TAG, "PressureRaw: " + bt.getBarometerRaw()); - Log.i(TAG, "TemperatureRaw: " + bt.getTemperatureRaw()); - Log.i(TAG, "Pressure: " + bt.getBarometer()); - Log.i(TAG, "Temperature: " + bt.getTemperature()); - } catch (Exception e) { - Log.e(TAG, "Oops", e); - } + // just a snippet that verifies the device is working + // your actual use would of course be much more awesome + try (BaroTemp bt = SenseHat.openBaroTemp()) { + bt.setBarometerOffset(-6.2); + Log.i(TAG, "PressureRaw: " + bt.getBarometerRaw()); + Log.i(TAG, "TemperatureRaw: " + bt.getTemperatureRaw()); + Log.i(TAG, "Pressure: " + bt.getBarometer()); + Log.i(TAG, "Temperature: " + bt.getTemperature()); + } catch (Exception e) { + Log.e(TAG, "Oops", e); + } ``` License diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java index 13df1e8..f9ce959 100644 --- a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/BaroTemp.java @@ -48,7 +48,7 @@ public class BaroTemp implements AutoCloseable { // The next two registers need special soldering private final int LPS_RPDS_L = 0x39;// Pressure offset for differential pressure computing, low byte private final int LPS_RPDS_H = 0x3A; // Differential offset, high byte - private int milliBarAdjust = 0; + private int mMillibarAdjust = 0; /** * Create a new barometric pressure and temperature sensor driver connected on the given I2C bus. @@ -101,18 +101,25 @@ private int readSigned16(int a0, int a1) throws IOException { } /** - * The sensor seems to have an offset to the actual pressure. You can find your local "real" pressure quite easily on the web. Get the measured value from the - * sensor and compute the difference. The value obtained can be passed to this method to "calibrate" your board's sensor. + * The sensor seems to have an offset to the actual pressure. You can find your local "real" + * pressure quite easily on the web. Get the measured value from the sensor and compute the + * difference. The value obtained can be passed to this method to "calibrate" your board's + * sensor. In the author's case the difference was 6.2 hPa which is quite significant. This + * error was confirmed with another (unrelated) sensor. * - * @param hPa difference to actual air pressure + * @param hPa difference to actual air pressure in hectoPascal (hPa) or millibar. * @throws IOException from I2cDevice */ public void setBarometerOffset(double hPa) throws IOException { - this.milliBarAdjust = (int) Math.round(hPa * 4096); + this.mMillibarAdjust = (int) Math.round(hPa * 4096); } /** - * Fetch raw value, see the data sheet. Note that this call waits for data to be available. + * Fetch raw value, see the data sheet.

Note that this call waits for data to be available. + * From the data sheet the (selected) refresh rate is 12.5 Hz so the max wait could be + * 1000/12.5 = 80 milliseconds with an average of 40 milliseconds. Call from asynchronous code + * if this is an issue. If your code calls this method less frequently then 12.5 times per + * second there will be no wait.

* * @return The raw sensor value, adjusted by the given offset (if any). * @throws IOException from I2cDevice @@ -126,11 +133,15 @@ public int getBarometerRaw() throws IOException { throw new IOException(e); } } - return readSigned24(LPS_PRESS_OUT_XL, LPS_PRESS_OUT_L, LPS_PRESS_OUT_H) + milliBarAdjust; + return readSigned24(LPS_PRESS_OUT_XL, LPS_PRESS_OUT_L, LPS_PRESS_OUT_H) + mMillibarAdjust; } /** - * Fetch raw value, see the data sheet. Note that this call waits for data to be available. + * Fetch raw value, see the data sheet.

Note that this call waits for data to be available. + * From the data sheet the (selected) refresh rate is 12.5 Hz so the max wait could be + * 1000/12.5 = 80 milliseconds with an average of 40 milliseconds. Call from asynchronous code + * if this is an issue. If your code calls this method less frequently then 12.5 times per + * second there will be no wait.

* * @return The raw sensor value. * @throws IOException from I2cDevice @@ -148,9 +159,13 @@ public int getTemperatureRaw() throws IOException { } /** - * Fetch air pressure in hPa (milli bar). Note that this call waits for data to be available. + * Fetch air pressure in hPa (millibar).

Note that this call waits for data to be available. + * From the data sheet the (selected) refresh rate is 12.5 Hz so the max wait could be + * 1000/12.5 = 80 milliseconds with an average of 40 milliseconds. Call from asynchronous code + * if this is an issue. If your code calls this method less frequently then 12.5 times per + * second there will be no wait.

* - * @return The current air pressure, adjusted by the given offset (if any). + * @return The current air pressure in hPa(millibar), adjusted by the given offset (if any). * @throws IOException from I2cDevice */ public double getBarometer() throws IOException { @@ -158,10 +173,15 @@ public double getBarometer() throws IOException { } /** - * Fetch the temperature in degrees Celcius. Note that the design of the SenseHat makes this more the - * temperature of the board then the actual (room) temperature! + * Fetch the temperature in degrees Celcius. Note that the design of the SenseHat makes this + * more the temperature of the board then the actual (room) temperature! + *

Also note that this call waits for data to be available. + * From the data sheet the (selected) refresh rate is 12.5 Hz so the max wait could be + * 1000/12.5 = 80 milliseconds with an average of 40 milliseconds. Call from asynchronous code + * if this is an issue. If your code calls this method less frequently then 12.5 times per + * second there will be no wait.

* - * @return The temperature as reported by the sensor. + * @return The temperature as reported by the sensor in degrees Celcius. * @throws IOException from I2cDevice */ public double getTemperature() throws IOException { diff --git a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java index 227a8ce..b92a963 100644 --- a/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java +++ b/sensehat/src/main/java/com/google/android/things/contrib/driver/sensehat/SenseHat.java @@ -24,16 +24,46 @@ @SuppressWarnings({"unused", "WeakerAccess"}) public class SenseHat { public static final int I2C_DISPLAY_ADDRESS = 0x46; - public static final int I2C_LPS25H_ADDRESS = 0x46; + public static final int I2C_LPS25H_ADDRESS = 0x5C; public static final String BUS_NAME = "I2C1"; public static final int DISPLAY_WIDTH = LedMatrix.WIDTH; public static final int DISPLAY_HEIGHT = LedMatrix.HEIGHT; + /** + * Connect to the LedMatrix of the SenseHat on a Raspberry Pi 3. + * @return The autoclosing LedMatrix object. + * @throws IOException If caused by the hardware. + */ public static LedMatrix openDisplay() throws IOException { return new LedMatrix(BUS_NAME); } + /** + * Connect to the LPS25H barometer/temperature of the SenseHat sensor on a Raspberry Pi 3. + * @return The autoclosing BaroTemp object. + * @throws IOException If caused by the hardware. + */ public static BaroTemp openBaroTemp() throws IOException { return new BaroTemp(BUS_NAME); } + + /** + * Connect to the LedMatrix of the SenseHat. + * @param busName The name of the I2C bus device on a non-raspi3 board. + * @return The autoclosing LedMatrix object. + * @throws IOException If caused by the hardware. + */ + public static LedMatrix openDisplay(final String busName) throws IOException { + return new LedMatrix(busName); + } + + /** + * Connect to the LPS25H barometer/temperature of the SenseHat sensor. + * @param busName The name of the I2C bus device on a non-raspi3 board. + * @return The autoclosing BaroTemp object. + * @throws IOException If caused by the hardware. + */ + public static BaroTemp openBaroTemp(final String busName) throws IOException { + return new BaroTemp(busName); + } }