1 /*******************************************************************************
2  Copyright � 2016, STMicroelectronics International N.V.
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of STMicroelectronics nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
19  NON-INFRINGEMENT OF INTELLECTUAL PROPERTY RIGHTS ARE DISCLAIMED.
20  IN NO EVENT SHALL STMICROELECTRONICS INTERNATIONAL N.V. BE LIABLE FOR ANY
21  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  ******************************************************************************/
28 
29 #include "vl53l0x_api.h"
30 #include "vl53l0x_api_core.h"
31 #include "vl53l0x_api_calibration.h"
32 
33 
34 #ifndef __KERNEL__
35 #include <stdlib.h>
36 #endif
37 #define LOG_FUNCTION_START(fmt, ...) \
38 	_LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
39 #define LOG_FUNCTION_END(status, ...) \
40 	_LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
41 #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
42 	_LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
43 
VL53L0X_reverse_bytes(uint8_t * data,uint32_t size)44 VL53L0X_Error VL53L0X_reverse_bytes(uint8_t *data, uint32_t size)
45 {
46 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
47 	uint8_t tempData;
48 	uint32_t mirrorIndex;
49 	uint32_t middle = size/2;
50 	uint32_t index;
51 
52 	for (index = 0; index < middle; index++) {
53 		mirrorIndex		 = size - index - 1;
54 		tempData		 = data[index];
55 		data[index]		 = data[mirrorIndex];
56 		data[mirrorIndex] = tempData;
57 	}
58 	return Status;
59 }
60 
VL53L0X_measurement_poll_for_completion(VL53L0X_DEV Dev)61 VL53L0X_Error VL53L0X_measurement_poll_for_completion(VL53L0X_DEV Dev)
62 {
63 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
64 	uint8_t NewDataReady = 0;
65 	uint32_t LoopNb;
66 
67 	LOG_FUNCTION_START("");
68 
69 	LoopNb = 0;
70 
71 	do {
72 		Status = VL53L0X_GetMeasurementDataReady(Dev, &NewDataReady);
73 		if (Status != 0)
74 			break; /* the error is set */
75 
76 		if (NewDataReady == 1)
77 			break; /* done note that status == 0 */
78 
79 		LoopNb++;
80 		if (LoopNb >= VL53L0X_DEFAULT_MAX_LOOP) {
81 			Status = VL53L0X_ERROR_TIME_OUT;
82 			break;
83 		}
84 
85 		VL53L0X_PollingDelay(Dev);
86 	} while (1);
87 
88 	LOG_FUNCTION_END(Status);
89 
90 	return Status;
91 }
92 
93 
VL53L0X_decode_vcsel_period(uint8_t vcsel_period_reg)94 uint8_t VL53L0X_decode_vcsel_period(uint8_t vcsel_period_reg)
95 {
96 	/*!
97 	 * Converts the encoded VCSEL period register value into the real
98 	 * period in PLL clocks
99 	 */
100 
101 	uint8_t vcsel_period_pclks = 0;
102 
103 	vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
104 
105 	return vcsel_period_pclks;
106 }
107 
VL53L0X_encode_vcsel_period(uint8_t vcsel_period_pclks)108 uint8_t VL53L0X_encode_vcsel_period(uint8_t vcsel_period_pclks)
109 {
110 	/*!
111 	 * Converts the encoded VCSEL period register value into the real period
112 	 * in PLL clocks
113 	 */
114 
115 	uint8_t vcsel_period_reg = 0;
116 
117 	vcsel_period_reg = (vcsel_period_pclks >> 1) - 1;
118 
119 	return vcsel_period_reg;
120 }
121 
122 
VL53L0X_isqrt(uint32_t num)123 uint32_t VL53L0X_isqrt(uint32_t num)
124 {
125 	/*
126 	 * Implements an integer square root
127 	 *
128 	 * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
129 	 */
130 
131 	uint32_t  res = 0;
132 	uint32_t  bit = 1 << 30;
133 	/* The second-to-top bit is set:
134 	 *	1 << 14 for 16-bits, 1 << 30 for 32 bits */
135 
136 	 /* "bit" starts at the highest power of four <= the argument. */
137 	while (bit > num)
138 		bit >>= 2;
139 
140 
141 	while (bit != 0) {
142 		if (num >= res + bit) {
143 			num -= res + bit;
144 			res = (res >> 1) + bit;
145 		} else
146 			res >>= 1;
147 
148 		bit >>= 2;
149 	}
150 
151 	return res;
152 }
153 
154 
VL53L0X_quadrature_sum(uint32_t a,uint32_t b)155 uint32_t VL53L0X_quadrature_sum(uint32_t a, uint32_t b)
156 {
157 	/*
158 	 * Implements a quadrature sum
159 	 *
160 	 * rea = sqrt(a^2 + b^2)
161 	 *
162 	 * Trap overflow case max input value is 65535 (16-bit value)
163 	 * as internal calc are 32-bit wide
164 	 *
165 	 * If overflow then seta output to maximum
166 	 */
167 	uint32_t  res = 0;
168 
169 	if (a > 65535 || b > 65535)
170 		res = 65535;
171 	else
172 		res = VL53L0X_isqrt(a * a + b * b);
173 
174 	return res;
175 }
176 
177 
VL53L0X_device_read_strobe(VL53L0X_DEV Dev)178 VL53L0X_Error VL53L0X_device_read_strobe(VL53L0X_DEV Dev)
179 {
180 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
181 	uint8_t strobe;
182 	uint32_t LoopNb;
183 	LOG_FUNCTION_START("");
184 
185 	Status |= VL53L0X_WrByte(Dev, 0x83, 0x00);
186 
187 	/* polling
188 	 * use timeout to avoid deadlock*/
189 	if (Status == VL53L0X_ERROR_NONE) {
190 		LoopNb = 0;
191 		do {
192 			Status = VL53L0X_RdByte(Dev, 0x83, &strobe);
193 			if ((strobe != 0x00) || Status != VL53L0X_ERROR_NONE)
194 					break;
195 
196 			LoopNb = LoopNb + 1;
197 		} while (LoopNb < VL53L0X_DEFAULT_MAX_LOOP);
198 
199 		if (LoopNb >= VL53L0X_DEFAULT_MAX_LOOP)
200 			Status = VL53L0X_ERROR_TIME_OUT;
201 
202 	}
203 
204 	Status |= VL53L0X_WrByte(Dev, 0x83, 0x01);
205 
206 	LOG_FUNCTION_END(Status);
207 	return Status;
208 
209 }
210 
VL53L0X_get_info_from_device(VL53L0X_DEV Dev,uint8_t option)211 VL53L0X_Error VL53L0X_get_info_from_device(VL53L0X_DEV Dev, uint8_t option)
212 {
213 
214 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
215 	uint8_t byte;
216 	uint32_t TmpDWord;
217 	uint8_t ModuleId;
218 	uint8_t Revision;
219 	uint8_t ReferenceSpadCount = 0;
220 	uint8_t ReferenceSpadType = 0;
221 	uint32_t PartUIDUpper = 0;
222 	uint32_t PartUIDLower = 0;
223 	uint32_t OffsetFixed1104_mm = 0;
224 	int16_t OffsetMicroMeters = 0;
225 	uint32_t DistMeasTgtFixed1104_mm = 400 << 4;
226 	uint32_t DistMeasFixed1104_400_mm = 0;
227 	uint32_t SignalRateMeasFixed1104_400_mm = 0;
228 	char ProductId[19];
229 	char *ProductId_tmp;
230 	uint8_t ReadDataFromDeviceDone;
231 	FixPoint1616_t SignalRateMeasFixed400mmFix = 0;
232 	uint8_t NvmRefGoodSpadMap[VL53L0X_REF_SPAD_BUFFER_SIZE];
233 	int i;
234 
235 
236 	LOG_FUNCTION_START("");
237 
238 	ReadDataFromDeviceDone = VL53L0X_GETDEVICESPECIFICPARAMETER(Dev,
239 			ReadDataFromDeviceDone);
240 
241 	/* This access is done only once after that a GetDeviceInfo or
242 	 * datainit is done*/
243 	if (ReadDataFromDeviceDone != 7) {
244 
245 		Status |= VL53L0X_WrByte(Dev, 0x80, 0x01);
246 		Status |= VL53L0X_WrByte(Dev, 0xFF, 0x01);
247 		Status |= VL53L0X_WrByte(Dev, 0x00, 0x00);
248 
249 		Status |= VL53L0X_WrByte(Dev, 0xFF, 0x06);
250 		Status |= VL53L0X_RdByte(Dev, 0x83, &byte);
251 		Status |= VL53L0X_WrByte(Dev, 0x83, byte|4);
252 		Status |= VL53L0X_WrByte(Dev, 0xFF, 0x07);
253 		Status |= VL53L0X_WrByte(Dev, 0x81, 0x01);
254 
255 		Status |= VL53L0X_PollingDelay(Dev);
256 
257 		Status |= VL53L0X_WrByte(Dev, 0x80, 0x01);
258 
259 		if (((option & 1) == 1) &&
260 			((ReadDataFromDeviceDone & 1) == 0)) {
261 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x6b);
262 			Status |= VL53L0X_device_read_strobe(Dev);
263 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
264 
265 			ReferenceSpadCount = (uint8_t)((TmpDWord >> 8) & 0x07f);
266 			ReferenceSpadType  = (uint8_t)((TmpDWord >> 15) & 0x01);
267 
268 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x24);
269 			Status |= VL53L0X_device_read_strobe(Dev);
270 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
271 
272 
273 			NvmRefGoodSpadMap[0] = (uint8_t)((TmpDWord >> 24)
274 				& 0xff);
275 			NvmRefGoodSpadMap[1] = (uint8_t)((TmpDWord >> 16)
276 				& 0xff);
277 			NvmRefGoodSpadMap[2] = (uint8_t)((TmpDWord >> 8)
278 				& 0xff);
279 			NvmRefGoodSpadMap[3] = (uint8_t)(TmpDWord & 0xff);
280 
281 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x25);
282 			Status |= VL53L0X_device_read_strobe(Dev);
283 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
284 
285 			NvmRefGoodSpadMap[4] = (uint8_t)((TmpDWord >> 24)
286 				& 0xff);
287 			NvmRefGoodSpadMap[5] = (uint8_t)((TmpDWord >> 16)
288 				& 0xff);
289 		}
290 
291 		if (((option & 2) == 2) &&
292 			((ReadDataFromDeviceDone & 2) == 0)) {
293 
294 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x02);
295 			Status |= VL53L0X_device_read_strobe(Dev);
296 			Status |= VL53L0X_RdByte(Dev, 0x90, &ModuleId);
297 
298 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x7B);
299 			Status |= VL53L0X_device_read_strobe(Dev);
300 			Status |= VL53L0X_RdByte(Dev, 0x90, &Revision);
301 
302 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x77);
303 			Status |= VL53L0X_device_read_strobe(Dev);
304 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
305 
306 			ProductId[0] = (char)((TmpDWord >> 25) & 0x07f);
307 			ProductId[1] = (char)((TmpDWord >> 18) & 0x07f);
308 			ProductId[2] = (char)((TmpDWord >> 11) & 0x07f);
309 			ProductId[3] = (char)((TmpDWord >> 4) & 0x07f);
310 
311 			byte = (uint8_t)((TmpDWord & 0x00f) << 3);
312 
313 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x78);
314 			Status |= VL53L0X_device_read_strobe(Dev);
315 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
316 
317 			ProductId[4] = (char)(byte +
318 					((TmpDWord >> 29) & 0x07f));
319 			ProductId[5] = (char)((TmpDWord >> 22) & 0x07f);
320 			ProductId[6] = (char)((TmpDWord >> 15) & 0x07f);
321 			ProductId[7] = (char)((TmpDWord >> 8) & 0x07f);
322 			ProductId[8] = (char)((TmpDWord >> 1) & 0x07f);
323 
324 			byte = (uint8_t)((TmpDWord & 0x001) << 6);
325 
326 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x79);
327 
328 			Status |= VL53L0X_device_read_strobe(Dev);
329 
330 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
331 
332 			ProductId[9] = (char)(byte +
333 					((TmpDWord >> 26) & 0x07f));
334 			ProductId[10] = (char)((TmpDWord >> 19) & 0x07f);
335 			ProductId[11] = (char)((TmpDWord >> 12) & 0x07f);
336 			ProductId[12] = (char)((TmpDWord >> 5) & 0x07f);
337 
338 			byte = (uint8_t)((TmpDWord & 0x01f) << 2);
339 
340 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x7A);
341 
342 			Status |= VL53L0X_device_read_strobe(Dev);
343 
344 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
345 
346 			ProductId[13] = (char)(byte +
347 					((TmpDWord >> 30) & 0x07f));
348 			ProductId[14] = (char)((TmpDWord >> 23) & 0x07f);
349 			ProductId[15] = (char)((TmpDWord >> 16) & 0x07f);
350 			ProductId[16] = (char)((TmpDWord >> 9) & 0x07f);
351 			ProductId[17] = (char)((TmpDWord >> 2) & 0x07f);
352 			ProductId[18] = '\0';
353 
354 		}
355 
356 		if (((option & 4) == 4) &&
357 			((ReadDataFromDeviceDone & 4) == 0)) {
358 
359 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x7B);
360 			Status |= VL53L0X_device_read_strobe(Dev);
361 			Status |= VL53L0X_RdDWord(Dev, 0x90, &PartUIDUpper);
362 
363 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x7C);
364 			Status |= VL53L0X_device_read_strobe(Dev);
365 			Status |= VL53L0X_RdDWord(Dev, 0x90, &PartUIDLower);
366 
367 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x73);
368 			Status |= VL53L0X_device_read_strobe(Dev);
369 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
370 
371 			SignalRateMeasFixed1104_400_mm = (TmpDWord &
372 				0x0000000ff) << 8;
373 
374 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x74);
375 			Status |= VL53L0X_device_read_strobe(Dev);
376 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
377 
378 			SignalRateMeasFixed1104_400_mm |= ((TmpDWord &
379 				0xff000000) >> 24);
380 
381 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x75);
382 			Status |= VL53L0X_device_read_strobe(Dev);
383 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
384 
385 			DistMeasFixed1104_400_mm = (TmpDWord & 0x0000000ff)
386 							<< 8;
387 
388 			Status |= VL53L0X_WrByte(Dev, 0x94, 0x76);
389 			Status |= VL53L0X_device_read_strobe(Dev);
390 			Status |= VL53L0X_RdDWord(Dev, 0x90, &TmpDWord);
391 
392 			DistMeasFixed1104_400_mm |= ((TmpDWord & 0xff000000)
393 							>> 24);
394 		}
395 
396 		Status |= VL53L0X_WrByte(Dev, 0x81, 0x00);
397 		Status |= VL53L0X_WrByte(Dev, 0xFF, 0x06);
398 		Status |= VL53L0X_RdByte(Dev, 0x83, &byte);
399 		Status |= VL53L0X_WrByte(Dev, 0x83, byte&0xfb);
400 		Status |= VL53L0X_WrByte(Dev, 0xFF, 0x01);
401 		Status |= VL53L0X_WrByte(Dev, 0x00, 0x01);
402 
403 		Status |= VL53L0X_WrByte(Dev, 0xFF, 0x00);
404 		Status |= VL53L0X_WrByte(Dev, 0x80, 0x00);
405 	}
406 
407 	if ((Status == VL53L0X_ERROR_NONE) &&
408 		(ReadDataFromDeviceDone != 7)) {
409 		/* Assign to variable if status is ok */
410 		if (((option & 1) == 1) &&
411 			((ReadDataFromDeviceDone & 1) == 0)) {
412 			VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
413 				ReferenceSpadCount, ReferenceSpadCount);
414 
415 			VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
416 				ReferenceSpadType, ReferenceSpadType);
417 
418 			for (i = 0; i < VL53L0X_REF_SPAD_BUFFER_SIZE; i++) {
419 				Dev->Data.SpadData.RefGoodSpadMap[i] =
420 					NvmRefGoodSpadMap[i];
421 			}
422 		}
423 
424 		if (((option & 2) == 2) &&
425 			((ReadDataFromDeviceDone & 2) == 0)) {
426 			VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
427 					ModuleId, ModuleId);
428 
429 			VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
430 					Revision, Revision);
431 
432 			ProductId_tmp = VL53L0X_GETDEVICESPECIFICPARAMETER(Dev,
433 					ProductId);
434 			VL53L0X_COPYSTRING(ProductId_tmp, ProductId);
435 
436 		}
437 
438 		if (((option & 4) == 4) &&
439 			((ReadDataFromDeviceDone & 4) == 0)) {
440 			VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
441 						PartUIDUpper, PartUIDUpper);
442 
443 			VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
444 						PartUIDLower, PartUIDLower);
445 
446 			SignalRateMeasFixed400mmFix =
447 				VL53L0X_FIXPOINT97TOFIXPOINT1616(
448 					SignalRateMeasFixed1104_400_mm);
449 
450 			VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
451 				SignalRateMeasFixed400mm,
452 				SignalRateMeasFixed400mmFix);
453 
454 			OffsetMicroMeters = 0;
455 			if (DistMeasFixed1104_400_mm != 0) {
456 					OffsetFixed1104_mm =
457 						DistMeasFixed1104_400_mm -
458 						DistMeasTgtFixed1104_mm;
459 					OffsetMicroMeters = (OffsetFixed1104_mm
460 						* 1000) >> 4;
461 					OffsetMicroMeters *= -1;
462 			}
463 
464 			PALDevDataSet(Dev,
465 				Part2PartOffsetAdjustmentNVMMicroMeter,
466 				OffsetMicroMeters);
467 		}
468 		byte = (uint8_t)(ReadDataFromDeviceDone|option);
469 		VL53L0X_SETDEVICESPECIFICPARAMETER(Dev, ReadDataFromDeviceDone,
470 				byte);
471 	}
472 
473 	LOG_FUNCTION_END(Status);
474 	return Status;
475 }
476 
477 
VL53L0X_calc_macro_period_ps(VL53L0X_DEV Dev,uint8_t vcsel_period_pclks)478 uint32_t VL53L0X_calc_macro_period_ps(VL53L0X_DEV Dev, uint8_t vcsel_period_pclks)
479 {
480 	uint64_t PLL_period_ps;
481 	uint32_t macro_period_vclks;
482 	uint32_t macro_period_ps;
483 
484 	LOG_FUNCTION_START("");
485 
486 	/* The above calculation will produce rounding errors,
487 	   therefore set fixed value
488 	*/
489 	PLL_period_ps = 1655;
490 
491 	macro_period_vclks = 2304;
492 	macro_period_ps = (uint32_t)(macro_period_vclks
493 			* vcsel_period_pclks * PLL_period_ps);
494 
495 	LOG_FUNCTION_END("");
496 	return macro_period_ps;
497 }
498 
VL53L0X_encode_timeout(uint32_t timeout_macro_clks)499 uint16_t VL53L0X_encode_timeout(uint32_t timeout_macro_clks)
500 {
501 	/*!
502 	 * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format
503 	 */
504 
505 	uint16_t encoded_timeout = 0;
506 	uint32_t ls_byte = 0;
507 	uint16_t ms_byte = 0;
508 
509 	if (timeout_macro_clks > 0) {
510 		ls_byte = timeout_macro_clks - 1;
511 
512 		while ((ls_byte & 0xFFFFFF00) > 0) {
513 			ls_byte = ls_byte >> 1;
514 			ms_byte++;
515 		}
516 
517 		encoded_timeout = (ms_byte << 8)
518 				+ (uint16_t) (ls_byte & 0x000000FF);
519 	}
520 
521 	return encoded_timeout;
522 
523 }
524 
VL53L0X_decode_timeout(uint16_t encoded_timeout)525 uint32_t VL53L0X_decode_timeout(uint16_t encoded_timeout)
526 {
527 	/*!
528 	 * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1
529 	 */
530 
531 	uint32_t timeout_macro_clks = 0;
532 
533 	timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF)
534 			<< (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1;
535 
536 	return timeout_macro_clks;
537 }
538 
539 
540 /* To convert ms into register value */
VL53L0X_calc_timeout_mclks(VL53L0X_DEV Dev,uint32_t timeout_period_us,uint8_t vcsel_period_pclks)541 uint32_t VL53L0X_calc_timeout_mclks(VL53L0X_DEV Dev,
542 		uint32_t timeout_period_us,
543 		uint8_t vcsel_period_pclks)
544 {
545 	uint32_t macro_period_ps;
546 	uint32_t macro_period_ns;
547 	uint32_t timeout_period_mclks = 0;
548 
549 	macro_period_ps = VL53L0X_calc_macro_period_ps(Dev, vcsel_period_pclks);
550 	macro_period_ns = (macro_period_ps + 500) / 1000;
551 
552 	timeout_period_mclks =
553 		(uint32_t) (((timeout_period_us * 1000)
554 		+ (macro_period_ns / 2)) / macro_period_ns);
555 
556     return timeout_period_mclks;
557 }
558 
559 /* To convert register value into us */
VL53L0X_calc_timeout_us(VL53L0X_DEV Dev,uint16_t timeout_period_mclks,uint8_t vcsel_period_pclks)560 uint32_t VL53L0X_calc_timeout_us(VL53L0X_DEV Dev,
561 		uint16_t timeout_period_mclks,
562 		uint8_t vcsel_period_pclks)
563 {
564 	uint32_t macro_period_ps;
565 	uint32_t macro_period_ns;
566 	uint32_t actual_timeout_period_us = 0;
567 
568 	macro_period_ps = VL53L0X_calc_macro_period_ps(Dev, vcsel_period_pclks);
569 	macro_period_ns = (macro_period_ps + 500) / 1000;
570 
571 	actual_timeout_period_us =
572 		((timeout_period_mclks * macro_period_ns) + 500) / 1000;
573 
574 	return actual_timeout_period_us;
575 }
576 
577 
get_sequence_step_timeout(VL53L0X_DEV Dev,VL53L0X_SequenceStepId SequenceStepId,uint32_t * pTimeOutMicroSecs)578 VL53L0X_Error get_sequence_step_timeout(VL53L0X_DEV Dev,
579 				VL53L0X_SequenceStepId SequenceStepId,
580 				uint32_t *pTimeOutMicroSecs)
581 {
582 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
583 	uint8_t CurrentVCSELPulsePeriodPClk;
584 	uint8_t EncodedTimeOutByte = 0;
585 	uint32_t TimeoutMicroSeconds = 0;
586 	uint16_t PreRangeEncodedTimeOut = 0;
587 	uint16_t MsrcTimeOutMClks;
588 	uint16_t PreRangeTimeOutMClks;
589 	uint16_t FinalRangeTimeOutMClks = 0;
590 	uint16_t FinalRangeEncodedTimeOut;
591 	VL53L0X_SchedulerSequenceSteps_t SchedulerSequenceSteps;
592 
593 	if ((SequenceStepId == VL53L0X_SEQUENCESTEP_TCC)	 ||
594 		(SequenceStepId == VL53L0X_SEQUENCESTEP_DSS)	 ||
595 		(SequenceStepId == VL53L0X_SEQUENCESTEP_MSRC)) {
596 
597 		Status = VL53L0X_GetVcselPulsePeriod(Dev,
598 					VL53L0X_VCSEL_PERIOD_PRE_RANGE,
599 					&CurrentVCSELPulsePeriodPClk);
600 		if (Status == VL53L0X_ERROR_NONE) {
601 			Status = VL53L0X_RdByte(Dev,
602 					VL53L0X_REG_MSRC_CONFIG_TIMEOUT_MACROP,
603 					&EncodedTimeOutByte);
604 		}
605 		MsrcTimeOutMClks = VL53L0X_decode_timeout(EncodedTimeOutByte);
606 
607 		TimeoutMicroSeconds = VL53L0X_calc_timeout_us(Dev,
608 						MsrcTimeOutMClks,
609 						CurrentVCSELPulsePeriodPClk);
610 	} else if (SequenceStepId == VL53L0X_SEQUENCESTEP_PRE_RANGE) {
611 		/* Retrieve PRE-RANGE VCSEL Period */
612 		Status = VL53L0X_GetVcselPulsePeriod(Dev,
613 						VL53L0X_VCSEL_PERIOD_PRE_RANGE,
614 						&CurrentVCSELPulsePeriodPClk);
615 
616 		/* Retrieve PRE-RANGE Timeout in Macro periods (MCLKS) */
617 		if (Status == VL53L0X_ERROR_NONE) {
618 
619 			/* Retrieve PRE-RANGE VCSEL Period */
620 			Status = VL53L0X_GetVcselPulsePeriod(Dev,
621 					VL53L0X_VCSEL_PERIOD_PRE_RANGE,
622 					&CurrentVCSELPulsePeriodPClk);
623 
624 			if (Status == VL53L0X_ERROR_NONE) {
625 				Status = VL53L0X_RdWord(Dev,
626 				VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
627 				&PreRangeEncodedTimeOut);
628 			}
629 
630 			PreRangeTimeOutMClks = VL53L0X_decode_timeout(
631 					PreRangeEncodedTimeOut);
632 
633 			TimeoutMicroSeconds = VL53L0X_calc_timeout_us(Dev,
634 					PreRangeTimeOutMClks,
635 					CurrentVCSELPulsePeriodPClk);
636 		}
637 	} else if (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE) {
638 
639 		VL53L0X_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
640 		PreRangeTimeOutMClks = 0;
641 
642 		if (SchedulerSequenceSteps.PreRangeOn) {
643 			/* Retrieve PRE-RANGE VCSEL Period */
644 			Status = VL53L0X_GetVcselPulsePeriod(Dev,
645 				VL53L0X_VCSEL_PERIOD_PRE_RANGE,
646 				&CurrentVCSELPulsePeriodPClk);
647 
648 			/* Retrieve PRE-RANGE Timeout in Macro periods
649 			 * (MCLKS) */
650 			if (Status == VL53L0X_ERROR_NONE) {
651 				Status = VL53L0X_RdWord(Dev,
652 				VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
653 				&PreRangeEncodedTimeOut);
654 				PreRangeTimeOutMClks = VL53L0X_decode_timeout(
655 						PreRangeEncodedTimeOut);
656 			}
657 		}
658 
659 		if (Status == VL53L0X_ERROR_NONE) {
660 			/* Retrieve FINAL-RANGE VCSEL Period */
661 			Status = VL53L0X_GetVcselPulsePeriod(Dev,
662 					VL53L0X_VCSEL_PERIOD_FINAL_RANGE,
663 					&CurrentVCSELPulsePeriodPClk);
664 		}
665 
666 		/* Retrieve FINAL-RANGE Timeout in Macro periods (MCLKS) */
667 		if (Status == VL53L0X_ERROR_NONE) {
668 			Status = VL53L0X_RdWord(Dev,
669 				VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
670 				&FinalRangeEncodedTimeOut);
671 			FinalRangeTimeOutMClks = VL53L0X_decode_timeout(
672 					FinalRangeEncodedTimeOut);
673 		}
674 
675 		FinalRangeTimeOutMClks -= PreRangeTimeOutMClks;
676 		TimeoutMicroSeconds = VL53L0X_calc_timeout_us(Dev,
677 						FinalRangeTimeOutMClks,
678 						CurrentVCSELPulsePeriodPClk);
679 	}
680 
681 	*pTimeOutMicroSecs = TimeoutMicroSeconds;
682 
683 	return Status;
684 }
685 
686 
set_sequence_step_timeout(VL53L0X_DEV Dev,VL53L0X_SequenceStepId SequenceStepId,uint32_t TimeOutMicroSecs)687 VL53L0X_Error set_sequence_step_timeout(VL53L0X_DEV Dev,
688 					VL53L0X_SequenceStepId SequenceStepId,
689 					uint32_t TimeOutMicroSecs)
690 {
691 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
692 	uint8_t CurrentVCSELPulsePeriodPClk;
693 	uint8_t MsrcEncodedTimeOut;
694 	uint16_t PreRangeEncodedTimeOut;
695 	uint16_t PreRangeTimeOutMClks;
696 	uint16_t MsrcRangeTimeOutMClks;
697 	uint32_t FinalRangeTimeOutMClks;
698 	uint16_t FinalRangeEncodedTimeOut;
699 	VL53L0X_SchedulerSequenceSteps_t SchedulerSequenceSteps;
700 
701 	if ((SequenceStepId == VL53L0X_SEQUENCESTEP_TCC)	 ||
702 		(SequenceStepId == VL53L0X_SEQUENCESTEP_DSS)	 ||
703 		(SequenceStepId == VL53L0X_SEQUENCESTEP_MSRC)) {
704 
705 		Status = VL53L0X_GetVcselPulsePeriod(Dev,
706 					VL53L0X_VCSEL_PERIOD_PRE_RANGE,
707 					&CurrentVCSELPulsePeriodPClk);
708 
709 		if (Status == VL53L0X_ERROR_NONE) {
710 			MsrcRangeTimeOutMClks = VL53L0X_calc_timeout_mclks(Dev,
711 					TimeOutMicroSecs,
712 					(uint8_t)CurrentVCSELPulsePeriodPClk);
713 
714 			if (MsrcRangeTimeOutMClks > 256)
715 				MsrcEncodedTimeOut = 255;
716 			else
717 				MsrcEncodedTimeOut =
718 					(uint8_t)MsrcRangeTimeOutMClks - 1;
719 
720 			VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
721 				LastEncodedTimeout,
722 				MsrcEncodedTimeOut);
723 		}
724 
725 		if (Status == VL53L0X_ERROR_NONE) {
726 			Status = VL53L0X_WrByte(Dev,
727 				VL53L0X_REG_MSRC_CONFIG_TIMEOUT_MACROP,
728 				MsrcEncodedTimeOut);
729 		}
730 	} else {
731 
732 		if (SequenceStepId == VL53L0X_SEQUENCESTEP_PRE_RANGE) {
733 
734 			if (Status == VL53L0X_ERROR_NONE) {
735 				Status = VL53L0X_GetVcselPulsePeriod(Dev,
736 						VL53L0X_VCSEL_PERIOD_PRE_RANGE,
737 						&CurrentVCSELPulsePeriodPClk);
738 				PreRangeTimeOutMClks =
739 					VL53L0X_calc_timeout_mclks(Dev,
740 					TimeOutMicroSecs,
741 					(uint8_t)CurrentVCSELPulsePeriodPClk);
742 				PreRangeEncodedTimeOut = VL53L0X_encode_timeout(
743 					PreRangeTimeOutMClks);
744 
745 				VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
746 					LastEncodedTimeout,
747 					PreRangeEncodedTimeOut);
748 			}
749 
750 			if (Status == VL53L0X_ERROR_NONE) {
751 				Status = VL53L0X_WrWord(Dev,
752 				VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
753 				PreRangeEncodedTimeOut);
754 			}
755 
756 			if (Status == VL53L0X_ERROR_NONE) {
757 				VL53L0X_SETDEVICESPECIFICPARAMETER(
758 					Dev,
759 					PreRangeTimeoutMicroSecs,
760 					TimeOutMicroSecs);
761 			}
762 		} else if (SequenceStepId == VL53L0X_SEQUENCESTEP_FINAL_RANGE) {
763 
764 			/* For the final range timeout, the pre-range timeout
765 			 * must be added. To do this both final and pre-range
766 			 * timeouts must be expressed in macro periods MClks
767 			 * because they have different vcsel periods.
768 			 */
769 
770 			VL53L0X_GetSequenceStepEnables(Dev,
771 					&SchedulerSequenceSteps);
772 			PreRangeTimeOutMClks = 0;
773 			if (SchedulerSequenceSteps.PreRangeOn) {
774 
775 				/* Retrieve PRE-RANGE VCSEL Period */
776 				Status = VL53L0X_GetVcselPulsePeriod(Dev,
777 					VL53L0X_VCSEL_PERIOD_PRE_RANGE,
778 					&CurrentVCSELPulsePeriodPClk);
779 
780 				/* Retrieve PRE-RANGE Timeout in Macro periods
781 				 * (MCLKS) */
782 				if (Status == VL53L0X_ERROR_NONE) {
783 					Status = VL53L0X_RdWord(Dev, 0x51,
784 						&PreRangeEncodedTimeOut);
785 					PreRangeTimeOutMClks =
786 						VL53L0X_decode_timeout(
787 							PreRangeEncodedTimeOut);
788 				}
789 			}
790 
791 			/* Calculate FINAL RANGE Timeout in Macro Periods
792 			 * (MCLKS) and add PRE-RANGE value
793 			 */
794 			if (Status == VL53L0X_ERROR_NONE) {
795 
796 				Status = VL53L0X_GetVcselPulsePeriod(Dev,
797 						VL53L0X_VCSEL_PERIOD_FINAL_RANGE,
798 						&CurrentVCSELPulsePeriodPClk);
799 			}
800 			if (Status == VL53L0X_ERROR_NONE) {
801 
802 				FinalRangeTimeOutMClks =
803 					VL53L0X_calc_timeout_mclks(Dev,
804 					TimeOutMicroSecs,
805 					(uint8_t) CurrentVCSELPulsePeriodPClk);
806 
807 				FinalRangeTimeOutMClks += PreRangeTimeOutMClks;
808 
809 				FinalRangeEncodedTimeOut =
810 				VL53L0X_encode_timeout(FinalRangeTimeOutMClks);
811 
812 				if (Status == VL53L0X_ERROR_NONE) {
813 					Status = VL53L0X_WrWord(Dev, 0x71,
814 					FinalRangeEncodedTimeOut);
815 				}
816 
817 				if (Status == VL53L0X_ERROR_NONE) {
818 					VL53L0X_SETDEVICESPECIFICPARAMETER(
819 						Dev,
820 						FinalRangeTimeoutMicroSecs,
821 						TimeOutMicroSecs);
822 				}
823 			}
824 		} else
825 			Status = VL53L0X_ERROR_INVALID_PARAMS;
826 
827 	}
828 	return Status;
829 }
830 
VL53L0X_set_vcsel_pulse_period(VL53L0X_DEV Dev,VL53L0X_VcselPeriod VcselPeriodType,uint8_t VCSELPulsePeriodPCLK)831 VL53L0X_Error VL53L0X_set_vcsel_pulse_period(VL53L0X_DEV Dev,
832 	VL53L0X_VcselPeriod VcselPeriodType, uint8_t VCSELPulsePeriodPCLK)
833 {
834 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
835 	uint8_t vcsel_period_reg;
836 	uint8_t MinPreVcselPeriodPCLK = 12;
837 	uint8_t MaxPreVcselPeriodPCLK = 18;
838 	uint8_t MinFinalVcselPeriodPCLK = 8;
839 	uint8_t MaxFinalVcselPeriodPCLK = 14;
840 	uint32_t MeasurementTimingBudgetMicroSeconds;
841 	uint32_t FinalRangeTimeoutMicroSeconds;
842 	uint32_t PreRangeTimeoutMicroSeconds;
843 	uint32_t MsrcTimeoutMicroSeconds;
844 	uint8_t PhaseCalInt = 0;
845 
846 	/* Check if valid clock period requested */
847 
848 	if ((VCSELPulsePeriodPCLK % 2) != 0) {
849 		/* Value must be an even number */
850 		Status = VL53L0X_ERROR_INVALID_PARAMS;
851 	} else if (VcselPeriodType == VL53L0X_VCSEL_PERIOD_PRE_RANGE &&
852 		(VCSELPulsePeriodPCLK < MinPreVcselPeriodPCLK ||
853 		VCSELPulsePeriodPCLK > MaxPreVcselPeriodPCLK)) {
854 		Status = VL53L0X_ERROR_INVALID_PARAMS;
855 	} else if (VcselPeriodType == VL53L0X_VCSEL_PERIOD_FINAL_RANGE &&
856 		(VCSELPulsePeriodPCLK < MinFinalVcselPeriodPCLK ||
857 		 VCSELPulsePeriodPCLK > MaxFinalVcselPeriodPCLK)) {
858 
859 		Status = VL53L0X_ERROR_INVALID_PARAMS;
860 	}
861 
862 	/* Apply specific settings for the requested clock period */
863 
864 	if (Status != VL53L0X_ERROR_NONE)
865 		return Status;
866 
867 
868 	if (VcselPeriodType == VL53L0X_VCSEL_PERIOD_PRE_RANGE) {
869 
870 		/* Set phase check limits */
871 		if (VCSELPulsePeriodPCLK == 12) {
872 
873 			Status = VL53L0X_WrByte(Dev,
874 				VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
875 				0x18);
876 			Status = VL53L0X_WrByte(Dev,
877 				VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
878 				0x08);
879 		} else if (VCSELPulsePeriodPCLK == 14) {
880 
881 			Status = VL53L0X_WrByte(Dev,
882 				VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
883 				0x30);
884 			Status = VL53L0X_WrByte(Dev,
885 				VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
886 				0x08);
887 		} else if (VCSELPulsePeriodPCLK == 16) {
888 
889 			Status = VL53L0X_WrByte(Dev,
890 				VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
891 				0x40);
892 			Status = VL53L0X_WrByte(Dev,
893 				VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
894 				0x08);
895 		} else if (VCSELPulsePeriodPCLK == 18) {
896 
897 			Status = VL53L0X_WrByte(Dev,
898 				VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
899 				0x50);
900 			Status = VL53L0X_WrByte(Dev,
901 				VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
902 				0x08);
903 		}
904 	} else if (VcselPeriodType == VL53L0X_VCSEL_PERIOD_FINAL_RANGE) {
905 
906 		if (VCSELPulsePeriodPCLK == 8) {
907 
908 			Status = VL53L0X_WrByte(Dev,
909 				VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
910 				0x10);
911 			Status = VL53L0X_WrByte(Dev,
912 				VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
913 				0x08);
914 
915 			Status |= VL53L0X_WrByte(Dev,
916 				VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
917 			Status |= VL53L0X_WrByte(Dev,
918 				VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
919 
920 			Status |= VL53L0X_WrByte(Dev, 0xff, 0x01);
921 			Status |= VL53L0X_WrByte(Dev,
922 				VL53L0X_REG_ALGO_PHASECAL_LIM,
923 				0x30);
924 			Status |= VL53L0X_WrByte(Dev, 0xff, 0x00);
925 		} else if (VCSELPulsePeriodPCLK == 10) {
926 
927 			Status = VL53L0X_WrByte(Dev,
928 				VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
929 				0x28);
930 			Status = VL53L0X_WrByte(Dev,
931 				VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
932 				0x08);
933 
934 			Status |= VL53L0X_WrByte(Dev,
935 				VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
936 			Status |= VL53L0X_WrByte(Dev,
937 				VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
938 
939 			Status |= VL53L0X_WrByte(Dev, 0xff, 0x01);
940 			Status |= VL53L0X_WrByte(Dev,
941 				VL53L0X_REG_ALGO_PHASECAL_LIM,
942 				0x20);
943 			Status |= VL53L0X_WrByte(Dev, 0xff, 0x00);
944 		} else if (VCSELPulsePeriodPCLK == 12) {
945 
946 			Status = VL53L0X_WrByte(Dev,
947 				VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
948 				0x38);
949 			Status = VL53L0X_WrByte(Dev,
950 				VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
951 				0x08);
952 
953 			Status |= VL53L0X_WrByte(Dev,
954 				VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
955 			Status |= VL53L0X_WrByte(Dev,
956 				VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
957 
958 			Status |= VL53L0X_WrByte(Dev, 0xff, 0x01);
959 			Status |= VL53L0X_WrByte(Dev,
960 				VL53L0X_REG_ALGO_PHASECAL_LIM,
961 				0x20);
962 			Status |= VL53L0X_WrByte(Dev, 0xff, 0x00);
963 		} else if (VCSELPulsePeriodPCLK == 14) {
964 
965 			Status = VL53L0X_WrByte(Dev,
966 				VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
967 				0x048);
968 			Status = VL53L0X_WrByte(Dev,
969 				VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
970 				0x08);
971 
972 			Status |= VL53L0X_WrByte(Dev,
973 				VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
974 			Status |= VL53L0X_WrByte(Dev,
975 				VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
976 
977 			Status |= VL53L0X_WrByte(Dev, 0xff, 0x01);
978 			Status |= VL53L0X_WrByte(Dev,
979 				VL53L0X_REG_ALGO_PHASECAL_LIM,
980 				0x20);
981 			Status |= VL53L0X_WrByte(Dev, 0xff, 0x00);
982 		}
983 	}
984 
985 
986 	/* Re-calculate and apply timeouts, in macro periods */
987 
988 	if (Status == VL53L0X_ERROR_NONE) {
989 		vcsel_period_reg = VL53L0X_encode_vcsel_period((uint8_t)
990 			VCSELPulsePeriodPCLK);
991 
992 		/* When the VCSEL period for the pre or final range is changed,
993 		* the corresponding timeout must be read from the device using
994 		* the current VCSEL period, then the new VCSEL period can be
995 		* applied. The timeout then must be written back to the device
996 		* using the new VCSEL period.
997 		*
998 		* For the MSRC timeout, the same applies - this timeout being
999 		* dependant on the pre-range vcsel period.
1000 		*/
1001 		switch (VcselPeriodType) {
1002 		case VL53L0X_VCSEL_PERIOD_PRE_RANGE:
1003 			Status = get_sequence_step_timeout(Dev,
1004 				VL53L0X_SEQUENCESTEP_PRE_RANGE,
1005 				&PreRangeTimeoutMicroSeconds);
1006 
1007 			if (Status == VL53L0X_ERROR_NONE)
1008 				Status = get_sequence_step_timeout(Dev,
1009 					VL53L0X_SEQUENCESTEP_MSRC,
1010 					&MsrcTimeoutMicroSeconds);
1011 
1012 			if (Status == VL53L0X_ERROR_NONE)
1013 				Status = VL53L0X_WrByte(Dev,
1014 				VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
1015 					vcsel_period_reg);
1016 
1017 
1018 			if (Status == VL53L0X_ERROR_NONE)
1019 				Status = set_sequence_step_timeout(Dev,
1020 					VL53L0X_SEQUENCESTEP_PRE_RANGE,
1021 					PreRangeTimeoutMicroSeconds);
1022 
1023 
1024 			if (Status == VL53L0X_ERROR_NONE)
1025 				Status = set_sequence_step_timeout(Dev,
1026 					VL53L0X_SEQUENCESTEP_MSRC,
1027 					MsrcTimeoutMicroSeconds);
1028 
1029 			VL53L0X_SETDEVICESPECIFICPARAMETER(
1030 				Dev,
1031 				PreRangeVcselPulsePeriod,
1032 				VCSELPulsePeriodPCLK);
1033 			break;
1034 		case VL53L0X_VCSEL_PERIOD_FINAL_RANGE:
1035 			Status = get_sequence_step_timeout(Dev,
1036 				VL53L0X_SEQUENCESTEP_FINAL_RANGE,
1037 				&FinalRangeTimeoutMicroSeconds);
1038 
1039 			if (Status == VL53L0X_ERROR_NONE)
1040 				Status = VL53L0X_WrByte(Dev,
1041 				VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
1042 					vcsel_period_reg);
1043 
1044 
1045 			if (Status == VL53L0X_ERROR_NONE)
1046 				Status = set_sequence_step_timeout(Dev,
1047 					VL53L0X_SEQUENCESTEP_FINAL_RANGE,
1048 					FinalRangeTimeoutMicroSeconds);
1049 
1050 			VL53L0X_SETDEVICESPECIFICPARAMETER(
1051 				Dev,
1052 				FinalRangeVcselPulsePeriod,
1053 				VCSELPulsePeriodPCLK);
1054 			break;
1055 		default:
1056 			Status = VL53L0X_ERROR_INVALID_PARAMS;
1057 		}
1058 	}
1059 
1060 	/* Finally, the timing budget must be re-applied */
1061 	if (Status == VL53L0X_ERROR_NONE) {
1062 		VL53L0X_GETPARAMETERFIELD(Dev,
1063 			MeasurementTimingBudgetMicroSeconds,
1064 			MeasurementTimingBudgetMicroSeconds);
1065 
1066 		Status = VL53L0X_SetMeasurementTimingBudgetMicroSeconds(Dev,
1067 				MeasurementTimingBudgetMicroSeconds);
1068 	}
1069 
1070 	/* Perform the phase calibration. This is needed after changing on
1071 	 * vcsel period.
1072 	 * get_data_enable = 0, restore_config = 1 */
1073 	if (Status == VL53L0X_ERROR_NONE)
1074 		Status = VL53L0X_perform_phase_calibration(
1075 			Dev, &PhaseCalInt, 0, 1);
1076 
1077 	return Status;
1078 }
1079 
VL53L0X_get_vcsel_pulse_period(VL53L0X_DEV Dev,VL53L0X_VcselPeriod VcselPeriodType,uint8_t * pVCSELPulsePeriodPCLK)1080 VL53L0X_Error VL53L0X_get_vcsel_pulse_period(VL53L0X_DEV Dev,
1081 	VL53L0X_VcselPeriod VcselPeriodType, uint8_t *pVCSELPulsePeriodPCLK)
1082 {
1083 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1084 	uint8_t vcsel_period_reg;
1085 
1086 	switch (VcselPeriodType) {
1087 	case VL53L0X_VCSEL_PERIOD_PRE_RANGE:
1088 		Status = VL53L0X_RdByte(Dev,
1089 			VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
1090 			&vcsel_period_reg);
1091 	break;
1092 	case VL53L0X_VCSEL_PERIOD_FINAL_RANGE:
1093 		Status = VL53L0X_RdByte(Dev,
1094 			VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
1095 			&vcsel_period_reg);
1096 	break;
1097 	default:
1098 		Status = VL53L0X_ERROR_INVALID_PARAMS;
1099 	}
1100 
1101 	if (Status == VL53L0X_ERROR_NONE)
1102 		*pVCSELPulsePeriodPCLK =
1103 			VL53L0X_decode_vcsel_period(vcsel_period_reg);
1104 
1105 	return Status;
1106 }
1107 
1108 
1109 
VL53L0X_set_measurement_timing_budget_micro_seconds(VL53L0X_DEV Dev,uint32_t MeasurementTimingBudgetMicroSeconds)1110 VL53L0X_Error VL53L0X_set_measurement_timing_budget_micro_seconds(VL53L0X_DEV Dev,
1111 		uint32_t MeasurementTimingBudgetMicroSeconds)
1112 {
1113 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1114 	uint32_t FinalRangeTimingBudgetMicroSeconds;
1115 	VL53L0X_SchedulerSequenceSteps_t SchedulerSequenceSteps;
1116 	uint32_t MsrcDccTccTimeoutMicroSeconds	= 2000;
1117 	uint32_t StartOverheadMicroSeconds		= 1910;
1118 	uint32_t EndOverheadMicroSeconds		= 960;
1119 	uint32_t MsrcOverheadMicroSeconds		= 660;
1120 	uint32_t TccOverheadMicroSeconds		= 590;
1121 	uint32_t DssOverheadMicroSeconds		= 690;
1122 	uint32_t PreRangeOverheadMicroSeconds	= 660;
1123 	uint32_t FinalRangeOverheadMicroSeconds = 550;
1124 	uint32_t PreRangeTimeoutMicroSeconds	= 0;
1125 	uint32_t cMinTimingBudgetMicroSeconds	= 20000;
1126 	uint32_t SubTimeout = 0;
1127 
1128 	LOG_FUNCTION_START("");
1129 
1130 	if (MeasurementTimingBudgetMicroSeconds
1131 			< cMinTimingBudgetMicroSeconds) {
1132 		Status = VL53L0X_ERROR_INVALID_PARAMS;
1133 		return Status;
1134 	}
1135 
1136 	FinalRangeTimingBudgetMicroSeconds =
1137 		MeasurementTimingBudgetMicroSeconds -
1138 		(StartOverheadMicroSeconds + EndOverheadMicroSeconds);
1139 
1140 	Status = VL53L0X_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
1141 
1142 	if (Status == VL53L0X_ERROR_NONE &&
1143 		(SchedulerSequenceSteps.TccOn  ||
1144 		SchedulerSequenceSteps.MsrcOn ||
1145 		SchedulerSequenceSteps.DssOn)) {
1146 
1147 		/* TCC, MSRC and DSS all share the same timeout */
1148 		Status = get_sequence_step_timeout(Dev,
1149 					VL53L0X_SEQUENCESTEP_MSRC,
1150 					&MsrcDccTccTimeoutMicroSeconds);
1151 
1152 		/* Subtract the TCC, MSRC and DSS timeouts if they are
1153 		 * enabled. */
1154 
1155 		if (Status != VL53L0X_ERROR_NONE)
1156 			return Status;
1157 
1158 		/* TCC */
1159 		if (SchedulerSequenceSteps.TccOn) {
1160 
1161 			SubTimeout = MsrcDccTccTimeoutMicroSeconds
1162 				+ TccOverheadMicroSeconds;
1163 
1164 			if (SubTimeout <
1165 				FinalRangeTimingBudgetMicroSeconds) {
1166 				FinalRangeTimingBudgetMicroSeconds -=
1167 							SubTimeout;
1168 			} else {
1169 				/* Requested timeout too big. */
1170 				Status = VL53L0X_ERROR_INVALID_PARAMS;
1171 			}
1172 		}
1173 
1174 		if (Status != VL53L0X_ERROR_NONE) {
1175 			LOG_FUNCTION_END(Status);
1176 			return Status;
1177 		}
1178 
1179 		/* DSS */
1180 		if (SchedulerSequenceSteps.DssOn) {
1181 
1182 			SubTimeout = 2 * (MsrcDccTccTimeoutMicroSeconds +
1183 				DssOverheadMicroSeconds);
1184 
1185 			if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
1186 				FinalRangeTimingBudgetMicroSeconds
1187 							-= SubTimeout;
1188 			} else {
1189 				/* Requested timeout too big. */
1190 				Status = VL53L0X_ERROR_INVALID_PARAMS;
1191 			}
1192 		} else if (SchedulerSequenceSteps.MsrcOn) {
1193 			/* MSRC */
1194 			SubTimeout = MsrcDccTccTimeoutMicroSeconds +
1195 						MsrcOverheadMicroSeconds;
1196 
1197 			if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
1198 				FinalRangeTimingBudgetMicroSeconds
1199 							-= SubTimeout;
1200 			} else {
1201 				/* Requested timeout too big. */
1202 				Status = VL53L0X_ERROR_INVALID_PARAMS;
1203 			}
1204 		}
1205 
1206 	}
1207 
1208 	if (Status != VL53L0X_ERROR_NONE) {
1209 		LOG_FUNCTION_END(Status);
1210 		return Status;
1211 	}
1212 
1213 	if (SchedulerSequenceSteps.PreRangeOn) {
1214 
1215 		/* Subtract the Pre-range timeout if enabled. */
1216 
1217 		Status = get_sequence_step_timeout(Dev,
1218 				VL53L0X_SEQUENCESTEP_PRE_RANGE,
1219 				&PreRangeTimeoutMicroSeconds);
1220 
1221 		SubTimeout = PreRangeTimeoutMicroSeconds +
1222 				PreRangeOverheadMicroSeconds;
1223 
1224 		if (SubTimeout < FinalRangeTimingBudgetMicroSeconds) {
1225 			FinalRangeTimingBudgetMicroSeconds -= SubTimeout;
1226 		} else {
1227 			/* Requested timeout too big. */
1228 			Status = VL53L0X_ERROR_INVALID_PARAMS;
1229 		}
1230 	}
1231 
1232 
1233 	if (Status == VL53L0X_ERROR_NONE &&
1234 		SchedulerSequenceSteps.FinalRangeOn) {
1235 
1236 		FinalRangeTimingBudgetMicroSeconds -=
1237 				FinalRangeOverheadMicroSeconds;
1238 
1239 		/* Final Range Timeout
1240 		 * Note that the final range timeout is determined by the timing
1241 		 * budget and the sum of all other timeouts within the sequence.
1242 		 * If there is no room for the final range timeout, then an error
1243 		 * will be set. Otherwise the remaining time will be applied to
1244 		 * the final range.
1245 		 */
1246 		Status = set_sequence_step_timeout(Dev,
1247 			VL53L0X_SEQUENCESTEP_FINAL_RANGE,
1248 			FinalRangeTimingBudgetMicroSeconds);
1249 
1250 		VL53L0X_SETPARAMETERFIELD(Dev,
1251 			MeasurementTimingBudgetMicroSeconds,
1252 			MeasurementTimingBudgetMicroSeconds);
1253 	}
1254 
1255 	LOG_FUNCTION_END(Status);
1256 
1257 	return Status;
1258 }
1259 
VL53L0X_get_measurement_timing_budget_micro_seconds(VL53L0X_DEV Dev,uint32_t * pMeasurementTimingBudgetMicroSeconds)1260 VL53L0X_Error VL53L0X_get_measurement_timing_budget_micro_seconds(VL53L0X_DEV Dev,
1261 		uint32_t *pMeasurementTimingBudgetMicroSeconds)
1262 {
1263 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1264 	VL53L0X_SchedulerSequenceSteps_t SchedulerSequenceSteps;
1265 	uint32_t FinalRangeTimeoutMicroSeconds;
1266 	uint32_t MsrcDccTccTimeoutMicroSeconds	= 2000;
1267 	uint32_t StartOverheadMicroSeconds		= 1910;
1268 	uint32_t EndOverheadMicroSeconds		= 960;
1269 	uint32_t MsrcOverheadMicroSeconds		= 660;
1270 	uint32_t TccOverheadMicroSeconds		= 590;
1271 	uint32_t DssOverheadMicroSeconds		= 690;
1272 	uint32_t PreRangeOverheadMicroSeconds	= 660;
1273 	uint32_t FinalRangeOverheadMicroSeconds = 550;
1274 	uint32_t PreRangeTimeoutMicroSeconds	= 0;
1275 
1276 	LOG_FUNCTION_START("");
1277 
1278 	/* Start and end overhead times always present */
1279 	*pMeasurementTimingBudgetMicroSeconds
1280 		= StartOverheadMicroSeconds + EndOverheadMicroSeconds;
1281 
1282 	Status = VL53L0X_GetSequenceStepEnables(Dev, &SchedulerSequenceSteps);
1283 
1284 	if (Status != VL53L0X_ERROR_NONE) {
1285 		LOG_FUNCTION_END(Status);
1286 		return Status;
1287 	}
1288 
1289 
1290 	if (SchedulerSequenceSteps.TccOn  ||
1291 		SchedulerSequenceSteps.MsrcOn ||
1292 		SchedulerSequenceSteps.DssOn) {
1293 
1294 		Status = get_sequence_step_timeout(Dev,
1295 				VL53L0X_SEQUENCESTEP_MSRC,
1296 				&MsrcDccTccTimeoutMicroSeconds);
1297 
1298 		if (Status == VL53L0X_ERROR_NONE) {
1299 			if (SchedulerSequenceSteps.TccOn) {
1300 				*pMeasurementTimingBudgetMicroSeconds +=
1301 					MsrcDccTccTimeoutMicroSeconds +
1302 					TccOverheadMicroSeconds;
1303 			}
1304 
1305 			if (SchedulerSequenceSteps.DssOn) {
1306 				*pMeasurementTimingBudgetMicroSeconds +=
1307 				2 * (MsrcDccTccTimeoutMicroSeconds +
1308 					DssOverheadMicroSeconds);
1309 			} else if (SchedulerSequenceSteps.MsrcOn) {
1310 				*pMeasurementTimingBudgetMicroSeconds +=
1311 					MsrcDccTccTimeoutMicroSeconds +
1312 					MsrcOverheadMicroSeconds;
1313 			}
1314 		}
1315 	}
1316 
1317 	if (Status == VL53L0X_ERROR_NONE) {
1318 		if (SchedulerSequenceSteps.PreRangeOn) {
1319 			Status = get_sequence_step_timeout(Dev,
1320 				VL53L0X_SEQUENCESTEP_PRE_RANGE,
1321 				&PreRangeTimeoutMicroSeconds);
1322 			*pMeasurementTimingBudgetMicroSeconds +=
1323 				PreRangeTimeoutMicroSeconds +
1324 				PreRangeOverheadMicroSeconds;
1325 		}
1326 	}
1327 
1328 	if (Status == VL53L0X_ERROR_NONE) {
1329 		if (SchedulerSequenceSteps.FinalRangeOn) {
1330 			Status = get_sequence_step_timeout(Dev,
1331 					VL53L0X_SEQUENCESTEP_FINAL_RANGE,
1332 					&FinalRangeTimeoutMicroSeconds);
1333 			*pMeasurementTimingBudgetMicroSeconds +=
1334 				(FinalRangeTimeoutMicroSeconds +
1335 				FinalRangeOverheadMicroSeconds);
1336 		}
1337 	}
1338 
1339 	if (Status == VL53L0X_ERROR_NONE) {
1340 		VL53L0X_SETPARAMETERFIELD(Dev,
1341 			MeasurementTimingBudgetMicroSeconds,
1342 			*pMeasurementTimingBudgetMicroSeconds);
1343 	}
1344 
1345 	LOG_FUNCTION_END(Status);
1346 	return Status;
1347 }
1348 
1349 
1350 
VL53L0X_load_tuning_settings(VL53L0X_DEV Dev,uint8_t * pTuningSettingBuffer)1351 VL53L0X_Error VL53L0X_load_tuning_settings(VL53L0X_DEV Dev,
1352 		uint8_t *pTuningSettingBuffer)
1353 {
1354 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1355 	int i;
1356 	int Index;
1357 	uint8_t msb;
1358 	uint8_t lsb;
1359 	uint8_t SelectParam;
1360 	uint8_t NumberOfWrites;
1361 	uint8_t Address;
1362 	uint8_t localBuffer[4]; /* max */
1363 	uint16_t Temp16;
1364 
1365 	LOG_FUNCTION_START("");
1366 
1367 	Index = 0;
1368 
1369 	while ((*(pTuningSettingBuffer + Index) != 0) &&
1370 			(Status == VL53L0X_ERROR_NONE)) {
1371 		NumberOfWrites = *(pTuningSettingBuffer + Index);
1372 		Index++;
1373 		if (NumberOfWrites == 0xFF) {
1374 			/* internal parameters */
1375 			SelectParam = *(pTuningSettingBuffer + Index);
1376 			Index++;
1377 			switch (SelectParam) {
1378 			case 0: /* uint16_t SigmaEstRefArray -> 2 bytes */
1379 				msb = *(pTuningSettingBuffer + Index);
1380 				Index++;
1381 				lsb = *(pTuningSettingBuffer + Index);
1382 				Index++;
1383 				Temp16 = VL53L0X_MAKEUINT16(lsb, msb);
1384 				PALDevDataSet(Dev, SigmaEstRefArray, Temp16);
1385 				break;
1386 			case 1: /* uint16_t SigmaEstEffPulseWidth -> 2 bytes */
1387 				msb = *(pTuningSettingBuffer + Index);
1388 				Index++;
1389 				lsb = *(pTuningSettingBuffer + Index);
1390 				Index++;
1391 				Temp16 = VL53L0X_MAKEUINT16(lsb, msb);
1392 				PALDevDataSet(Dev, SigmaEstEffPulseWidth,
1393 					Temp16);
1394 				break;
1395 			case 2: /* uint16_t SigmaEstEffAmbWidth -> 2 bytes */
1396 				msb = *(pTuningSettingBuffer + Index);
1397 				Index++;
1398 				lsb = *(pTuningSettingBuffer + Index);
1399 				Index++;
1400 				Temp16 = VL53L0X_MAKEUINT16(lsb, msb);
1401 				PALDevDataSet(Dev, SigmaEstEffAmbWidth, Temp16);
1402 				break;
1403 			case 3: /* uint16_t targetRefRate -> 2 bytes */
1404 				msb = *(pTuningSettingBuffer + Index);
1405 				Index++;
1406 				lsb = *(pTuningSettingBuffer + Index);
1407 				Index++;
1408 				Temp16 = VL53L0X_MAKEUINT16(lsb, msb);
1409 				PALDevDataSet(Dev, targetRefRate, Temp16);
1410 				break;
1411 			default: /* invalid parameter */
1412 				Status = VL53L0X_ERROR_INVALID_PARAMS;
1413 			}
1414 
1415 		} else if (NumberOfWrites <= 4) {
1416 			Address = *(pTuningSettingBuffer + Index);
1417 			Index++;
1418 
1419 			for (i = 0; i < NumberOfWrites; i++) {
1420 				localBuffer[i] = *(pTuningSettingBuffer +
1421 							Index);
1422 				Index++;
1423 			}
1424 
1425 			Status = VL53L0X_WriteMulti(Dev, Address, localBuffer,
1426 					NumberOfWrites);
1427 
1428 		} else {
1429 			Status = VL53L0X_ERROR_INVALID_PARAMS;
1430 		}
1431 	}
1432 
1433 	LOG_FUNCTION_END(Status);
1434 	return Status;
1435 }
1436 
VL53L0X_get_total_xtalk_rate(VL53L0X_DEV Dev,VL53L0X_RangingMeasurementData_t * pRangingMeasurementData,FixPoint1616_t * ptotal_xtalk_rate_mcps)1437 VL53L0X_Error VL53L0X_get_total_xtalk_rate(VL53L0X_DEV Dev,
1438 	VL53L0X_RangingMeasurementData_t *pRangingMeasurementData,
1439 	FixPoint1616_t *ptotal_xtalk_rate_mcps)
1440 {
1441 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1442 
1443 	uint8_t xtalkCompEnable;
1444 	FixPoint1616_t totalXtalkMegaCps;
1445 	FixPoint1616_t xtalkPerSpadMegaCps;
1446 
1447 	*ptotal_xtalk_rate_mcps = 0;
1448 
1449 	Status = VL53L0X_GetXTalkCompensationEnable(Dev, &xtalkCompEnable);
1450 	if (Status == VL53L0X_ERROR_NONE) {
1451 
1452 		if (xtalkCompEnable) {
1453 
1454 			VL53L0X_GETPARAMETERFIELD(
1455 				Dev,
1456 				XTalkCompensationRateMegaCps,
1457 				xtalkPerSpadMegaCps);
1458 
1459 			/* FixPoint1616 * FixPoint 8:8 = FixPoint0824 */
1460 			totalXtalkMegaCps =
1461 				pRangingMeasurementData->EffectiveSpadRtnCount *
1462 				xtalkPerSpadMegaCps;
1463 
1464 			/* FixPoint0824 >> 8 = FixPoint1616 */
1465 			*ptotal_xtalk_rate_mcps =
1466 				(totalXtalkMegaCps + 0x80) >> 8;
1467 		}
1468 	}
1469 
1470 	return Status;
1471 }
1472 
VL53L0X_get_total_signal_rate(VL53L0X_DEV Dev,VL53L0X_RangingMeasurementData_t * pRangingMeasurementData,FixPoint1616_t * ptotal_signal_rate_mcps)1473 VL53L0X_Error VL53L0X_get_total_signal_rate(VL53L0X_DEV Dev,
1474 	VL53L0X_RangingMeasurementData_t *pRangingMeasurementData,
1475 	FixPoint1616_t *ptotal_signal_rate_mcps)
1476 {
1477 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1478 	FixPoint1616_t totalXtalkMegaCps;
1479 
1480 	LOG_FUNCTION_START("");
1481 
1482 	*ptotal_signal_rate_mcps =
1483 		pRangingMeasurementData->SignalRateRtnMegaCps;
1484 
1485 	Status = VL53L0X_get_total_xtalk_rate(
1486 		Dev, pRangingMeasurementData, &totalXtalkMegaCps);
1487 
1488 	if (Status == VL53L0X_ERROR_NONE)
1489 		*ptotal_signal_rate_mcps += totalXtalkMegaCps;
1490 
1491 	return Status;
1492 }
1493 
VL53L0X_calc_dmax(VL53L0X_DEV Dev,FixPoint1616_t totalSignalRate_mcps,FixPoint1616_t totalCorrSignalRate_mcps,FixPoint1616_t pwMult,uint32_t sigmaEstimateP1,FixPoint1616_t sigmaEstimateP2,uint32_t peakVcselDuration_us,uint32_t * pdmax_mm)1494 VL53L0X_Error VL53L0X_calc_dmax(
1495 	VL53L0X_DEV Dev,
1496 	FixPoint1616_t totalSignalRate_mcps,
1497 	FixPoint1616_t totalCorrSignalRate_mcps,
1498 	FixPoint1616_t pwMult,
1499 	uint32_t sigmaEstimateP1,
1500 	FixPoint1616_t sigmaEstimateP2,
1501 	uint32_t peakVcselDuration_us,
1502 	uint32_t *pdmax_mm)
1503 {
1504 	const uint32_t cSigmaLimit		= 18;
1505 	const FixPoint1616_t cSignalLimit	= 0x4000; /* 0.25 */
1506 	const FixPoint1616_t cSigmaEstRef	= 0x00000042; /* 0.001 */
1507 	const uint32_t cAmbEffWidthSigmaEst_ns = 6;
1508 	const uint32_t cAmbEffWidthDMax_ns	   = 7;
1509 	uint32_t dmaxCalRange_mm;
1510 	FixPoint1616_t dmaxCalSignalRateRtn_mcps;
1511 	FixPoint1616_t minSignalNeeded;
1512 	FixPoint1616_t minSignalNeeded_p1;
1513 	FixPoint1616_t minSignalNeeded_p2;
1514 	FixPoint1616_t minSignalNeeded_p3;
1515 	FixPoint1616_t minSignalNeeded_p4;
1516 	FixPoint1616_t sigmaLimitTmp;
1517 	FixPoint1616_t sigmaEstSqTmp;
1518 	FixPoint1616_t signalLimitTmp;
1519 	FixPoint1616_t SignalAt0mm;
1520 	FixPoint1616_t dmaxDark;
1521 	FixPoint1616_t dmaxAmbient;
1522 	FixPoint1616_t dmaxDarkTmp;
1523 	FixPoint1616_t sigmaEstP2Tmp;
1524 	uint32_t signalRateTemp_mcps;
1525 
1526 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1527 
1528 	LOG_FUNCTION_START("");
1529 
1530 	dmaxCalRange_mm =
1531 		PALDevDataGet(Dev, DmaxCalRangeMilliMeter);
1532 
1533 	dmaxCalSignalRateRtn_mcps =
1534 		PALDevDataGet(Dev, DmaxCalSignalRateRtnMegaCps);
1535 
1536 	/* uint32 * FixPoint1616 = FixPoint1616 */
1537 	SignalAt0mm = dmaxCalRange_mm * dmaxCalSignalRateRtn_mcps;
1538 
1539 	/* FixPoint1616 >> 8 = FixPoint2408 */
1540 	SignalAt0mm = (SignalAt0mm + 0x80) >> 8;
1541 	SignalAt0mm *= dmaxCalRange_mm;
1542 
1543 	minSignalNeeded_p1 = 0;
1544 	if (totalCorrSignalRate_mcps > 0) {
1545 
1546 		/* Shift by 10 bits to increase resolution prior to the
1547 		 * division */
1548 		signalRateTemp_mcps = totalSignalRate_mcps << 10;
1549 
1550 		/* Add rounding value prior to division */
1551 		minSignalNeeded_p1 = signalRateTemp_mcps +
1552 			(totalCorrSignalRate_mcps/2);
1553 
1554 		/* FixPoint0626/FixPoint1616 = FixPoint2210 */
1555 		minSignalNeeded_p1 /= totalCorrSignalRate_mcps;
1556 
1557 		/* Apply a factored version of the speed of light.
1558 		 Correction to be applied at the end */
1559 		minSignalNeeded_p1 *= 3;
1560 
1561 		/* FixPoint2210 * FixPoint2210 = FixPoint1220 */
1562 		minSignalNeeded_p1 *= minSignalNeeded_p1;
1563 
1564 		/* FixPoint1220 >> 16 = FixPoint2804 */
1565 		minSignalNeeded_p1 = (minSignalNeeded_p1 + 0x8000) >> 16;
1566 	}
1567 
1568 	minSignalNeeded_p2 = pwMult * sigmaEstimateP1;
1569 
1570 	/* FixPoint1616 >> 16 =	 uint32 */
1571 	minSignalNeeded_p2 = (minSignalNeeded_p2 + 0x8000) >> 16;
1572 
1573 	/* uint32 * uint32	=  uint32 */
1574 	minSignalNeeded_p2 *= minSignalNeeded_p2;
1575 
1576 	/* Check sigmaEstimateP2
1577 	 * If this value is too high there is not enough signal rate
1578 	 * to calculate dmax value so set a suitable value to ensure
1579 	 * a very small dmax.
1580 	 */
1581 	sigmaEstP2Tmp = (sigmaEstimateP2 + 0x8000) >> 16;
1582 	sigmaEstP2Tmp = (sigmaEstP2Tmp + cAmbEffWidthSigmaEst_ns/2)/
1583 		cAmbEffWidthSigmaEst_ns;
1584 	sigmaEstP2Tmp *= cAmbEffWidthDMax_ns;
1585 
1586 	if (sigmaEstP2Tmp > 0xffff) {
1587 		minSignalNeeded_p3 = 0xfff00000;
1588 	} else {
1589 
1590 		/* DMAX uses a different ambient width from sigma, so apply
1591 		 * correction.
1592 		 * Perform division before multiplication to prevent overflow.
1593 		 */
1594 		sigmaEstimateP2 = (sigmaEstimateP2 + cAmbEffWidthSigmaEst_ns/2)/
1595 			cAmbEffWidthSigmaEst_ns;
1596 		sigmaEstimateP2 *= cAmbEffWidthDMax_ns;
1597 
1598 		/* FixPoint1616 >> 16 = uint32 */
1599 		minSignalNeeded_p3 = (sigmaEstimateP2 + 0x8000) >> 16;
1600 
1601 		minSignalNeeded_p3 *= minSignalNeeded_p3;
1602 
1603 	}
1604 
1605 	/* FixPoint1814 / uint32 = FixPoint1814 */
1606 	sigmaLimitTmp = ((cSigmaLimit << 14) + 500) / 1000;
1607 
1608 	/* FixPoint1814 * FixPoint1814 = FixPoint3628 := FixPoint0428 */
1609 	sigmaLimitTmp *= sigmaLimitTmp;
1610 
1611 	/* FixPoint1616 * FixPoint1616 = FixPoint3232 */
1612 	sigmaEstSqTmp = cSigmaEstRef * cSigmaEstRef;
1613 
1614 	/* FixPoint3232 >> 4 = FixPoint0428 */
1615 	sigmaEstSqTmp = (sigmaEstSqTmp + 0x08) >> 4;
1616 
1617 	/* FixPoint0428 - FixPoint0428	= FixPoint0428 */
1618 	sigmaLimitTmp -=  sigmaEstSqTmp;
1619 
1620 	/* uint32_t * FixPoint0428 = FixPoint0428 */
1621 	minSignalNeeded_p4 = 4 * 12 * sigmaLimitTmp;
1622 
1623 	/* FixPoint0428 >> 14 = FixPoint1814 */
1624 	minSignalNeeded_p4 = (minSignalNeeded_p4 + 0x2000) >> 14;
1625 
1626 	/* uint32 + uint32 = uint32 */
1627 	minSignalNeeded = (minSignalNeeded_p2 + minSignalNeeded_p3);
1628 
1629 	/* uint32 / uint32 = uint32 */
1630 	minSignalNeeded += (peakVcselDuration_us/2);
1631 	minSignalNeeded /= peakVcselDuration_us;
1632 
1633 	/* uint32 << 14 = FixPoint1814 */
1634 	minSignalNeeded <<= 14;
1635 
1636 	/* FixPoint1814 / FixPoint1814 = uint32 */
1637 	minSignalNeeded += (minSignalNeeded_p4/2);
1638 	minSignalNeeded /= minSignalNeeded_p4;
1639 
1640 	/* FixPoint3200 * FixPoint2804 := FixPoint2804*/
1641 	minSignalNeeded *= minSignalNeeded_p1;
1642 
1643 	/* Apply correction by dividing by 1000000.
1644 	 * This assumes 10E16 on the numerator of the equation
1645 	 * and 10E-22 on the denominator.
1646 	 * We do this because 32bit fix point calculation can't
1647 	 * handle the larger and smaller elements of this equation,
1648 	 * i.e. speed of light and pulse widths.
1649 	 */
1650 	minSignalNeeded = (minSignalNeeded + 500) / 1000;
1651 	minSignalNeeded <<= 4;
1652 
1653 	minSignalNeeded = (minSignalNeeded + 500) / 1000;
1654 
1655 	/* FixPoint1616 >> 8 = FixPoint2408 */
1656 	signalLimitTmp = (cSignalLimit + 0x80) >> 8;
1657 
1658 	/* FixPoint2408/FixPoint2408 = uint32 */
1659 	if (signalLimitTmp != 0)
1660 		dmaxDarkTmp = (SignalAt0mm + (signalLimitTmp / 2))
1661 			/ signalLimitTmp;
1662 	else
1663 		dmaxDarkTmp = 0;
1664 
1665 	dmaxDark = VL53L0X_isqrt(dmaxDarkTmp);
1666 
1667 	/* FixPoint2408/FixPoint2408 = uint32 */
1668 	if (minSignalNeeded != 0)
1669 		dmaxAmbient = (SignalAt0mm + minSignalNeeded/2)
1670 			/ minSignalNeeded;
1671 	else
1672 		dmaxAmbient = 0;
1673 
1674 	dmaxAmbient = VL53L0X_isqrt(dmaxAmbient);
1675 
1676 	*pdmax_mm = dmaxDark;
1677 	if (dmaxDark > dmaxAmbient)
1678 		*pdmax_mm = dmaxAmbient;
1679 
1680 	LOG_FUNCTION_END(Status);
1681 
1682 	return Status;
1683 }
1684 
1685 
VL53L0X_calc_sigma_estimate(VL53L0X_DEV Dev,VL53L0X_RangingMeasurementData_t * pRangingMeasurementData,FixPoint1616_t * pSigmaEstimate,uint32_t * pDmax_mm)1686 VL53L0X_Error VL53L0X_calc_sigma_estimate(VL53L0X_DEV Dev,
1687 	VL53L0X_RangingMeasurementData_t *pRangingMeasurementData,
1688 	FixPoint1616_t *pSigmaEstimate,
1689 	uint32_t *pDmax_mm)
1690 {
1691 	/* Expressed in 100ths of a ns, i.e. centi-ns */
1692 	const uint32_t cPulseEffectiveWidth_centi_ns   = 800;
1693 	/* Expressed in 100ths of a ns, i.e. centi-ns */
1694 	const uint32_t cAmbientEffectiveWidth_centi_ns = 600;
1695 	const FixPoint1616_t cDfltFinalRangeIntegrationTimeMilliSecs	= 0x00190000; /* 25ms */
1696 	const uint32_t cVcselPulseWidth_ps	= 4700; /* pico secs */
1697 	const FixPoint1616_t cSigmaEstMax	= 0x028F87AE;
1698 	const FixPoint1616_t cSigmaEstRtnMax	= 0xF000;
1699 	const FixPoint1616_t cAmbToSignalRatioMax = 0xF0000000/
1700 		cAmbientEffectiveWidth_centi_ns;
1701 	/* Time Of Flight per mm (6.6 pico secs) */
1702 	const FixPoint1616_t cTOF_per_mm_ps		= 0x0006999A;
1703 	const uint32_t c16BitRoundingParam		= 0x00008000;
1704 	const FixPoint1616_t cMaxXTalk_kcps		= 0x00320000;
1705 	const uint32_t cPllPeriod_ps			= 1655;
1706 
1707 	uint32_t vcselTotalEventsRtn;
1708 	uint32_t finalRangeTimeoutMicroSecs;
1709 	uint32_t preRangeTimeoutMicroSecs;
1710 	uint32_t finalRangeIntegrationTimeMilliSecs;
1711 	FixPoint1616_t sigmaEstimateP1;
1712 	FixPoint1616_t sigmaEstimateP2;
1713 	FixPoint1616_t sigmaEstimateP3;
1714 	FixPoint1616_t deltaT_ps;
1715 	FixPoint1616_t pwMult;
1716 	FixPoint1616_t sigmaEstRtn;
1717 	FixPoint1616_t sigmaEstimate;
1718 	FixPoint1616_t xTalkCorrection;
1719 	FixPoint1616_t ambientRate_kcps;
1720 	FixPoint1616_t peakSignalRate_kcps;
1721 	FixPoint1616_t xTalkCompRate_mcps;
1722 	uint32_t xTalkCompRate_kcps;
1723 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1724 	FixPoint1616_t diff1_mcps;
1725 	FixPoint1616_t diff2_mcps;
1726 	FixPoint1616_t sqr1;
1727 	FixPoint1616_t sqr2;
1728 	FixPoint1616_t sqrSum;
1729 	FixPoint1616_t sqrtResult_centi_ns;
1730 	FixPoint1616_t sqrtResult;
1731 	FixPoint1616_t totalSignalRate_mcps;
1732 	FixPoint1616_t correctedSignalRate_mcps;
1733 	FixPoint1616_t sigmaEstRef;
1734 	uint32_t vcselWidth;
1735 	uint32_t finalRangeMacroPCLKS;
1736 	uint32_t preRangeMacroPCLKS;
1737 	uint32_t peakVcselDuration_us;
1738 	uint8_t finalRangeVcselPCLKS;
1739 	uint8_t preRangeVcselPCLKS;
1740 	/*! \addtogroup calc_sigma_estimate
1741 	 * @{
1742 	 *
1743 	 * Estimates the range sigma
1744 	 */
1745 
1746 	LOG_FUNCTION_START("");
1747 
1748 	VL53L0X_GETPARAMETERFIELD(Dev, XTalkCompensationRateMegaCps,
1749 			xTalkCompRate_mcps);
1750 
1751 	/*
1752 	 * We work in kcps rather than mcps as this helps keep within the
1753 	 * confines of the 32 Fix1616 type.
1754 	 */
1755 
1756 	ambientRate_kcps =
1757 		(pRangingMeasurementData->AmbientRateRtnMegaCps * 1000) >> 16;
1758 
1759 	correctedSignalRate_mcps =
1760 		pRangingMeasurementData->SignalRateRtnMegaCps;
1761 
1762 
1763 	Status = VL53L0X_get_total_signal_rate(
1764 		Dev, pRangingMeasurementData, &totalSignalRate_mcps);
1765 	Status = VL53L0X_get_total_xtalk_rate(
1766 		Dev, pRangingMeasurementData, &xTalkCompRate_mcps);
1767 
1768 
1769 	/* Signal rate measurement provided by device is the
1770 	 * peak signal rate, not average.
1771 	 */
1772 	peakSignalRate_kcps = (totalSignalRate_mcps * 1000);
1773 	peakSignalRate_kcps = (peakSignalRate_kcps + 0x8000) >> 16;
1774 
1775 	xTalkCompRate_kcps = xTalkCompRate_mcps * 1000;
1776 
1777 	if (xTalkCompRate_kcps > cMaxXTalk_kcps)
1778 		xTalkCompRate_kcps = cMaxXTalk_kcps;
1779 
1780 	if (Status == VL53L0X_ERROR_NONE) {
1781 
1782 		/* Calculate final range macro periods */
1783 		finalRangeTimeoutMicroSecs = VL53L0X_GETDEVICESPECIFICPARAMETER(
1784 			Dev, FinalRangeTimeoutMicroSecs);
1785 
1786 		finalRangeVcselPCLKS = VL53L0X_GETDEVICESPECIFICPARAMETER(
1787 			Dev, FinalRangeVcselPulsePeriod);
1788 
1789 		finalRangeMacroPCLKS = VL53L0X_calc_timeout_mclks(
1790 			Dev, finalRangeTimeoutMicroSecs, finalRangeVcselPCLKS);
1791 
1792 		/* Calculate pre-range macro periods */
1793 		preRangeTimeoutMicroSecs = VL53L0X_GETDEVICESPECIFICPARAMETER(
1794 			Dev, PreRangeTimeoutMicroSecs);
1795 
1796 		preRangeVcselPCLKS = VL53L0X_GETDEVICESPECIFICPARAMETER(
1797 			Dev, PreRangeVcselPulsePeriod);
1798 
1799 		preRangeMacroPCLKS = VL53L0X_calc_timeout_mclks(
1800 			Dev, preRangeTimeoutMicroSecs, preRangeVcselPCLKS);
1801 
1802 		vcselWidth = 3;
1803 		if (finalRangeVcselPCLKS == 8)
1804 			vcselWidth = 2;
1805 
1806 
1807 		peakVcselDuration_us = vcselWidth * 2048 *
1808 			(preRangeMacroPCLKS + finalRangeMacroPCLKS);
1809 		peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
1810 		peakVcselDuration_us *= cPllPeriod_ps;
1811 		peakVcselDuration_us = (peakVcselDuration_us + 500)/1000;
1812 
1813 		/* Fix1616 >> 8 = Fix2408 */
1814 		totalSignalRate_mcps = (totalSignalRate_mcps + 0x80) >> 8;
1815 
1816 		/* Fix2408 * uint32 = Fix2408 */
1817 		vcselTotalEventsRtn = totalSignalRate_mcps *
1818 			peakVcselDuration_us;
1819 
1820 		/* Fix2408 >> 8 = uint32 */
1821 		vcselTotalEventsRtn = (vcselTotalEventsRtn + 0x80) >> 8;
1822 
1823 		/* Fix2408 << 8 = Fix1616 = */
1824 		totalSignalRate_mcps <<= 8;
1825 	}
1826 
1827 	if (Status != VL53L0X_ERROR_NONE) {
1828 		LOG_FUNCTION_END(Status);
1829 		return Status;
1830 	}
1831 
1832 	if (peakSignalRate_kcps == 0) {
1833 		*pSigmaEstimate = cSigmaEstMax;
1834 		PALDevDataSet(Dev, SigmaEstimate, cSigmaEstMax);
1835 		*pDmax_mm = 0;
1836 	} else {
1837 		if (vcselTotalEventsRtn < 1)
1838 			vcselTotalEventsRtn = 1;
1839 
1840 		sigmaEstimateP1 = cPulseEffectiveWidth_centi_ns;
1841 
1842 		/* ((FixPoint1616 << 16)* uint32)/uint32 = FixPoint1616 */
1843 		sigmaEstimateP2 = (ambientRate_kcps << 16)/peakSignalRate_kcps;
1844 		if (sigmaEstimateP2 > cAmbToSignalRatioMax) {
1845 			/* Clip to prevent overflow. Will ensure safe
1846 			 * max result. */
1847 			sigmaEstimateP2 = cAmbToSignalRatioMax;
1848 		}
1849 		sigmaEstimateP2 *= cAmbientEffectiveWidth_centi_ns;
1850 
1851 		sigmaEstimateP3 = 2 * VL53L0X_isqrt(vcselTotalEventsRtn * 12);
1852 
1853 		/* uint32 * FixPoint1616 = FixPoint1616 */
1854 		deltaT_ps = pRangingMeasurementData->RangeMilliMeter *
1855 					cTOF_per_mm_ps;
1856 
1857 		/*
1858 		 * vcselRate - xtalkCompRate
1859 		 * (uint32 << 16) - FixPoint1616 = FixPoint1616.
1860 		 * Divide result by 1000 to convert to mcps.
1861 		 * 500 is added to ensure rounding when integer division
1862 		 * truncates.
1863 		 */
1864 		diff1_mcps = (((peakSignalRate_kcps << 16) -
1865 			2 * xTalkCompRate_kcps) + 500)/1000;
1866 
1867 		/* vcselRate + xtalkCompRate */
1868 		diff2_mcps = ((peakSignalRate_kcps << 16) + 500)/1000;
1869 
1870 		/* Shift by 8 bits to increase resolution prior to the
1871 		 * division */
1872 		diff1_mcps <<= 8;
1873 
1874 		/* FixPoint0824/FixPoint1616 = FixPoint2408 */
1875 		xTalkCorrection	 = abs(diff1_mcps/diff2_mcps);
1876 
1877 		/* FixPoint2408 << 8 = FixPoint1616 */
1878 		xTalkCorrection <<= 8;
1879 
1880 		if(pRangingMeasurementData->RangeStatus != 0){
1881 			pwMult = 1 << 16;
1882 		} else {
1883 			/* FixPoint1616/uint32 = FixPoint1616 */
1884 			pwMult = deltaT_ps/cVcselPulseWidth_ps; /* smaller than 1.0f */
1885 
1886 			/*
1887 			 * FixPoint1616 * FixPoint1616 = FixPoint3232, however both
1888 			 * values are small enough such that32 bits will not be
1889 			 * exceeded.
1890 			 */
1891 			pwMult *= ((1 << 16) - xTalkCorrection);
1892 
1893 			/* (FixPoint3232 >> 16) = FixPoint1616 */
1894 			pwMult =  (pwMult + c16BitRoundingParam) >> 16;
1895 
1896 			/* FixPoint1616 + FixPoint1616 = FixPoint1616 */
1897 			pwMult += (1 << 16);
1898 
1899 			/*
1900 			 * At this point the value will be 1.xx, therefore if we square
1901 			 * the value this will exceed 32 bits. To address this perform
1902 			 * a single shift to the right before the multiplication.
1903 			 */
1904 			pwMult >>= 1;
1905 			/* FixPoint1715 * FixPoint1715 = FixPoint3430 */
1906 			pwMult = pwMult * pwMult;
1907 
1908 			/* (FixPoint3430 >> 14) = Fix1616 */
1909 			pwMult >>= 14;
1910 		}
1911 
1912 		/* FixPoint1616 * uint32 = FixPoint1616 */
1913 		sqr1 = pwMult * sigmaEstimateP1;
1914 
1915 		/* (FixPoint1616 >> 16) = FixPoint3200 */
1916 		sqr1 = (sqr1 + 0x8000) >> 16;
1917 
1918 		/* FixPoint3200 * FixPoint3200 = FixPoint6400 */
1919 		sqr1 *= sqr1;
1920 
1921 		sqr2 = sigmaEstimateP2;
1922 
1923 		/* (FixPoint1616 >> 16) = FixPoint3200 */
1924 		sqr2 = (sqr2 + 0x8000) >> 16;
1925 
1926 		/* FixPoint3200 * FixPoint3200 = FixPoint6400 */
1927 		sqr2 *= sqr2;
1928 
1929 		/* FixPoint64000 + FixPoint6400 = FixPoint6400 */
1930 		sqrSum = sqr1 + sqr2;
1931 
1932 		/* SQRT(FixPoin6400) = FixPoint3200 */
1933 		sqrtResult_centi_ns = VL53L0X_isqrt(sqrSum);
1934 
1935 		/* (FixPoint3200 << 16) = FixPoint1616 */
1936 		sqrtResult_centi_ns <<= 16;
1937 
1938 		/*
1939 		 * Note that the Speed Of Light is expressed in um per 1E-10
1940 		 * seconds (2997) Therefore to get mm/ns we have to divide by
1941 		 * 10000
1942 		 */
1943 		sigmaEstRtn = (((sqrtResult_centi_ns+50)/100) /
1944 				sigmaEstimateP3);
1945 		sigmaEstRtn		 *= VL53L0X_SPEED_OF_LIGHT_IN_AIR;
1946 
1947 		/* Add 5000 before dividing by 10000 to ensure rounding. */
1948 		sigmaEstRtn		 += 5000;
1949 		sigmaEstRtn		 /= 10000;
1950 
1951 		if (sigmaEstRtn > cSigmaEstRtnMax) {
1952 			/* Clip to prevent overflow. Will ensure safe
1953 			 * max result. */
1954 			sigmaEstRtn = cSigmaEstRtnMax;
1955 		}
1956 		finalRangeIntegrationTimeMilliSecs =
1957 			(finalRangeTimeoutMicroSecs + preRangeTimeoutMicroSecs + 500)/1000;
1958 
1959 		/* sigmaEstRef = 1mm * 25ms/final range integration time (inc pre-range)
1960 		 * sqrt(FixPoint1616/int) = FixPoint2408)
1961 		 */
1962 		sigmaEstRef =
1963 			VL53L0X_isqrt((cDfltFinalRangeIntegrationTimeMilliSecs +
1964 				finalRangeIntegrationTimeMilliSecs/2)/
1965 				finalRangeIntegrationTimeMilliSecs);
1966 
1967 		/* FixPoint2408 << 8 = FixPoint1616 */
1968 		sigmaEstRef <<= 8;
1969 		sigmaEstRef = (sigmaEstRef + 500)/1000;
1970 
1971 		/* FixPoint1616 * FixPoint1616 = FixPoint3232 */
1972 		sqr1 = sigmaEstRtn * sigmaEstRtn;
1973 		/* FixPoint1616 * FixPoint1616 = FixPoint3232 */
1974 		sqr2 = sigmaEstRef * sigmaEstRef;
1975 
1976 		/* sqrt(FixPoint3232) = FixPoint1616 */
1977 		sqrtResult = VL53L0X_isqrt((sqr1 + sqr2));
1978 		/*
1979 		 * Note that the Shift by 4 bits increases resolution prior to
1980 		 * the sqrt, therefore the result must be shifted by 2 bits to
1981 		 * the right to revert back to the FixPoint1616 format.
1982 		 */
1983 
1984 		sigmaEstimate	 = 1000 * sqrtResult;
1985 
1986 		if ((peakSignalRate_kcps < 1) || (vcselTotalEventsRtn < 1) ||
1987 				(sigmaEstimate > cSigmaEstMax)) {
1988 				sigmaEstimate = cSigmaEstMax;
1989 		}
1990 
1991 		*pSigmaEstimate = (uint32_t)(sigmaEstimate);
1992 		PALDevDataSet(Dev, SigmaEstimate, *pSigmaEstimate);
1993 		Status = VL53L0X_calc_dmax(
1994 			Dev,
1995 			totalSignalRate_mcps,
1996 			correctedSignalRate_mcps,
1997 			pwMult,
1998 			sigmaEstimateP1,
1999 			sigmaEstimateP2,
2000 			peakVcselDuration_us,
2001 			pDmax_mm);
2002 	}
2003 
2004 	LOG_FUNCTION_END(Status);
2005 	return Status;
2006 }
2007 
VL53L0X_get_pal_range_status(VL53L0X_DEV Dev,uint8_t DeviceRangeStatus,FixPoint1616_t SignalRate,uint16_t EffectiveSpadRtnCount,VL53L0X_RangingMeasurementData_t * pRangingMeasurementData,uint8_t * pPalRangeStatus)2008 VL53L0X_Error VL53L0X_get_pal_range_status(VL53L0X_DEV Dev,
2009 		uint8_t DeviceRangeStatus,
2010 		FixPoint1616_t SignalRate,
2011 		uint16_t EffectiveSpadRtnCount,
2012 		VL53L0X_RangingMeasurementData_t *pRangingMeasurementData,
2013 		uint8_t *pPalRangeStatus)
2014 {
2015 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
2016 	uint8_t NoneFlag;
2017 	uint8_t SigmaLimitflag = 0;
2018 	uint8_t SignalRefClipflag = 0;
2019 	uint8_t RangeIgnoreThresholdflag = 0;
2020 	uint8_t SigmaLimitCheckEnable = 0;
2021 	uint8_t SignalRateFinalRangeLimitCheckEnable = 0;
2022 	uint8_t SignalRefClipLimitCheckEnable = 0;
2023 	uint8_t RangeIgnoreThresholdLimitCheckEnable = 0;
2024 	FixPoint1616_t SigmaEstimate;
2025 	FixPoint1616_t SigmaLimitValue;
2026 	FixPoint1616_t SignalRefClipValue;
2027 	FixPoint1616_t RangeIgnoreThresholdValue;
2028 	FixPoint1616_t SignalRatePerSpad;
2029 	uint8_t DeviceRangeStatusInternal = 0;
2030 	uint16_t tmpWord = 0;
2031 	uint8_t Temp8;
2032 	uint32_t Dmax_mm = 0;
2033 	FixPoint1616_t LastSignalRefMcps;
2034 
2035 	LOG_FUNCTION_START("");
2036 
2037 
2038 	/*
2039 	 * VL53L0X has a good ranging when the value of the
2040 	 * DeviceRangeStatus = 11. This function will replace the value 0 with
2041 	 * the value 11 in the DeviceRangeStatus.
2042 	 * In addition, the SigmaEstimator is not included in the VL53L0X
2043 	 * DeviceRangeStatus, this will be added in the PalRangeStatus.
2044 	 */
2045 
2046 	DeviceRangeStatusInternal = ((DeviceRangeStatus & 0x78) >> 3);
2047 
2048 	if (DeviceRangeStatusInternal == 0 ||
2049 		DeviceRangeStatusInternal == 5 ||
2050 		DeviceRangeStatusInternal == 7 ||
2051 		DeviceRangeStatusInternal == 12 ||
2052 		DeviceRangeStatusInternal == 13 ||
2053 		DeviceRangeStatusInternal == 14 ||
2054 		DeviceRangeStatusInternal == 15
2055 			) {
2056 		NoneFlag = 1;
2057 	} else {
2058 		NoneFlag = 0;
2059 	}
2060 
2061 	/*
2062 	 * Check if Sigma limit is enabled, if yes then do comparison with limit
2063 	 * value and put the result back into pPalRangeStatus.
2064 	 */
2065 	if (Status == VL53L0X_ERROR_NONE)
2066 		Status =  VL53L0X_GetLimitCheckEnable(Dev,
2067 			VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
2068 			&SigmaLimitCheckEnable);
2069 
2070 	if ((SigmaLimitCheckEnable != 0) && (Status == VL53L0X_ERROR_NONE)) {
2071 		/*
2072 		* compute the Sigma and check with limit
2073 		*/
2074 		Status = VL53L0X_calc_sigma_estimate(
2075 			Dev,
2076 			pRangingMeasurementData,
2077 			&SigmaEstimate,
2078 			&Dmax_mm);
2079 		if (Status == VL53L0X_ERROR_NONE)
2080 			pRangingMeasurementData->RangeDMaxMilliMeter = Dmax_mm;
2081 
2082 		if (Status == VL53L0X_ERROR_NONE) {
2083 			Status = VL53L0X_GetLimitCheckValue(Dev,
2084 				VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
2085 				&SigmaLimitValue);
2086 
2087 			if ((SigmaLimitValue > 0) &&
2088 				(SigmaEstimate > SigmaLimitValue))
2089 					/* Limit Fail */
2090 					SigmaLimitflag = 1;
2091 		}
2092 	}
2093 
2094 	/*
2095 	 * Check if Signal ref clip limit is enabled, if yes then do comparison
2096 	 * with limit value and put the result back into pPalRangeStatus.
2097 	 */
2098 	if (Status == VL53L0X_ERROR_NONE)
2099 		Status =  VL53L0X_GetLimitCheckEnable(Dev,
2100 				VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP,
2101 				&SignalRefClipLimitCheckEnable);
2102 
2103 	if ((SignalRefClipLimitCheckEnable != 0) &&
2104 			(Status == VL53L0X_ERROR_NONE)) {
2105 
2106 		Status = VL53L0X_GetLimitCheckValue(Dev,
2107 				VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP,
2108 				&SignalRefClipValue);
2109 
2110 		/* Read LastSignalRefMcps from device */
2111 		if (Status == VL53L0X_ERROR_NONE)
2112 			Status = VL53L0X_WrByte(Dev, 0xFF, 0x01);
2113 
2114 		if (Status == VL53L0X_ERROR_NONE)
2115 			Status = VL53L0X_RdWord(Dev,
2116 				VL53L0X_REG_RESULT_PEAK_SIGNAL_RATE_REF,
2117 				&tmpWord);
2118 
2119 		if (Status == VL53L0X_ERROR_NONE)
2120 			Status = VL53L0X_WrByte(Dev, 0xFF, 0x00);
2121 
2122 		LastSignalRefMcps = VL53L0X_FIXPOINT97TOFIXPOINT1616(tmpWord);
2123 		PALDevDataSet(Dev, LastSignalRefMcps, LastSignalRefMcps);
2124 
2125 		if ((SignalRefClipValue > 0) &&
2126 				(LastSignalRefMcps > SignalRefClipValue)) {
2127 			/* Limit Fail */
2128 			SignalRefClipflag = 1;
2129 		}
2130 	}
2131 
2132 	/*
2133 	 * Check if Signal ref clip limit is enabled, if yes then do comparison
2134 	 * with limit value and put the result back into pPalRangeStatus.
2135 	 * EffectiveSpadRtnCount has a format 8.8
2136 	 * If (Return signal rate < (1.5 x Xtalk x number of Spads)) : FAIL
2137 	 */
2138 	if (Status == VL53L0X_ERROR_NONE)
2139 		Status =  VL53L0X_GetLimitCheckEnable(Dev,
2140 				VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
2141 				&RangeIgnoreThresholdLimitCheckEnable);
2142 
2143 	if ((RangeIgnoreThresholdLimitCheckEnable != 0) &&
2144 			(Status == VL53L0X_ERROR_NONE)) {
2145 
2146 		/* Compute the signal rate per spad */
2147 		if (EffectiveSpadRtnCount == 0) {
2148 			SignalRatePerSpad = 0;
2149 		} else {
2150 			SignalRatePerSpad = (FixPoint1616_t)((256 * SignalRate)
2151 				/ EffectiveSpadRtnCount);
2152 		}
2153 
2154 		Status = VL53L0X_GetLimitCheckValue(Dev,
2155 				VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
2156 				&RangeIgnoreThresholdValue);
2157 
2158 		if ((RangeIgnoreThresholdValue > 0) &&
2159 			(SignalRatePerSpad < RangeIgnoreThresholdValue)) {
2160 			/* Limit Fail add 2^6 to range status */
2161 			RangeIgnoreThresholdflag = 1;
2162 		}
2163 	}
2164 
2165 	if (Status == VL53L0X_ERROR_NONE) {
2166 		if (NoneFlag == 1) {
2167 			*pPalRangeStatus = 255;	 /* NONE */
2168 		} else if (DeviceRangeStatusInternal == 1 ||
2169 					DeviceRangeStatusInternal == 2 ||
2170 					DeviceRangeStatusInternal == 3) {
2171 			*pPalRangeStatus = 5; /* HW fail */
2172 		} else if (DeviceRangeStatusInternal == 6 ||
2173 					DeviceRangeStatusInternal == 9) {
2174 			*pPalRangeStatus = 4;  /* Phase fail */
2175 		} else if (DeviceRangeStatusInternal == 8 ||
2176 					DeviceRangeStatusInternal == 10 ||
2177 					SignalRefClipflag == 1) {
2178 			*pPalRangeStatus = 3;  /* Min range */
2179 		} else if (DeviceRangeStatusInternal == 4 ||
2180 					RangeIgnoreThresholdflag == 1) {
2181 			*pPalRangeStatus = 2;  /* Signal Fail */
2182 		} else if (SigmaLimitflag == 1) {
2183 			*pPalRangeStatus = 1;  /* Sigma	 Fail */
2184 		} else {
2185 			*pPalRangeStatus = 0; /* Range Valid */
2186 		}
2187 	}
2188 
2189 	/* DMAX only relevant during range error */
2190 	if (*pPalRangeStatus == 0)
2191 		pRangingMeasurementData->RangeDMaxMilliMeter = 0;
2192 
2193 	/* fill the Limit Check Status */
2194 
2195 	Status =  VL53L0X_GetLimitCheckEnable(Dev,
2196 			VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
2197 			&SignalRateFinalRangeLimitCheckEnable);
2198 
2199 	if (Status == VL53L0X_ERROR_NONE) {
2200 		if ((SigmaLimitCheckEnable == 0) || (SigmaLimitflag == 1))
2201 			Temp8 = 1;
2202 		else
2203 			Temp8 = 0;
2204 		VL53L0X_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
2205 				VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, Temp8);
2206 
2207 		if ((DeviceRangeStatusInternal == 4) ||
2208 				(SignalRateFinalRangeLimitCheckEnable == 0))
2209 			Temp8 = 1;
2210 		else
2211 			Temp8 = 0;
2212 		VL53L0X_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
2213 				VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
2214 				Temp8);
2215 
2216 		if ((SignalRefClipLimitCheckEnable == 0) ||
2217 					(SignalRefClipflag == 1))
2218 			Temp8 = 1;
2219 		else
2220 			Temp8 = 0;
2221 
2222 		VL53L0X_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
2223 				VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP, Temp8);
2224 
2225 		if ((RangeIgnoreThresholdLimitCheckEnable == 0) ||
2226 				(RangeIgnoreThresholdflag == 1))
2227 			Temp8 = 1;
2228 		else
2229 			Temp8 = 0;
2230 
2231 		VL53L0X_SETARRAYPARAMETERFIELD(Dev, LimitChecksStatus,
2232 				VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
2233 				Temp8);
2234 	}
2235 
2236 	LOG_FUNCTION_END(Status);
2237 	return Status;
2238 
2239 }
2240