Skip to content

Commit 04bafa8

Browse files
authored
fix: fix data acquisition from TSL2561 luminosity sensor (#2790)
1 parent 9b7826a commit 04bafa8

File tree

2 files changed

+104
-85
lines changed

2 files changed

+104
-85
lines changed

app/src/main/java/io/pslab/activity/SensorActivity.java

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public class SensorActivity extends GuideActivity {
5656
private I2C i2c;
5757
private ScienceLab scienceLab;
5858
private final Map<Integer, List<String>> sensorAddr = new LinkedHashMap<>();
59-
private final List<String> dataAddress = new ArrayList<>();
59+
private final List<Integer> dataAddress = new ArrayList<>();
6060
private final List<String> dataName = new ArrayList<>();
6161
private ArrayAdapter<String> adapter;
6262
private ListView lvSensor;
@@ -83,15 +83,16 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
8383
i2c = scienceLab.i2c;
8484

8585
// Populate sensor addresses with multiple sensors mapped to the same address
86+
sensorAddr.put(0x29, List.of("TSL2561", "VL53L0X"));
87+
sensorAddr.put(0x39, List.of("TSL2561", "APDS9960"));
88+
sensorAddr.put(0x40, List.of("SHT21"));
8689
sensorAddr.put(0x48, List.of("ADS1115"));
87-
sensorAddr.put(0x77, List.of("BMP180"));
88-
sensorAddr.put(0x5A, List.of("MLX90614", "CCS811"));
89-
sensorAddr.put(0x1E, List.of("HMC5883L"));
90+
sensorAddr.put(0x49, List.of("TSL2561"));
9091
sensorAddr.put(0x68, List.of("MPU6050"));
91-
sensorAddr.put(0x40, List.of("SHT21"));
92-
sensorAddr.put(0x39, List.of("TSL2561", "APDS9960"));
9392
sensorAddr.put(0x69, List.of("MPU925x"));
94-
sensorAddr.put(0x29, List.of("VL53L0X"));
93+
sensorAddr.put(0x77, List.of("BMP180"));
94+
sensorAddr.put(0x1E, List.of("HMC5883L"));
95+
sensorAddr.put(0x5A, List.of("MLX90614", "CCS811"));
9596

9697
adapter = new ArrayAdapter<>(getApplication(), R.layout.sensor_list_item, R.id.tv_sensor_list_item, dataName);
9798

@@ -104,7 +105,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) {
104105
if (savedInstanceState != null) {
105106
String savedScanResults = savedInstanceState.getString(KEY_VALUE_SCAN);
106107
List<String> savedNames = savedInstanceState.getStringArrayList(KEY_ENTRIES_NAMES);
107-
List<String> savedAddresses = savedInstanceState.getStringArrayList(KEY_ENTRIES_ADDRESSES);
108+
List<Integer> savedAddresses = savedInstanceState.getIntegerArrayList(KEY_ENTRIES_ADDRESSES);
108109
if (savedScanResults != null) tvSensorScan.setText(savedScanResults);
109110
if (savedNames != null) dataName.addAll(savedNames);
110111
if (savedAddresses != null) dataAddress.addAll(savedAddresses);
@@ -176,7 +177,7 @@ protected void onSaveInstanceState(@NonNull Bundle outState) {
176177
super.onSaveInstanceState(outState);
177178
outState.putString(KEY_VALUE_SCAN, tvSensorScan.getText().toString());
178179
outState.putStringArrayList(KEY_ENTRIES_NAMES, new ArrayList<>(dataName));
179-
outState.putStringArrayList(KEY_ENTRIES_ADDRESSES, new ArrayList<>(dataAddress));
180+
outState.putIntegerArrayList(KEY_ENTRIES_ADDRESSES, new ArrayList<>(dataAddress));
180181
}
181182

182183
private class PopulateSensors extends AsyncTask<Void, Void, Void> {
@@ -210,22 +211,29 @@ protected void onPostExecute(Void aVoid) {
210211
if (detectedSensors != null && scienceLab.isConnected()) {
211212
for (Integer address : detectedSensors) {
212213
if (address != null && sensorAddr.containsKey(address)) {
213-
dataAddress.add(String.valueOf(address));
214+
dataAddress.add(address);
214215
dataName.addAll(sensorAddr.get(address));
215216
}
216217
}
217218

218219
// Build scan results for detected sensors
219-
for (final String address : dataAddress) {
220-
scanResults.append(address).append(": ").append(sensorAddr.get(Integer.parseInt(address))).append("\n");
220+
for (final Integer address : dataAddress) {
221+
scanResults
222+
.append("0x")
223+
.append(Integer.toHexString(address))
224+
.append(": ")
225+
.append(sensorAddr.get(address))
226+
.append("\n");
221227
}
222228
tvSensorScan.setText(scanResults);
223229
}
224230

225231
// Ensure the full list of sensors is displayed, even if not connected
226232
for (List<String> sensors : sensorAddr.values()) {
227-
if (!dataName.containsAll(sensors)) {
228-
dataName.addAll(sensors);
233+
for (String sensor : sensors) {
234+
if (!dataName.contains(sensor)) {
235+
dataName.add(sensor);
236+
}
229237
}
230238
}
231239

app/src/main/java/io/pslab/communication/sensors/TSL2561.java

Lines changed: 82 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -2,123 +2,134 @@
22

33
import android.util.Log;
44

5-
import io.pslab.communication.ScienceLab;
6-
import io.pslab.communication.peripherals.I2C;
7-
85
import java.io.IOException;
9-
import java.util.ArrayList;
10-
import java.util.Arrays;
6+
import java.util.List;
117
import java.util.concurrent.TimeUnit;
128

13-
/**
14-
* Created by akarshan on 4/15/17.
15-
*/
9+
import io.pslab.communication.ScienceLab;
10+
import io.pslab.communication.peripherals.I2C;
1611

12+
/*
13+
* See https://www.digikey.in/htmldatasheets/production/1640693/0/0/1/tsl2560-tsl2561-datasheet.html
14+
*/
1715
public class TSL2561 {
18-
private String TAG = "TSL2561";
19-
private int VISIBLE = 2; // channel 0 - channel 1
20-
private int INFRARED = 1; // channel 1
21-
private int FULLSPECTRUM = 0; // channel 0
16+
private static final String TAG = TSL2561.class.getSimpleName();
2217

23-
private int READBIT = 0x01;
24-
private int COMMAND_BIT = 0x80; // Must be 1
18+
/* See https://github.com/adafruit/TSL2561-Arduino-Library/blob/master/TSL2561.h for all constants. */
2519

26-
private int CONTROL_POWERON = 0x03;
27-
private int CONTROL_POWEROFF = 0x00;
20+
private static final byte COMMAND_BIT = (byte) 0x80; // Must be 1
21+
private static final byte WORD_BIT = (0x20); // 1 = read/write word (rather than byte)
2822

29-
private int REGISTER_CONTROL = 0x00;
30-
private int REGISTER_TIMING = 0x01;
31-
private int REGISTER_ID = 0x0A;
23+
private static final byte CONTROL_POWERON = 0x03;
24+
private static final byte CONTROL_POWEROFF = 0x00;
3225

33-
private int INTEGRATIONTIME_13MS = 0x00; // 13.7ms
34-
private int INTEGRATIONTIME_101MS = 0x01; // 101ms
35-
private int INTEGRATIONTIME_402MS = 0x02; // 402ms
26+
private static final byte REGISTER_CONTROL = 0x00;
27+
private static final byte REGISTER_TIMING = 0x01;
28+
private static final byte REGISTER_ID = 0x0A;
29+
private static final byte REGISTER_CHAN0_LOW = 0x0C;
30+
private static final byte REGISTER_CHAN1_LOW = 0x0E;
3631

37-
private int GAIN_1X = 0x00; // No gain
38-
private int GAIN_16X = 0x10; // 16x gain
39-
private int GAIN_OX;
32+
private static final byte INTEGRATIONTIME_13MS = 0x00; // 13.7ms
33+
private static final byte INTEGRATIONTIME_101MS = 0x01; // 101ms
34+
private static final byte INTEGRATIONTIME_402MS = 0x02; // 402ms
4035

41-
private int ADDRESS = 0x39; // addr normal
42-
private int timing = INTEGRATIONTIME_13MS;
43-
private int gain = GAIN_16X;
36+
private static final byte GAIN_0X = 0x00; // No gain
37+
private static final byte GAIN_16X = 0x10; // 16x gain
4438

45-
public String name = "TSL2561 Luminosity";
46-
public int NUMPLOTS = 3;
47-
public String[] PLOTNAMES = {"Full", "IR", "Visible"};
39+
/**
40+
* Normal address is 0x39, but it may also be configured to 0x29 or 0x49.
41+
* We use the normal address first before querying the alternatives.
42+
*/
43+
private static final byte[] ADDRESSES = new byte[]{0x39, 0x29, 0x49};
44+
private byte address;
45+
private byte timing = INTEGRATIONTIME_13MS;
46+
private byte gain = GAIN_16X;
4847

49-
private I2C i2c;
50-
private int full, infra;
51-
private ArrayList<Integer> infraList, fullList;
52-
private ArrayList<java.io.Serializable> setGain = new ArrayList<java.io.Serializable>(Arrays.asList("1x", "16x"));
53-
private ArrayList<java.io.Serializable> setTiming = new ArrayList<java.io.Serializable>(Arrays.asList(0, 1, 2));
48+
private final I2C i2c;
5449

5550
public TSL2561(I2C i2c, ScienceLab scienceLab) throws IOException, InterruptedException {
5651
this.i2c = i2c;
5752
// set timing 101ms & 16x gain
5853
if (scienceLab.isConnected()) {
54+
55+
/* Here we probe if any of the expected I2C addresses has an ID in the expected format.
56+
* If no sensor is available with the given ID, the value 0xFFFFFFFF will be returned.
57+
* If a different value is returned, we can check for the expected value (see data sheet
58+
* for details).
59+
*/
60+
for (byte addr : ADDRESSES) {
61+
address = addr;
62+
/* We disable the sensor before probing since it will not return the expected value
63+
* if it is still active due to a previous data capture.
64+
*/
65+
disable();
66+
Log.d(TAG, "Checking address 0x" + Integer.toHexString(address));
67+
int id = i2c.readByte(address, REGISTER_ID);
68+
if (id != 0xffffffff && (id & 0x0A) == 0x0A) {
69+
Log.d(TAG, "TSL2561 found!");
70+
break;
71+
} else {
72+
Log.d(TAG, "TSL2561 not found.");
73+
}
74+
}
75+
5976
enable();
6077
_wait();
61-
i2c.writeBulk(ADDRESS, new int[]{0x80 | 0x01, 0x01 | 0x10});
62-
//full scale luminosity
63-
infraList = i2c.readBulk(ADDRESS, 0x80 | 0x20 | 0x0E, 2);
64-
fullList = i2c.readBulk(ADDRESS, 0x80 | 0x20 | 0x0C, 2);
65-
full = (fullList.get(1) << 8) | fullList.get(0);
66-
infra = (infraList.get(1) << 8) | infraList.get(0);
67-
68-
Log.v(TAG, "Full - " + Integer.toString(full));
69-
Log.v(TAG, "Infrared - " + Integer.toString(infra));
70-
Log.v(TAG, "Visible -" + Integer.toString(full - infra));
78+
i2c.writeBulk(address, new int[]{COMMAND_BIT | REGISTER_TIMING, timing | gain});
7179
}
7280
}
7381

7482
public int getID() throws IOException {
75-
ArrayList<Integer> _ID_ = i2c.readBulk(ADDRESS, REGISTER_ID, 1);
83+
List<Integer> _ID_ = i2c.readBulk(address, REGISTER_ID, 1);
7684
int ID = Integer.parseInt(Character.getNumericValue(_ID_.get(0)) + "", 16);
77-
Log.d("ID", Integer.toString(ID));
85+
Log.d(TAG, "ID: " + ID);
7886
return ID;
7987
}
8088

8189
public int[] getRaw() throws IOException {
82-
fullList = i2c.readBulk(ADDRESS, 0x80 | 0x20 | 0x0E, 2);
83-
infraList = i2c.readBulk(ADDRESS, 0x80 | 0x20 | 0x0C, 2);
90+
List<Integer> infraList = i2c.readBulk(address, COMMAND_BIT | WORD_BIT | REGISTER_CHAN1_LOW, 2);
91+
List<Integer> fullList = i2c.readBulk(address, COMMAND_BIT | WORD_BIT | REGISTER_CHAN0_LOW, 2);
8492
if (!infraList.isEmpty()) {
85-
full = (fullList.get(0) << 8) | fullList.get(0);
86-
infra = (infraList.get(0) << 8) | infraList.get(0);
93+
int full = ((fullList.get(1) & 0xff) << 8) | fullList.get(0) & 0xff;
94+
int infra = ((infraList.get(1) & 0xff) << 8) | infraList.get(0) & 0xff;
8795
return (new int[]{full, infra, full - infra});
8896
} else
8997
return null;
9098
}
9199

92-
public void setGain(String _gain_) throws IOException {
93-
if (_gain_.equals("1x"))
94-
gain = GAIN_1X;
100+
public void setGain(String gain) throws IOException {
101+
if (gain.equals("1x"))
102+
this.gain = GAIN_0X;
95103

96-
else if (_gain_.equals("16x"))
97-
gain = GAIN_16X;
98-
else
99-
gain = GAIN_OX;
100-
i2c.writeBulk(ADDRESS, new int[]{COMMAND_BIT | REGISTER_TIMING, gain | timing});
101-
}
104+
else if (gain.equals("16x"))
105+
this.gain = GAIN_16X;
102106

103-
public void setTiming(int timing) throws IOException {
104-
Log.v(TAG, new int[]{13, 101, 404}[timing] + "mS");
105-
this.timing = timing;
106-
i2c.writeBulk(ADDRESS, new int[]{COMMAND_BIT | REGISTER_TIMING, gain | timing});
107+
i2c.writeBulk(address, new int[]{COMMAND_BIT | REGISTER_TIMING, this.gain | timing});
107108
}
108109

109110
private void enable() throws IOException {
110-
i2c.writeBulk(ADDRESS, new int[]{COMMAND_BIT | REGISTER_CONTROL, CONTROL_POWERON});
111+
i2c.writeBulk(address, new int[]{COMMAND_BIT | REGISTER_CONTROL, CONTROL_POWERON});
111112
}
112113

113114
public void disable() throws IOException {
114-
i2c.writeBulk(ADDRESS, new int[]{COMMAND_BIT | REGISTER_CONTROL, CONTROL_POWEROFF});
115+
i2c.writeBulk(address, new int[]{COMMAND_BIT | REGISTER_CONTROL, CONTROL_POWEROFF});
115116
}
116117

117118
private void _wait() throws InterruptedException {
118-
if (timing == INTEGRATIONTIME_13MS) TimeUnit.MILLISECONDS.sleep(14);
119-
if (timing == INTEGRATIONTIME_101MS) TimeUnit.MILLISECONDS.sleep(102);
120-
if (timing == INTEGRATIONTIME_402MS) TimeUnit.MILLISECONDS.sleep(403);
121-
119+
switch (timing) {
120+
case INTEGRATIONTIME_13MS: {
121+
TimeUnit.MILLISECONDS.sleep(14);
122+
break;
123+
}
124+
case INTEGRATIONTIME_101MS: {
125+
TimeUnit.MILLISECONDS.sleep(102);
126+
break;
127+
}
128+
case INTEGRATIONTIME_402MS:
129+
default: {
130+
TimeUnit.MILLISECONDS.sleep(403);
131+
}
132+
}
122133
}
123134

124135
}

0 commit comments

Comments
 (0)