diff --git a/driver-tsl256x/.gitignore b/driver-tsl256x/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/driver-tsl256x/.gitignore @@ -0,0 +1 @@ +/build diff --git a/driver-tsl256x/CHANGELOG.md b/driver-tsl256x/CHANGELOG.md new file mode 100644 index 0000000..9832057 --- /dev/null +++ b/driver-tsl256x/CHANGELOG.md @@ -0,0 +1,4 @@ +# Change Log + +## [0.1] - 2018-01-30 +- initial version diff --git a/driver-tsl256x/README.md b/driver-tsl256x/README.md new file mode 100644 index 0000000..3d5265d --- /dev/null +++ b/driver-tsl256x/README.md @@ -0,0 +1,58 @@ +# TSL256x sensor driver for Android Things + +[![Maven metadata URI](https://img.shields.io/maven-metadata/v/http/jcenter.bintray.com/com/leinardi/android/things/driver-tsl256x/maven-metadata.xml.svg?style=plastic)](https://jcenter.bintray.com/com/leinardi/android/things/driver-tsl256x/maven-metadata.xml) +[![Build Status](https://img.shields.io/travis/leinardi/androidthings-drivers/master.svg?style=plastic)](https://travis-ci.org/leinardi/androidthings-drivers) +[![GitHub license](https://img.shields.io/github/license/leinardi/androidthings-drivers.svg?style=plastic)](https://github.com/leinardi/androidthings-drivers/blob/master/LICENSE) + +This driver supports sensor peripherals built on the TSL256x chip. + +NOTE: these drivers are not production-ready. They are offered as sample +implementations of Android Things user space drivers for common peripherals +as part of the Developer Preview release. There is no guarantee +of correctness, completeness or robustness. + +This driver is based on the [Adafruit_TSL256x driver from adafruit](https://github.com/adafruit/Adafruit_TSL256x), +the [Adafruit_CircuitPython_TSL256x driver from adafruit](https://github.com/adafruit/Adafruit_CircuitPython_TSL256x) +and the [TSL256x_RaspberryPi_Library driver from akimach](https://github.com/akimach/TSL256x_RaspberryPi_Library) + +## How to use the driver + +### Gradle dependency + +To use the `tsl256x` driver, simply add the line below to your project's `build.gradle`, +where `` matches the last version of the driver available on [jcenter][jcenter]. + +``` +dependencies { + implementation 'com.leinardi.android.things:driver-tsl256x:' +} +``` + +### Sample usage + +```java +// TBD +``` + +To use it with the `SensorManager` check the [sample project](https://github.com/leinardi/androidthings-drivers/tree/tsl256x/sample-tsl256x). + +## License + +Copyright 2018 Roberto Leinardi + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. + +[jcenter]: https://bintray.com/leinardi/androidthings/driver-tsl256x/_latestVersion diff --git a/driver-tsl256x/build.gradle b/driver-tsl256x/build.gradle new file mode 100644 index 0000000..bf956a5 --- /dev/null +++ b/driver-tsl256x/build.gradle @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'com.android.library' +apply from: rootProject.file('checkstyle.gradle') + +android { + compileSdkVersion build_versions.target_sdk + buildToolsVersion build_versions.build_tools + + apply from: 'mavenConfig.gradle' + + defaultConfig { + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + versionCode build_versions.version_code + versionName mvn_config.version as String + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + + compileOptions { + sourceCompatibility build_versions.java_version + targetCompatibility build_versions.java_version + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + compileOnly deps.androidthings + implementation deps.support.annotations + + testImplementation deps.androidthings + testImplementation deps.powermock.module_junit4 + testImplementation deps.powermock.api_mockito +} diff --git a/driver-tsl256x/docs/TSL2560-61.pdf b/driver-tsl256x/docs/TSL2560-61.pdf new file mode 100644 index 0000000..3fbe144 Binary files /dev/null and b/driver-tsl256x/docs/TSL2560-61.pdf differ diff --git a/driver-tsl256x/docs/TSL2560-61_DS000110_2-00.pdf b/driver-tsl256x/docs/TSL2560-61_DS000110_2-00.pdf new file mode 100644 index 0000000..9cecd3d Binary files /dev/null and b/driver-tsl256x/docs/TSL2560-61_DS000110_2-00.pdf differ diff --git a/driver-tsl256x/docs/TSL2562-63.pdf b/driver-tsl256x/docs/TSL2562-63.pdf new file mode 100644 index 0000000..9dcd75a Binary files /dev/null and b/driver-tsl256x/docs/TSL2562-63.pdf differ diff --git a/driver-tsl256x/mavenConfig.gradle b/driver-tsl256x/mavenConfig.gradle new file mode 100644 index 0000000..3e53e38 --- /dev/null +++ b/driver-tsl256x/mavenConfig.gradle @@ -0,0 +1,37 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +def mvn_config = [:] +mvn_config.repository = 'androidthings' +mvn_config.group_id = 'com.leinardi.android.things' +mvn_config.artifact_id = 'driver-tsl256x' +mvn_config.version = '0.4' +mvn_config.licenses = 'Apache-2.0' // Comma separated +mvn_config.website = 'https://github.com/leinardi/androidthings-drivers' +mvn_config.issue_tracker_url = 'https://github.com/leinardi/androidthings-drivers/issues' +mvn_config.vcs_url = 'https://github.com/leinardi/androidthings-drivers.git' +mvn_config.description = 'TSL256x driver for Android Things' +mvn_config.tags = 'tsl2560,tsl2561,tsl2562,tsl2563,android-things,android,raspberry-pi' // Comma separated +mvn_config.githubRepo = 'leinardi/androidthings-drivers' +mvn_config.inception_year = '2017' +mvn_config.dryRun = false +mvn_config.publish = false +mvn_config.override = true + +ext.mvn_config = mvn_config + +apply from: rootProject.file('maven.gradle') +apply from: rootProject.file('bintray.gradle') diff --git a/driver-tsl256x/proguard-rules.pro b/driver-tsl256x/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/driver-tsl256x/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/driver-tsl256x/src/main/AndroidManifest.xml b/driver-tsl256x/src/main/AndroidManifest.xml new file mode 100644 index 0000000..7505dd0 --- /dev/null +++ b/driver-tsl256x/src/main/AndroidManifest.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/driver-tsl256x/src/main/java/com/leinardi/android/things/driver/tsl256x/Tsl256x.java b/driver-tsl256x/src/main/java/com/leinardi/android/things/driver/tsl256x/Tsl256x.java new file mode 100644 index 0000000..d53011a --- /dev/null +++ b/driver-tsl256x/src/main/java/com/leinardi/android/things/driver/tsl256x/Tsl256x.java @@ -0,0 +1,600 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.driver.tsl256x; + +import android.os.SystemClock; +import android.support.annotation.IntDef; +import android.util.Log; + +import com.google.android.things.pio.I2cDevice; +import com.google.android.things.pio.PeripheralManagerService; + +import java.io.Closeable; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.Gain.GAIN_16X; +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.Gain.GAIN_1X; +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.IntegrationTime.INTEGRATIONTIME_101MS; +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.IntegrationTime.INTEGRATIONTIME_13_7MS; +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.IntegrationTime.INTEGRATIONTIME_402MS; +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.Mode.MODE_ACTIVE; +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.Mode.MODE_STANDBY; +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.PackageType.CS; +import static com.leinardi.android.things.driver.tsl256x.Tsl256x.PackageType.T_FN_CL; +import static java.lang.Math.pow; + +/** + * Driver for the TSL256x light-to-digital converter. + */ +@SuppressWarnings("WeakerAccess") +public class Tsl256x implements Closeable { + private static final String TAG = Tsl256x.class.getSimpleName(); + + private static final int COMMAND_BIT = 0b1000_0000; // Must be 1 + private static final int CLEAR_BIT = 0b0100_0000; // Clears any pending interrupt (write 1 to clear) + private static final int WORD_BIT = 0b0010_0000; // 1 = read/write word (rather than byte) + private static final int BLOCK_BIT = 0b0001_0000; // 1 = using block read/write + + private static final int REGISTER_CONTROL = 0x00; // Control/power register + private static final int REGISTER_TIMING = 0x01; // Set integration time register + private static final int REGISTER_THRESHHOLDL_LOW = 0x02; // Interrupt low threshold low-byte + private static final int REGISTER_THRESHHOLDL_HIGH = 0x03; // Interrupt low threshold high-byte + private static final int REGISTER_THRESHHOLDH_LOW = 0x04; // Interrupt high threshold low-byte + private static final int REGISTER_THRESHHOLDH_HIGH = 0x05; // Interrupt high threshold high-byte + private static final int REGISTER_INTERRUPT = 0x06; // Interrupt settings + private static final int REGISTER_CRC = 0x08; // Factory use only + private static final int REGISTER_ID = 0x0A; // TSL2561 identification setting + private static final int REGISTER_CHAN0_LOW = 0x0C; // Light data channel 0, low byte + private static final int REGISTER_CHAN0_HIGH = 0x0D; // Light data channel 0, high byte + private static final int REGISTER_CHAN1_LOW = 0x0E; // Light data channel 1, low byte + private static final int REGISTER_CHAN1_HIGH = 0x0F; // Light data channel 1, high byte + + private static final int ID_PART_NUMBER = 0b1111_0000; + private static final int ID_REVISION_NUMBER = 0b0000_1111; + private static final int TSL2560_ID = 0b0000_0000; + private static final int TSL2561_ID = 0b0001_0000; + private static final int TSL2562_ID = 0b0010_0000; + private static final int TSL2563_ID = 0b0011_0000; + private static final int TSL2560T_FN_CL_ID = 0b0100_0000; + private static final int TSL2561T_FN_CL_ID = 0b0101_0000; + + private static final int LUX_LUXSCALE = 14; // Scale by 2^14 + private static final int LUX_RATIOSCALE = 9; // Scale ratio by 2^9 + private static final int LUX_CHSCALE = 10; // Scale channel values by 2^10 + private static final int LUX_CHSCALE_TINT0 = 0x7517; // 322/11 * 2^LUX_CHSCALE + private static final int LUX_CHSCALE_TINT1 = 0x0FE7; // 322/81 * 2^LUX_CHSCALE + + // CS package values + private static final int LUX_K1CS = 0x0043; // 0.130 * 2^RATIO_SCALE + private static final int LUX_B1CS = 0x0204; // 0.0315 * 2^LUX_SCALE + private static final int LUX_M1CS = 0x01ad; // 0.0262 * 2^LUX_SCALE + private static final int LUX_K2CS = 0x0085; // 0.260 * 2^RATIO_SCALE + private static final int LUX_B2CS = 0x0228; // 0.0337 * 2^LUX_SCALE + private static final int LUX_M2CS = 0x02c1; // 0.0430 * 2^LUX_SCALE + private static final int LUX_K3CS = 0x00c8; // 0.390 * 2^RATIO_SCALE + private static final int LUX_B3CS = 0x0253; // 0.0363 * 2^LUX_SCALE + private static final int LUX_M3CS = 0x0363; // 0.0529 * 2^LUX_SCALE + private static final int LUX_K4CS = 0x010a; // 0.520 * 2^RATIO_SCALE + private static final int LUX_B4CS = 0x0282; // 0.0392 * 2^LUX_SCALE + private static final int LUX_M4CS = 0x03df; // 0.0605 * 2^LUX_SCALE + private static final int LUX_K5CS = 0x014d; // 0.65 * 2^RATIO_SCALE + private static final int LUX_B5CS = 0x0177; // 0.0229 * 2^LUX_SCALE + private static final int LUX_M5CS = 0x01dd; // 0.0291 * 2^LUX_SCALE + private static final int LUX_K6CS = 0x019a; // 0.80 * 2^RATIO_SCALE + private static final int LUX_B6CS = 0x0101; // 0.0157 * 2^LUX_SCALE + private static final int LUX_M6CS = 0x0127; // 0.0180 * 2^LUX_SCALE + private static final int LUX_K7CS = 0x029a; // 1.3 * 2^RATIO_SCALE + private static final int LUX_B7CS = 0x0037; // 0.00338 * 2^LUX_SCALE + private static final int LUX_M7CS = 0x002b; // 0.00260 * 2^LUX_SCALE + private static final int LUX_K8CS = 0x029a; // 1.3 * 2^RATIO_SCALE + private static final int LUX_B8CS = 0x0000; // 0.000 * 2^LUX_SCALE + private static final int LUX_M8CS = 0x0000; // 0.000 * 2^LUX_SCALE + + // T, FN and CL package values + private static final int LUX_K1T = 0x0040; // 0.125 * 2^RATIO_SCALE + private static final int LUX_B1T = 0x01f2; // 0.0304 * 2^LUX_SCALE + private static final int LUX_M1T = 0x01be; // 0.0272 * 2^LUX_SCALE + private static final int LUX_K2T = 0x0080; // 0.250 * 2^RATIO_SCALE + private static final int LUX_B2T = 0x0214; // 0.0325 * 2^LUX_SCALE + private static final int LUX_M2T = 0x02d1; // 0.0440 * 2^LUX_SCALE + private static final int LUX_K3T = 0x00c0; // 0.375 * 2^RATIO_SCALE + private static final int LUX_B3T = 0x023f; // 0.0351 * 2^LUX_SCALE + private static final int LUX_M3T = 0x037b; // 0.0544 * 2^LUX_SCALE + private static final int LUX_K4T = 0x0100; // 0.50 * 2^RATIO_SCALE + private static final int LUX_B4T = 0x0270; // 0.0381 * 2^LUX_SCALE + private static final int LUX_M4T = 0x03fe; // 0.0624 * 2^LUX_SCALE + private static final int LUX_K5T = 0x0138; // 0.61 * 2^RATIO_SCALE + private static final int LUX_B5T = 0x016f; // 0.0224 * 2^LUX_SCALE + private static final int LUX_M5T = 0x01fc; // 0.0310 * 2^LUX_SCALE + private static final int LUX_K6T = 0x019a; // 0.80 * 2^RATIO_SCALE + private static final int LUX_B6T = 0x00d2; // 0.0128 * 2^LUX_SCALE + private static final int LUX_M6T = 0x00fb; // 0.0153 * 2^LUX_SCALE + private static final int LUX_K7T = 0x029a; // 1.3 * 2^RATIO_SCALE + private static final int LUX_B7T = 0x0018; // 0.00146 * 2^LUX_SCALE + private static final int LUX_M7T = 0x0012; // 0.00112 * 2^LUX_SCALE + private static final int LUX_K8T = 0x029a; // 1.3 * 2^RATIO_SCALE + private static final int LUX_B8T = 0x0000; // 0.000 * 2^LUX_SCALE + private static final int LUX_M8T = 0x0000; // 0.000 * 2^LUX_SCALE + + // Auto-gain thresholds + private static final int AGC_THI_13MS = 4850; // Max value at Ti 13ms = 5047 + private static final int AGC_TLO_13MS = 100; // Min value at Ti 13ms = 100 + private static final int AGC_THI_101MS = 36000; // Max value at Ti 101ms = 37177 + private static final int AGC_TLO_101MS = 200; // Min value at Ti 101ms = 200 + private static final int AGC_THI_402MS = 63000; // Max value at Ti 402ms = 65535 + private static final int AGC_TLO_402MS = 500; // Min value at Ti 402ms = 500 + + private byte mChipId; + private boolean mAutoGain; + @IntegrationTime + private int mIntegrationTime; + @Gain + private int mGain; + @PackageType + private int mPackageType; + private I2cDevice mDevice; + + /** + * Create a new TSL2561 driver connected to the given I2C bus. + * + * @param i2cName I2C bus name the display is connected to + * @param i2cAddress I2C address of the display + * @throws IOException + */ + public Tsl256x(String i2cName, int i2cAddress) throws IOException { + PeripheralManagerService pioService = new PeripheralManagerService(); + I2cDevice device = pioService.openI2cDevice(i2cName, i2cAddress); + try { + connect(device); + } catch (IOException | RuntimeException e) { + try { + close(); + } catch (IOException | RuntimeException ignored) { + } + throw e; + } + } + + private void connect(I2cDevice device) throws IOException { + if (mDevice != null) { + throw new IllegalStateException("device already connected"); + } + mDevice = device; + + @PackageType int packageType = CS; + + mChipId = readRegByte(REGISTER_ID); + int partNumber = (mChipId & ID_PART_NUMBER) & 0xFF; + switch (partNumber) { + case TSL2560_ID: + Log.d(TAG, "Found TSL2560"); + break; + case TSL2561_ID: + Log.d(TAG, "Found TSL2561"); + break; + case TSL2562_ID: + Log.d(TAG, "Found TSL2562"); + break; + case TSL2563_ID: + Log.d(TAG, "Found TSL2563"); + break; + case TSL2560T_FN_CL_ID: + Log.d(TAG, "Found TSL2560T/FN/CL"); + packageType = T_FN_CL; + break; + case TSL2561T_FN_CL_ID: + Log.d(TAG, "Found TSL2561T/FN/CL"); + packageType = T_FN_CL; + break; + default: + throw new IllegalStateException("Could not find a TSL256x, check wiring!"); + } + + setPackageType(packageType); + setIntegrationTime(INTEGRATIONTIME_13_7MS); + setGain(GAIN_1X); + + /* Note: by default, the device is in power down mode on bootup */ + setMode(MODE_STANDBY); + } + + /** + * Close the driver and the underlying device. + */ + @Override + public void close() throws IOException { + if (mDevice != null) { + try { + mDevice.close(); + } finally { + mDevice = null; + } + } + } + + public byte getChipId() { + return mChipId; + } + + @PackageType + public int getPackageType() { + return mPackageType; + } + + public void setPackageType(@PackageType int packageType) { + mPackageType = packageType; + } + + public boolean isAutoGainEnabled() { + return mAutoGain; + } + + public void setAutoGain(boolean autoGain) { + mAutoGain = autoGain; + } + + public void setIntegrationTime(@IntegrationTime int integrationTime) throws IOException { + setMode(MODE_ACTIVE); + writeRegByte(COMMAND_BIT | REGISTER_TIMING, (byte) ((integrationTime | mGain) & 0xFF)); + setMode(MODE_STANDBY); + mIntegrationTime = integrationTime; + } + + public void setGain(@Gain int gain) throws IOException { + setMode(MODE_ACTIVE); + writeRegByte(COMMAND_BIT | REGISTER_TIMING, (byte) ((mIntegrationTime | gain) & 0xFF)); + setMode(MODE_STANDBY); + mGain = gain; + } + + public int[] getLuminosity() throws IOException { + setMode(MODE_ACTIVE); + // Wait x ms for ADC to complete + switch (mIntegrationTime) { + case INTEGRATIONTIME_13_7MS: + SystemClock.sleep(20); + break; + case INTEGRATIONTIME_101MS: + SystemClock.sleep(110); + break; + case INTEGRATIONTIME_402MS: + SystemClock.sleep(410); + break; + } + int[] luminosities; + if (isAutoGainEnabled()) { + boolean check = false; + boolean validRangeFound = false; + + do { + int ch0; + int tresholdHigh = 0; + int tresholdLow = 0; + @IntegrationTime + int integrationTime = mIntegrationTime; + + // Get the hi/low threshold for the current integration time + switch (integrationTime) { + case INTEGRATIONTIME_13_7MS: + tresholdHigh = AGC_THI_13MS; + tresholdLow = AGC_TLO_13MS; + break; + case INTEGRATIONTIME_101MS: + tresholdHigh = AGC_THI_101MS; + tresholdLow = AGC_TLO_101MS; + break; + case INTEGRATIONTIME_402MS: + tresholdHigh = AGC_THI_402MS; + tresholdLow = AGC_TLO_402MS; + break; + } + luminosities = getLuminosity(); + ch0 = luminosities[0]; + + // Run an auto-gain check if we haven't already done so... + if (!check) { + if ((ch0 < tresholdLow) && (mGain == GAIN_1X)) { + // Increase the gain and try again + setGain(GAIN_16X); + // Drop the previous conversion results + luminosities = getLuminosity(); + // Set a flag to indicate we've adjusted the gain + check = true; + } else if ((ch0 > tresholdHigh) && (mGain == GAIN_16X)) { + // Drop gain to 1x and try again + setGain(GAIN_1X); + // Drop the previous conversion results + luminosities = getLuminosity(); + // Set a flag to indicate we've adjusted the gain + check = true; + } else { + // Nothing to look at here, keep moving .... + // Reading is either valid, or we're already at the chips limits + validRangeFound = true; + } + } else { + // If we've already adjusted the gain once, just return the new results. + // This avoids endless loops where a value is at one extreme pre-gain, + // and the the other extreme post-gain + validRangeFound = true; + } + } while (!validRangeFound); + } else { + luminosities = readLuminosityData(); + } + setMode(MODE_STANDBY); + return luminosities; + } + + private int[] readLuminosityData() throws IOException { + int[] luminosities = new int[3]; + luminosities[0] = readRegWord(COMMAND_BIT | WORD_BIT | REGISTER_CHAN0_LOW) & 0xFFFF; + luminosities[1] = readRegWord(COMMAND_BIT | WORD_BIT | REGISTER_CHAN1_LOW) & 0xFFFF; + luminosities[2] = luminosities[0] - luminosities[1]; + return luminosities; + } + + public float getLuxF() throws IOException { + int[] luminosities = getLuminosity(); + // Convert from unsigned integer to floating point + float ch0 = luminosities[0]; + float ch1 = luminosities[1]; + + // We will need the ratio for subsequent calculations + float ratio = ch1 / ch0; + + float time = 0; + switch (mIntegrationTime) { + case INTEGRATIONTIME_13_7MS: + time = 13.7f; + break; + case INTEGRATIONTIME_101MS: + time = 101f; + break; + case INTEGRATIONTIME_402MS: + time = 402f; + break; + } + + // Normalize for integration time + ch0 *= (402.0 / time); + ch1 *= (402.0 / time); + + // Normalize for gain + if (mGain == GAIN_1X) { + ch0 *= 16; + ch1 *= 16; + } + + // Determine lux per datasheet equations + float lux = 0; + if (mPackageType == CS) { + if (ratio < 0.52) { + lux = 0.0315f * ch0 - 0.0593f * ch0 * (float) pow(ratio, 1.4); + } else if (ratio < 0.65) { + lux = 0.0229f * ch0 - 0.0291f * ch1; + } else if (ratio < 0.80) { + lux = 0.0157f * ch0 - 0.0180f * ch1; + } else if (ratio < 1.30) { + lux = 0.00338f * ch0 - 0.00260f * ch1; + } + } else { + if (ratio < 0.5) { + lux = 0.0304f * ch0 - 0.062f * ch0 * (float) pow(ratio, 1.4); + } else if (ratio < 0.61) { + lux = 0.0224f * ch0 - 0.031f * ch1; + } else if (ratio < 0.80) { + lux = 0.0128f * ch0 - 0.0153f * ch1; + } else if (ratio < 1.30) { + lux = 0.00146f * ch0 - 0.00112f * ch1; + } + } + return lux; + } + + public long getLux() throws IOException { + int[] luminosities = getLuminosity(); + int ch0 = luminosities[0]; + int ch1 = luminosities[1]; + long chScale = 0; + long channel1; + long channel0; + + switch (mIntegrationTime) { + case INTEGRATIONTIME_13_7MS: + chScale = LUX_CHSCALE_TINT0; + break; + case INTEGRATIONTIME_101MS: + chScale = LUX_CHSCALE_TINT1; + break; + case INTEGRATIONTIME_402MS: + chScale = (1 << LUX_CHSCALE); + break; + } + + // Scale for gain (1x or 16x) + if (mGain == GAIN_1X) { + chScale = chScale << 4; + } + + // scale the channel values + channel0 = (ch0 * chScale) >> LUX_CHSCALE; + channel1 = (ch1 * chScale) >> LUX_CHSCALE; + + // find the ratio of the channel values (Channel1/Channel0) + long ratio1 = 0; + if (channel0 != 0) { + ratio1 = (channel1 << (LUX_RATIOSCALE + 1)) / channel0; + } + + // round the ratio value + long ratio = (ratio1 + 1) >> 1; + + int b = 0; + int m = 0; + + if (mPackageType == CS) { + if ((ratio >= 0) && (ratio <= LUX_K1CS)) { + b = LUX_B1CS; + m = LUX_M1CS; + } else if (ratio <= LUX_K2CS) { + b = LUX_B2CS; + m = LUX_M2CS; + } else if (ratio <= LUX_K3CS) { + b = LUX_B3CS; + m = LUX_M3CS; + } else if (ratio <= LUX_K4CS) { + b = LUX_B4CS; + m = LUX_M4CS; + } else if (ratio <= LUX_K5CS) { + b = LUX_B5CS; + m = LUX_M5CS; + } else if (ratio <= LUX_K6CS) { + b = LUX_B6CS; + m = LUX_M6CS; + } else if (ratio <= LUX_K7CS) { + b = LUX_B7CS; + m = LUX_M7CS; + } else if (ratio > LUX_K8CS) { + b = LUX_B8CS; + m = LUX_M8CS; + } + } else { + if ((ratio >= 0) && (ratio <= LUX_K1T)) { + b = LUX_B1T; + m = LUX_M1T; + } else if (ratio <= LUX_K2T) { + b = LUX_B2T; + m = LUX_M2T; + } else if (ratio <= LUX_K3T) { + b = LUX_B3T; + m = LUX_M3T; + } else if (ratio <= LUX_K4T) { + b = LUX_B4T; + m = LUX_M4T; + } else if (ratio <= LUX_K5T) { + b = LUX_B5T; + m = LUX_M5T; + } else if (ratio <= LUX_K6T) { + b = LUX_B6T; + m = LUX_M6T; + } else if (ratio <= LUX_K7T) { + b = LUX_B7T; + m = LUX_M7T; + } else if (ratio > LUX_K8T) { + b = LUX_B8T; + m = LUX_M8T; + } + } + + long temp; + temp = ((channel0 * b) - (channel1 * m)); + + // do not allow negative lux value + if (temp < 0) { + temp = 0; + } + + // round lsb (2^(LUX_SCALE-1)) + temp += (1 << (LUX_LUXSCALE - 1)); + + // strip off fractional portion + return temp >> LUX_LUXSCALE; + } + + /** + * Set current power mode. + * + * @param mode + * @throws IOException + * @throws IllegalStateException + */ + public void setMode(@Mode int mode) throws IOException, IllegalStateException { + writeRegByte(COMMAND_BIT | REGISTER_CONTROL, (byte) mode); + } + + /** + * Get current power mode. + * + * @return + * @throws IOException + * @throws IllegalStateException + */ + // @SuppressWarnings("ResourceType") + // public @Mode + // int getMode() throws IOException, IllegalStateException { + // + // } + private byte readRegByte(int reg) throws IOException { + if (mDevice == null) { + throw new IllegalStateException("I2C Device not open"); + } + return mDevice.readRegByte(reg); + } + + private void writeRegByte(int reg, byte data) throws IOException { + if (mDevice == null) { + throw new IllegalStateException("I2C Device not open"); + } + mDevice.writeRegByte(reg, data); + } + + private short readRegWord(int reg) throws IOException { + if (mDevice == null) { + throw new IllegalStateException("I2C Device not open"); + } + return mDevice.readRegWord(reg); + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({INTEGRATIONTIME_13_7MS, + INTEGRATIONTIME_101MS, + INTEGRATIONTIME_402MS + }) + public @interface IntegrationTime { + int INTEGRATIONTIME_13_7MS = 0b0000_0000; // 13.7ms + int INTEGRATIONTIME_101MS = 0b0000_0001; // 101ms + int INTEGRATIONTIME_402MS = 0b0000_0010; // 402ms + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({GAIN_1X, GAIN_16X + }) + public @interface Gain { + int GAIN_1X = 0b0000_0000; // No gain + int GAIN_16X = 0b0001_0000; // 16x gain + } + + /** + * Power mode. + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef({MODE_STANDBY, MODE_ACTIVE}) + public @interface Mode { + int MODE_STANDBY = 0b00; // i2c on, output off, low power + int MODE_ACTIVE = 0b11; // i2c on, output on + } + + @Retention(RetentionPolicy.SOURCE) + @IntDef({CS, T_FN_CL}) + public @interface PackageType { + int CS = 0; + int T_FN_CL = 3; + } +} diff --git a/driver-tsl256x/src/main/java/com/leinardi/android/things/driver/tsl256x/Tsl256xSensorDriver.java b/driver-tsl256x/src/main/java/com/leinardi/android/things/driver/tsl256x/Tsl256xSensorDriver.java new file mode 100644 index 0000000..cf41384 --- /dev/null +++ b/driver-tsl256x/src/main/java/com/leinardi/android/things/driver/tsl256x/Tsl256xSensorDriver.java @@ -0,0 +1,158 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.driver.tsl256x; + +import com.google.android.things.userdriver.UserDriverManager; +import com.google.android.things.userdriver.UserSensor; +import com.google.android.things.userdriver.UserSensorDriver; +import com.google.android.things.userdriver.UserSensorReading; + +import java.io.IOException; + +public class Tsl256xSensorDriver implements AutoCloseable { + // DRIVER parameters + // documented at https://source.android.com/devices/sensors/hal-interface.html#sensor_t + // private static final String DRIVER_VENDOR = "STMicroelectronics"; + // private static final String DRIVER_NAME = "TSL2561"; + // private static final int DRIVER_XG_MIN_DELAY_US = Math.round(1000000.f / Tsl256x.MAX_FREQ_HZ_XG); + // private static final int DRIVER_XG_MAX_DELAY_US = Math.round(1000000.f / Tsl256x.MIN_FREQ_HZ_XG); + // private static final int DRIVER_MAG_MIN_DELAY_US = Math.round(1000000.f / Tsl256x.MAX_FREQ_HZ_M); + // private static final int DRIVER_MAG_MAX_DELAY_US = Math.round(1000000.f / Tsl256x.MIN_FREQ_HZ_M); + // + private Tsl256x mDevice; + + private LightUserDriver mLightUserDriver; + // + // /** + // * Create a new framework sensor driver connected on the given bus. + // * The driver emits {@link android.hardware.Sensor} with light, angular velocity, + // * magnetic induction and temperature data when registered. + // * + // * @param bus I2C bus the sensor is connected to. + // * @throws IOException + // */ + // public Tsl256xSensorDriver(String bus) throws IOException { + // this(bus, Tsl256x.I2C_ADDRESS_ACCEL_GYRO, Tsl256x.I2C_ADDRESS_MAG); + // } + // + // /** + // * Create a new framework sensor driver connected on the given bus and address. + // * The driver emits {@link android.hardware.Sensor} with light, angular velocity, + // * magnetic induction and temperature data when registered. + // * + // * @param bus I2C bus the sensor is connected to. + // * @param addressAccelGyro I2C address of the Accelerometer/Gyroscope sensor. + // * @param addressMag I2C address of the Magnetometer sensor. + // * @throws IOException + // */ + // public Tsl256xSensorDriver(String bus, int addressAccelGyro, int addressMag) throws IOException { + // mDevice = new Tsl256x.Builder(bus) + // .setI2cAddressAccelGyro(addressAccelGyro) + // .setI2cAddressMag(addressMag) + // .build(); + // } + + /** + * Close the driver and the underlying device. + * + * @throws IOException + */ + @Override + public void close() throws IOException { + unregisterAccelerometerSensor(); + if (mDevice != null) { + try { + mDevice.close(); + } finally { + mDevice = null; + } + } + } + + /** + * Register a {@link UserSensor} that pipes light readings into the Android SensorManager. + * + * @see #unregisterAccelerometerSensor() + */ + public void registerAccelerometerSensor() { + if (mDevice == null) { + throw new IllegalStateException("cannot register closed driver"); + } + + if (mLightUserDriver == null) { + mLightUserDriver = new LightUserDriver(); + UserDriverManager.getManager().registerSensor(mLightUserDriver.getUserSensor()); + } + } + + /** + * Unregister the light {@link UserSensor}. + */ + public void unregisterAccelerometerSensor() { + if (mLightUserDriver != null) { + UserDriverManager.getManager().unregisterSensor(mLightUserDriver.getUserSensor()); + mLightUserDriver = null; + } + } + + private class LightUserDriver extends UserSensorDriver { + // DRIVER parameters + // documented at https://source.android.com/devices/sensors/hal-interface.html#sensor_t + // private static final float DRIVER_MAX_RANGE = Tsl256x.MAX_ACCEL_RANGE_G_DEFAULT; + // private static final float DRIVER_POWER = Tsl256x.MAX_POWER_CONSUMPTION_X_UA / 1000.f; + // private static final int DRIVER_VERSION = 1; + // private static final String DRIVER_REQUIRED_PERMISSION = ""; + + private boolean mEnabled; + private UserSensor mUserSensor; + + private UserSensor getUserSensor() { + // if (mUserSensor == null) { + // mUserSensor = new UserSensor.Builder() + // .setType(Sensor.TYPE_ACCELEROMETER) + // .setName(DRIVER_NAME) + // .setVendor(DRIVER_VENDOR) + // .setVersion(DRIVER_VERSION) + // .setMaxRange(DRIVER_MAX_RANGE) + // .setResolution(mDevice.getLightSensitivity()) + // .setPower(DRIVER_POWER) + // .setMinDelay(DRIVER_XG_MIN_DELAY_US) + // .setMaxDelay(DRIVER_XG_MAX_DELAY_US) + // .setRequiredPermission(DRIVER_REQUIRED_PERMISSION) + // .setUuid(UUID.randomUUID()) + // .setDriver(this) + // .build(); + // } + return mUserSensor; + } + + @Override + public UserSensorReading read() throws IOException { + return null; //new UserSensorReading(mDevice.readLight()); + } + + @Override + public void setEnabled(boolean enabled) throws IOException { + mEnabled = enabled; + } + + private boolean isEnabled() { + return mEnabled; + } + } + +} diff --git a/sample-tsl256x/.gitignore b/sample-tsl256x/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/sample-tsl256x/.gitignore @@ -0,0 +1 @@ +/build diff --git a/sample-tsl256x/README.md b/sample-tsl256x/README.md new file mode 100644 index 0000000..34a70c8 --- /dev/null +++ b/sample-tsl256x/README.md @@ -0,0 +1,49 @@ +## Acceleration sensor sample for Android Things + +This sample demonstrates how to control the TSL256x acceleration sensor +and integrate it to the Android `SensorManager`. + + + +## Pre-requisites + +- Android Things compatible board +- Android Studio 3.0+ +- 1 [TSL2561 sensor](http://www.st.com/en/mems-and-sensors/tsl256x.html) +- jumper wires +- 1 breadboard + + +# Build and install + +On Android Studio, click on the "Run" button. + +If you prefer to run on the command line, from this repository's root directory, type + +```bash +./gradlew sample-tsl256x:installDebug +adb shell am start com.leinardi.android.things.sample.tsl256x/.AccelerationActivity +``` + +If you have everything set up correctly, in the logcat will be printed the values +from the accelerometer. + + +## License + +Copyright 2018 Roberto Leinardi. + +Licensed to the Apache Software Foundation (ASF) under one or more contributor +license agreements. See the NOTICE file distributed with this work for +additional information regarding copyright ownership. The ASF licenses this +file to you under the Apache License, Version 2.0 (the "License"); you may not +use this file except in compliance with the License. You may obtain a copy of +the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations under +the License. diff --git a/sample-tsl256x/build.gradle b/sample-tsl256x/build.gradle new file mode 100644 index 0000000..943b095 --- /dev/null +++ b/sample-tsl256x/build.gradle @@ -0,0 +1,54 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +apply plugin: 'com.android.application' +apply from: rootProject.file('checkstyle.gradle') + +android { + compileSdkVersion build_versions.target_sdk + buildToolsVersion build_versions.build_tools + + defaultConfig { + applicationId "com.leinardi.android.things.sample.tsl256x" + minSdkVersion build_versions.min_sdk + targetSdkVersion build_versions.target_sdk + versionCode build_versions.version_code + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + + } + + compileOptions { + sourceCompatibility build_versions.java_version + targetCompatibility build_versions.java_version + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + compileOnly deps.androidthings + implementation deps.support.annotations + implementation project(':driver-tsl256x') + +} diff --git a/sample-tsl256x/proguard-rules.pro b/sample-tsl256x/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/sample-tsl256x/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/sample-tsl256x/src/main/AndroidManifest.xml b/sample-tsl256x/src/main/AndroidManifest.xml new file mode 100644 index 0000000..69f9ef4 --- /dev/null +++ b/sample-tsl256x/src/main/AndroidManifest.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sample-tsl256x/src/main/java/com/leinardi/android/things/sample/tsl256x/BoardDefaults.java b/sample-tsl256x/src/main/java/com/leinardi/android/things/sample/tsl256x/BoardDefaults.java new file mode 100644 index 0000000..5960e81 --- /dev/null +++ b/sample-tsl256x/src/main/java/com/leinardi/android/things/sample/tsl256x/BoardDefaults.java @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.sample.tsl256x; + +import android.os.Build; + +@SuppressWarnings("WeakerAccess") +public class BoardDefaults { + private static final String DEVICE_RPI3 = "rpi3"; + private static final String DEVICE_IMX6UL_PICO = "imx6ul_pico"; + private static final String DEVICE_IMX7D_PICO = "imx7d_pico"; + + private BoardDefaults() { + } + + /** + * Return the preferred I2C port for each board. + */ + public static String getI2CPort() { + switch (Build.DEVICE) { + case DEVICE_RPI3: + return "I2C1"; + case DEVICE_IMX6UL_PICO: + return "I2C2"; + case DEVICE_IMX7D_PICO: + return "I2C1"; + default: + throw new IllegalStateException("Unknown Build.DEVICE " + Build.DEVICE); + } + } +} diff --git a/sample-tsl256x/src/main/java/com/leinardi/android/things/sample/tsl256x/LuxActivity.java b/sample-tsl256x/src/main/java/com/leinardi/android/things/sample/tsl256x/LuxActivity.java new file mode 100644 index 0000000..3b43c9b --- /dev/null +++ b/sample-tsl256x/src/main/java/com/leinardi/android/things/sample/tsl256x/LuxActivity.java @@ -0,0 +1,120 @@ +/* + * Copyright 2018 Roberto Leinardi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.leinardi.android.things.sample.tsl256x; + +import android.app.Activity; +import android.hardware.Sensor; +import android.hardware.SensorEvent; +import android.hardware.SensorEventListener; +import android.hardware.SensorManager; +import android.os.Bundle; +import android.util.Log; + +import com.leinardi.android.things.driver.tsl256x.Tsl256x; +import com.leinardi.android.things.driver.tsl256x.Tsl256xSensorDriver; + +import java.io.IOException; +import java.util.Locale; + +/** + * LuxActivity is an example that use the driver for the TSL256x sensors. + */ +public class LuxActivity extends Activity implements SensorEventListener { + private static final String TAG = LuxActivity.class.getSimpleName(); + + private Tsl256xSensorDriver mLightSensorDriver; + private SensorManager mSensorManager; + private Tsl256x mTsl256x; + + // private SensorManager.DynamicSensorCallback mDynamicSensorCallback = new SensorManager + // .DynamicSensorCallback() { + // @Override + // public void onDynamicSensorConnected(Sensor sensor) { + // if (sensor.getType() == Sensor.TYPE_LIGHT) { + // Log.i(TAG, "Light sensor connected"); + // mSensorManager.registerListener(LuxActivity.this, + // sensor, SensorManager.SENSOR_DELAY_NORMAL); + // } + // } + // }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + Log.i(TAG, "Starting LuxActivity"); + + try { + mTsl256x = new Tsl256x(BoardDefaults.getI2CPort(), 0x39); + mTsl256x.setGain(Tsl256x.Gain.GAIN_16X); + mTsl256x.setIntegrationTime(Tsl256x.IntegrationTime.INTEGRATIONTIME_402MS); + int[] luminosities = mTsl256x.getLuminosity(); + Log.d(TAG, "Broadband luminosity = " + luminosities[0]); + Log.d(TAG, "IR luminosity = " + luminosities[1]); + Log.d(TAG, "Visible luminosity = " + luminosities[2]); + long lux = mTsl256x.getLux(); + Log.d(TAG, "Lux = " + lux); + float luxF = mTsl256x.getLuxF(); + Log.d(TAG, "Lux = " + luxF); + } catch (IOException e) { + e.printStackTrace(); + } + + // mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); + // mSensorManager.registerDynamicSensorCallback(mDynamicSensorCallback); + // + // try { + // mLightSensorDriver = new Tsl256xSensorDriver(BoardDefaults.getI2CPort()); + // mLightSensorDriver.registerAccelerometerSensor(); + // } catch (IOException e) { + // Log.e(TAG, "Error configuring sensor", e); + // } + } + + @Override + protected void onDestroy() { + super.onDestroy(); + Log.i(TAG, "Closing sensor"); + try { + mTsl256x.close(); + } catch (IOException e) { + e.printStackTrace(); + } + // if (mLightSensorDriver != null) { + // mSensorManager.unregisterDynamicSensorCallback(mDynamicSensorCallback); + // mSensorManager.unregisterListener(this); + // mLightSensorDriver.unregisterAccelerometerSensor(); + // try { + // mLightSensorDriver.close(); + // } catch (IOException e) { + // Log.e(TAG, "Error closing sensor", e); + // } finally { + // mLightSensorDriver = null; + // } + // } + } + + @Override + public void onSensorChanged(SensorEvent event) { + Log.i(TAG, String.format(Locale.getDefault(), "sensor changed: [%f]", + event.values[0])); + } + + @Override + public void onAccuracyChanged(Sensor sensor, int accuracy) { + Log.i(TAG, "sensor accuracy changed: " + accuracy); + } +} diff --git a/sample-tsl256x/src/main/res/values/strings.xml b/sample-tsl256x/src/main/res/values/strings.xml new file mode 100644 index 0000000..f877881 --- /dev/null +++ b/sample-tsl256x/src/main/res/values/strings.xml @@ -0,0 +1,19 @@ + + + + Sample TSL256x + diff --git a/sample-tsl256x/src/main/res/values/styles.xml b/sample-tsl256x/src/main/res/values/styles.xml new file mode 100644 index 0000000..51e3dac --- /dev/null +++ b/sample-tsl256x/src/main/res/values/styles.xml @@ -0,0 +1,22 @@ + + + + + +