Skip to content

Commit 0eb30d1

Browse files
Yugesh-Kumar-Ssourcery-ai[bot]marcnause
authored
feat: ported VL53L0X sensor screen. (#2827)
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com> Co-authored-by: Marc Nause <[email protected]>
1 parent 013c2d4 commit 0eb30d1

File tree

8 files changed

+783
-0
lines changed

8 files changed

+783
-0
lines changed

assets/images/vl53l0x.jpg

121 KB
Loading
Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
import 'package:pslab/communication/peripherals/i2c.dart';
2+
import 'package:pslab/communication/science_lab.dart';
3+
import 'package:pslab/others/logger_service.dart';
4+
5+
class VL53L0X {
6+
static const String tag = "VL53L0X";
7+
static const int address = 0x29;
8+
static const int sysrangeStart = 0x00;
9+
static const int systemSequenceConfig = 0x01;
10+
static const int systemInterruptConfigGpio = 0x0A;
11+
static const int gpioHvMuxActiveHigh = 0x84;
12+
static const int systemInterruptClear = 0x0B;
13+
static const int resultInterruptStatus = 0x13;
14+
static const int resultRangeStatus = 0x14;
15+
static const int msrcConfigControl = 0x60;
16+
static const int globalConfigSpadEnablesRef0 = 0xB0;
17+
static const int globalConfigRefEnStartSelect = 0xB6;
18+
static const int dynamicSpadNumRequestedRefSpad = 0x4E;
19+
static const int dynamicSpadRefEnStartOffset = 0x4F;
20+
static const int disableSignalRateMsrc = 0x2;
21+
static const int disableSignalRatePreRange = 0x10;
22+
static const int maybeTimerReg = 0x83;
23+
static const int ioTimeout = 10;
24+
static const List<List<int>> spadConfig = [
25+
[0xFF, 0x01],
26+
[dynamicSpadRefEnStartOffset, 0x00],
27+
[dynamicSpadNumRequestedRefSpad, 0x2C],
28+
[0xFF, 0x00],
29+
[globalConfigRefEnStartSelect, 0xB4]
30+
];
31+
static const List<List<int>> tuningConfig = [
32+
[0xFF, 0x01],
33+
[0x00, 0x00],
34+
[0xFF, 0x00],
35+
[0x09, 0x00],
36+
[0x10, 0x00],
37+
[0x11, 0x00],
38+
[0x24, 0x01],
39+
[0x25, 0xFF],
40+
[0x75, 0x00],
41+
[0xFF, 0x01],
42+
[0x4E, 0x2C],
43+
[0x48, 0x00],
44+
[0x30, 0x20],
45+
[0xFF, 0x00],
46+
[0x30, 0x09],
47+
[0x54, 0x00],
48+
[0x31, 0x04],
49+
[0x32, 0x03],
50+
[0x40, 0x83],
51+
[0x46, 0x25],
52+
[0x60, 0x00],
53+
[0x27, 0x00],
54+
[0x50, 0x06],
55+
[0x51, 0x00],
56+
[0x52, 0x96],
57+
[0x56, 0x08],
58+
[0x57, 0x30],
59+
[0x61, 0x00],
60+
[0x62, 0x00],
61+
[0x64, 0x00],
62+
[0x65, 0x00],
63+
[0x66, 0xA0],
64+
[0xFF, 0x01],
65+
[0x22, 0x32],
66+
[0x47, 0x14],
67+
[0x49, 0xFF],
68+
[0x4A, 0x00],
69+
[0xFF, 0x00],
70+
[0x7A, 0x0A],
71+
[0x7B, 0x00],
72+
[0x78, 0x21],
73+
[0xFF, 0x01],
74+
[0x23, 0x34],
75+
[0x42, 0x00],
76+
[0x44, 0xFF],
77+
[0x45, 0x26],
78+
[0x46, 0x05],
79+
[0x40, 0x40],
80+
[0x0E, 0x06],
81+
[0x20, 0x1A],
82+
[0x43, 0x40],
83+
[0xFF, 0x00],
84+
[0x34, 0x03],
85+
[0x35, 0x44],
86+
[0xFF, 0x01],
87+
[0x31, 0x04],
88+
[0x4B, 0x09],
89+
[0x4C, 0x05],
90+
[0x4D, 0x04],
91+
[0xFF, 0x00],
92+
[0x44, 0x00],
93+
[0x45, 0x20],
94+
[0x47, 0x08],
95+
[0x48, 0x28],
96+
[0x67, 0x00],
97+
[0x70, 0x04],
98+
[0x71, 0x01],
99+
[0x72, 0xFE],
100+
[0x76, 0x00],
101+
[0x77, 0x00],
102+
[0xFF, 0x01],
103+
[0x0D, 0x01],
104+
[0xFF, 0x00],
105+
[0x80, 0x01],
106+
[0x01, 0xF8],
107+
[0xFF, 0x01],
108+
[0x8E, 0x01],
109+
[0x00, 0x01],
110+
[0xFF, 0x00],
111+
[0x80, 0x00]
112+
];
113+
static const List<List<int>> spad1 = [
114+
[0x80, 0x01],
115+
[0xFF, 0x01],
116+
[0x00, 0x00],
117+
[0xFF, 0x06]
118+
];
119+
static const List<List<int>> spad2 = [
120+
[0xFF, 0x07],
121+
[0x81, 0x01],
122+
[0x80, 0x01],
123+
[0x94, 0x6B],
124+
[maybeTimerReg, 0x00]
125+
];
126+
static const List<List<int>> spad3 = [
127+
[0x81, 0x00],
128+
[0xFF, 0x06]
129+
];
130+
static const List<List<int>> spad4 = [
131+
[0xFF, 0x01],
132+
[0x00, 0x01],
133+
[0xFF, 0x00],
134+
[0x80, 0x00]
135+
];
136+
final I2C i2c;
137+
late int stopByte;
138+
VL53L0X._(this.i2c);
139+
static Future<VL53L0X> create(I2C i2c, ScienceLab scienceLab) async {
140+
final vl53l0x = VL53L0X._(i2c);
141+
await vl53l0x._initialize(scienceLab);
142+
return vl53l0x;
143+
}
144+
145+
Future<void> _initialize(ScienceLab scienceLab) async {
146+
if (!scienceLab.isConnected()) {
147+
throw Exception("ScienceLab not connected");
148+
}
149+
try {
150+
List<List<int>> initSequence = [
151+
[0x88, 0x00],
152+
[0x80, 0x01],
153+
[0xFF, 0x01],
154+
[0x00, 0x00]
155+
];
156+
for (List<int> regValPair in initSequence) {
157+
await i2c.write(address, [regValPair[1]], regValPair[0]);
158+
}
159+
stopByte = await i2c.readByte(address, 0x91);
160+
List<List<int>> postReadSequence = [
161+
[0x00, 0x01],
162+
[0xFF, 0x00],
163+
[0x80, 0x00]
164+
];
165+
for (List<int> regValPair in postReadSequence) {
166+
await i2c.write(address, [regValPair[1]], regValPair[0]);
167+
}
168+
int configControl = await i2c.readByte(address, msrcConfigControl) |
169+
(disableSignalRateMsrc | disableSignalRatePreRange);
170+
await i2c.write(address, [configControl], msrcConfigControl);
171+
await i2c.write(address, [0xFF], systemSequenceConfig);
172+
await _spadConfig();
173+
for (List<int> regValPair in tuningConfig) {
174+
await i2c.write(address, [regValPair[1]], regValPair[0]);
175+
}
176+
await i2c.write(address, [0x04], systemInterruptConfigGpio);
177+
int gpioHvMux = await i2c.readByte(address, gpioHvMuxActiveHigh);
178+
await i2c.write(address, [gpioHvMux & ~0x10], gpioHvMuxActiveHigh);
179+
await i2c.write(address, [0x01], systemInterruptClear);
180+
await i2c.write(address, [0xE8], systemSequenceConfig);
181+
await i2c.write(address, [0x01], systemSequenceConfig);
182+
await _performSingleRefCalibration(0x40);
183+
await i2c.write(address, [0x01], systemSequenceConfig);
184+
await i2c.write(address, [0x02], systemSequenceConfig);
185+
await _performSingleRefCalibration(0x00);
186+
await i2c.write(address, [0xE8], systemSequenceConfig);
187+
logger.d("VL53L0X initialized successfully");
188+
} catch (e) {
189+
logger.e("Error initializing VL53L0X: $e");
190+
rethrow;
191+
}
192+
}
193+
194+
Future<List<int>> _getSpadInfo() async {
195+
for (List<int> regValPair in spad1) {
196+
await i2c.write(address, [regValPair[1]], regValPair[0]);
197+
}
198+
int uu = await i2c.readByte(address, maybeTimerReg) | 0x04;
199+
await i2c.write(address, [uu], maybeTimerReg);
200+
for (List<int> regValPair in spad2) {
201+
await i2c.write(address, [regValPair[1]], regValPair[0]);
202+
}
203+
int start = DateTime.now().millisecondsSinceEpoch;
204+
while (await i2c.readByte(address, maybeTimerReg) == 0x00) {
205+
if (ioTimeout > 0 &&
206+
(DateTime.now().millisecondsSinceEpoch - start) / 1000.0 >=
207+
ioTimeout) {
208+
logger.e("Timeout waiting for VL53L0X!");
209+
break;
210+
}
211+
}
212+
await i2c.write(address, [0x01], maybeTimerReg);
213+
int tmp = await i2c.readByte(address, 0x92);
214+
int count = tmp & 0x7F;
215+
bool isAperture = ((tmp >> 7) & 0x01) == 1;
216+
for (List<int> regValPair in spad3) {
217+
await i2c.write(address, [regValPair[1]], regValPair[0]);
218+
}
219+
int vv = await i2c.readByte(address, maybeTimerReg) & ~0x04;
220+
await i2c.write(address, [vv], maybeTimerReg);
221+
for (List<int> regValPair in spad4) {
222+
await i2c.write(address, [regValPair[1]], regValPair[0]);
223+
}
224+
return [count, isAperture ? 1 : 0];
225+
}
226+
227+
Future<void> _spadConfig() async {
228+
List<int> spadInfo = await _getSpadInfo();
229+
int spadCount = spadInfo[0];
230+
int spadIsAperture = spadInfo[1];
231+
await i2c.write(address, [0], globalConfigSpadEnablesRef0);
232+
List<int> spadMap =
233+
await i2c.readBulk(address, globalConfigSpadEnablesRef0, 6);
234+
for (List<int> regValPair in spadConfig) {
235+
await i2c.write(address, [regValPair[1]], regValPair[0]);
236+
}
237+
int firstSpadToEnable = (spadIsAperture == 1) ? 12 : 0;
238+
int spadsEnabled = 0;
239+
for (int i = 0; i < 48; i++) {
240+
int index = i ~/ 8;
241+
if (i < firstSpadToEnable || spadsEnabled == spadCount) {
242+
spadMap[index] = spadMap[index] & ~(1 << (i % 8));
243+
} else if (((spadMap[index] >> (i % 8)) & 0x1) > 0) {
244+
spadsEnabled++;
245+
}
246+
}
247+
await i2c.writeBulk(address, spadMap);
248+
}
249+
250+
Future<void> _performSingleRefCalibration(int vhvInitByte) async {
251+
await i2c.write(address, [0x01 | vhvInitByte & 0xFF], sysrangeStart);
252+
int start = DateTime.now().millisecondsSinceEpoch;
253+
while ((await i2c.readByte(address, resultInterruptStatus) & 0x07) == 0) {
254+
if (ioTimeout > 0 &&
255+
(DateTime.now().millisecondsSinceEpoch - start) / 1000.0 >=
256+
ioTimeout) {
257+
logger.e("Timeout waiting for VL53L0X!");
258+
break;
259+
}
260+
}
261+
await i2c.write(address, [0x01], systemInterruptClear);
262+
await i2c.write(address, [0x00], sysrangeStart);
263+
}
264+
265+
Future<int> getRaw() async {
266+
try {
267+
List<List<int>> startSequence = [
268+
[0x80, 0x01],
269+
[0xFF, 0x01],
270+
[0x00, 0x00],
271+
[0x91, stopByte],
272+
[0x00, 0x01],
273+
[0xFF, 0x00],
274+
[0x80, 0x00],
275+
[sysrangeStart, 0x01]
276+
];
277+
for (List<int> regValPair in startSequence) {
278+
await i2c.write(address, [regValPair[1]], regValPair[0]);
279+
}
280+
int start = DateTime.now().millisecondsSinceEpoch;
281+
while ((await i2c.readByte(address, sysrangeStart) & 0x01) > 0) {
282+
if (ioTimeout > 0 &&
283+
(DateTime.now().millisecondsSinceEpoch - start) / 1000.0 >=
284+
ioTimeout) {
285+
logger.e("Timeout waiting for VL53L0X!");
286+
break;
287+
}
288+
}
289+
start = DateTime.now().millisecondsSinceEpoch;
290+
while ((await i2c.readByte(address, resultInterruptStatus) & 0x07) == 0) {
291+
if (ioTimeout > 0 &&
292+
(DateTime.now().millisecondsSinceEpoch - start) / 1000.0 >=
293+
ioTimeout) {
294+
logger.e("Timeout waiting for VL53L0X!");
295+
break;
296+
}
297+
}
298+
List<int> data = await i2c.readBulk(address, resultRangeStatus + 10, 2);
299+
await i2c.write(address, [0x01], systemInterruptClear);
300+
return ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
301+
} catch (e) {
302+
logger.e("Error reading VL53L0X raw data: $e");
303+
rethrow;
304+
}
305+
}
306+
307+
Future<double> getDistance() async {
308+
int rawValue = await getRaw();
309+
return rawValue.toDouble();
310+
}
311+
}

lib/l10n/app_en.arb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,8 @@
481481
"time" : "Time",
482482
"notAvailable" : "N/A",
483483
"estimated" : "Estimated",
484+
"distance" : "Distance",
485+
"distanceUnitLabel" : "mm"
484486
"legacyFirmwareAlertTitle": "Legacy Firmware Detected",
485487
"legacyFirmwareAlertMessage": "We have detected that your PSLab device is running legacy firmware. Please note that support for this firmware has ended. For the best experience and continued support, please update your device to the latest firmware version."
486488
}

lib/l10n/app_localizations.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2790,6 +2790,18 @@ abstract class AppLocalizations {
27902790
/// **'Estimated'**
27912791
String get estimated;
27922792

2793+
/// No description provided for @distance.
2794+
///
2795+
/// In en, this message translates to:
2796+
/// **'Distance'**
2797+
String get distance;
2798+
2799+
/// No description provided for @distanceUnitLabel.
2800+
///
2801+
/// In en, this message translates to:
2802+
/// **'mm'**
2803+
String get distanceUnitLabel;
2804+
27932805
/// No description provided for @legacyFirmwareAlertTitle.
27942806
///
27952807
/// In en, this message translates to:

lib/l10n/app_localizations_en.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,6 +1445,12 @@ class AppLocalizationsEn extends AppLocalizations {
14451445
@override
14461446
String get estimated => 'Estimated';
14471447

1448+
@override
1449+
String get distance => 'Distance';
1450+
1451+
@override
1452+
String get distanceUnitLabel => 'mm';
1453+
14481454
@override
14491455
String get legacyFirmwareAlertTitle => 'Legacy Firmware Detected';
14501456

0 commit comments

Comments
 (0)