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 #ifndef __KERNEL__
34 #include <stdlib.h>
35 #endif
36 
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 
44 #define REF_ARRAY_SPAD_0  0
45 #define REF_ARRAY_SPAD_5  5
46 #define REF_ARRAY_SPAD_10 10
47 
48 uint32_t refArrayQuadrants[4] = {REF_ARRAY_SPAD_10, REF_ARRAY_SPAD_5,
49 		REF_ARRAY_SPAD_0, REF_ARRAY_SPAD_5 };
50 
VL53L0X_perform_xtalk_calibration(VL53L0X_DEV Dev,FixPoint1616_t XTalkCalDistance,FixPoint1616_t * pXTalkCompensationRateMegaCps)51 VL53L0X_Error VL53L0X_perform_xtalk_calibration(VL53L0X_DEV Dev,
52 			FixPoint1616_t XTalkCalDistance,
53 			FixPoint1616_t *pXTalkCompensationRateMegaCps)
54 {
55 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
56 	uint16_t sum_ranging = 0;
57 	uint16_t sum_spads = 0;
58 	FixPoint1616_t sum_signalRate = 0;
59 	FixPoint1616_t total_count = 0;
60 	uint8_t xtalk_meas = 0;
61 	VL53L0X_RangingMeasurementData_t RangingMeasurementData;
62 	FixPoint1616_t xTalkStoredMeanSignalRate;
63 	FixPoint1616_t xTalkStoredMeanRange;
64 	FixPoint1616_t xTalkStoredMeanRtnSpads;
65 	uint32_t signalXTalkTotalPerSpad;
66 	uint32_t xTalkStoredMeanRtnSpadsAsInt;
67 	uint32_t xTalkCalDistanceAsInt;
68 	FixPoint1616_t XTalkCompensationRateMegaCps;
69 
70 	if (XTalkCalDistance <= 0)
71 		Status = VL53L0X_ERROR_INVALID_PARAMS;
72 
73 	/* Disable the XTalk compensation */
74 	if (Status == VL53L0X_ERROR_NONE)
75 		Status = VL53L0X_SetXTalkCompensationEnable(Dev, 0);
76 
77 	/* Disable the RIT */
78 	if (Status == VL53L0X_ERROR_NONE) {
79 		Status = VL53L0X_SetLimitCheckEnable(Dev,
80 				VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
81 	}
82 
83 	/* Perform 50 measurements and compute the averages */
84 	if (Status == VL53L0X_ERROR_NONE) {
85 		sum_ranging = 0;
86 		sum_spads = 0;
87 		sum_signalRate = 0;
88 		total_count = 0;
89 		for (xtalk_meas = 0; xtalk_meas < 50; xtalk_meas++) {
90 			Status = VL53L0X_PerformSingleRangingMeasurement(Dev,
91 				&RangingMeasurementData);
92 
93 			if (Status != VL53L0X_ERROR_NONE)
94 				break;
95 
96 			/* The range is valid when RangeStatus = 0 */
97 			if (RangingMeasurementData.RangeStatus == 0) {
98 				sum_ranging = sum_ranging +
99 					RangingMeasurementData.RangeMilliMeter;
100 				sum_signalRate = sum_signalRate +
101 				RangingMeasurementData.SignalRateRtnMegaCps;
102 				sum_spads = sum_spads +
103 				RangingMeasurementData.EffectiveSpadRtnCount
104 					/ 256;
105 				total_count = total_count + 1;
106 			}
107 		}
108 
109 		/* no valid values found */
110 		if (total_count == 0)
111 			Status = VL53L0X_ERROR_RANGE_ERROR;
112 
113 	}
114 
115 
116 	if (Status == VL53L0X_ERROR_NONE) {
117 		/* FixPoint1616_t / uint16_t = FixPoint1616_t */
118 		xTalkStoredMeanSignalRate = sum_signalRate / total_count;
119 		xTalkStoredMeanRange = (FixPoint1616_t)((uint32_t)(
120 			sum_ranging << 16) / total_count);
121 		xTalkStoredMeanRtnSpads = (FixPoint1616_t)((uint32_t)(
122 			sum_spads << 16) / total_count);
123 
124 		/* Round Mean Spads to Whole Number.
125 		 * Typically the calculated mean SPAD count is a whole number
126 		 * or very close to a whole
127 		 * number, therefore any truncation will not result in a
128 		 * significant loss in accuracy.
129 		 * Also, for a grey target at a typical distance of around
130 		 * 400mm, around 220 SPADs will
131 		 * be enabled, therefore, any truncation will result in a loss
132 		 * of accuracy of less than
133 		 * 0.5%.
134 		 */
135 		xTalkStoredMeanRtnSpadsAsInt = (xTalkStoredMeanRtnSpads +
136 			0x8000) >> 16;
137 
138 		/* Round Cal Distance to Whole Number.
139 		 * Note that the cal distance is in mm, therefore no resolution
140 		 * is lost.*/
141 		 xTalkCalDistanceAsInt = (XTalkCalDistance + 0x8000) >> 16;
142 
143 		if (xTalkStoredMeanRtnSpadsAsInt == 0 ||
144 		   xTalkCalDistanceAsInt == 0 ||
145 		   xTalkStoredMeanRange >= XTalkCalDistance) {
146 			XTalkCompensationRateMegaCps = 0;
147 		} else {
148 			/* Round Cal Distance to Whole Number.
149 			   Note that the cal distance is in mm, therefore no
150 			   resolution is lost.*/
151 			xTalkCalDistanceAsInt = (XTalkCalDistance +
152 				0x8000) >> 16;
153 
154 			/* Apply division by mean spad count early in the
155 			 * calculation to keep the numbers small.
156 			 * This ensures we can maintain a 32bit calculation.
157 			 * Fixed1616 / int := Fixed1616 */
158 			signalXTalkTotalPerSpad = (xTalkStoredMeanSignalRate) /
159 				xTalkStoredMeanRtnSpadsAsInt;
160 
161 			/* Complete the calculation for total Signal XTalk per
162 			 * SPAD
163 			 * Fixed1616 * (Fixed1616 - Fixed1616/int) :=
164 			 * (2^16 * Fixed1616)
165 			 */
166 			signalXTalkTotalPerSpad *= ((1 << 16) -
167 				(xTalkStoredMeanRange / xTalkCalDistanceAsInt));
168 
169 			/* Round from 2^16 * Fixed1616, to Fixed1616. */
170 			XTalkCompensationRateMegaCps = (signalXTalkTotalPerSpad
171 				+ 0x8000) >> 16;
172 		}
173 
174 		*pXTalkCompensationRateMegaCps = XTalkCompensationRateMegaCps;
175 
176 		/* Enable the XTalk compensation */
177 		if (Status == VL53L0X_ERROR_NONE)
178 			Status = VL53L0X_SetXTalkCompensationEnable(Dev, 1);
179 
180 		/* Enable the XTalk compensation */
181 		if (Status == VL53L0X_ERROR_NONE)
182 			Status = VL53L0X_SetXTalkCompensationRateMegaCps(Dev,
183 					XTalkCompensationRateMegaCps);
184 
185 	}
186 
187 	return Status;
188 }
189 
VL53L0X_perform_offset_calibration(VL53L0X_DEV Dev,FixPoint1616_t CalDistanceMilliMeter,int32_t * pOffsetMicroMeter)190 VL53L0X_Error VL53L0X_perform_offset_calibration(VL53L0X_DEV Dev,
191 			FixPoint1616_t CalDistanceMilliMeter,
192 			int32_t *pOffsetMicroMeter)
193 {
194 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
195 	uint16_t sum_ranging = 0;
196 	FixPoint1616_t total_count = 0;
197 	VL53L0X_RangingMeasurementData_t RangingMeasurementData;
198 	FixPoint1616_t StoredMeanRange;
199 	uint32_t StoredMeanRangeAsInt;
200 	uint32_t CalDistanceAsInt_mm;
201 	uint8_t SequenceStepEnabled;
202 	int meas = 0;
203 
204 	if (CalDistanceMilliMeter <= 0)
205 		Status = VL53L0X_ERROR_INVALID_PARAMS;
206 
207 	if (Status == VL53L0X_ERROR_NONE)
208 		Status = VL53L0X_SetOffsetCalibrationDataMicroMeter(Dev, 0);
209 
210 
211 	/* Get the value of the TCC */
212 	if (Status == VL53L0X_ERROR_NONE)
213 		Status = VL53L0X_GetSequenceStepEnable(Dev,
214 				VL53L0X_SEQUENCESTEP_TCC, &SequenceStepEnabled);
215 
216 
217 	/* Disable the TCC */
218 	if (Status == VL53L0X_ERROR_NONE)
219 		Status = VL53L0X_SetSequenceStepEnable(Dev,
220 				VL53L0X_SEQUENCESTEP_TCC, 0);
221 
222 
223 	/* Disable the RIT */
224 	if (Status == VL53L0X_ERROR_NONE)
225 		Status = VL53L0X_SetLimitCheckEnable(Dev,
226 				VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
227 
228 	/* Perform 50 measurements and compute the averages */
229 	if (Status == VL53L0X_ERROR_NONE) {
230 		sum_ranging = 0;
231 		total_count = 0;
232 		for (meas = 0; meas < 50; meas++) {
233 			Status = VL53L0X_PerformSingleRangingMeasurement(Dev,
234 					&RangingMeasurementData);
235 
236 			if (Status != VL53L0X_ERROR_NONE)
237 				break;
238 
239 			/* The range is valid when RangeStatus = 0 */
240 			if (RangingMeasurementData.RangeStatus == 0) {
241 				sum_ranging = sum_ranging +
242 					RangingMeasurementData.RangeMilliMeter;
243 				total_count = total_count + 1;
244 			}
245 		}
246 
247 		/* no valid values found */
248 		if (total_count == 0)
249 			Status = VL53L0X_ERROR_RANGE_ERROR;
250 	}
251 
252 
253 	if (Status == VL53L0X_ERROR_NONE) {
254 		/* FixPoint1616_t / uint16_t = FixPoint1616_t */
255 		StoredMeanRange = (FixPoint1616_t)((uint32_t)(sum_ranging << 16)
256 			/ total_count);
257 
258 		StoredMeanRangeAsInt = (StoredMeanRange + 0x8000) >> 16;
259 
260 		/* Round Cal Distance to Whole Number.
261 		 * Note that the cal distance is in mm, therefore no resolution
262 		 * is lost.*/
263 		 CalDistanceAsInt_mm = (CalDistanceMilliMeter + 0x8000) >> 16;
264 
265 		 *pOffsetMicroMeter = (CalDistanceAsInt_mm -
266 				 StoredMeanRangeAsInt) * 1000;
267 
268 		/* Apply the calculated offset */
269 		if (Status == VL53L0X_ERROR_NONE) {
270 			VL53L0X_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
271 					*pOffsetMicroMeter);
272 			Status = VL53L0X_SetOffsetCalibrationDataMicroMeter(Dev,
273 					*pOffsetMicroMeter);
274 		}
275 
276 	}
277 
278 	/* Restore the TCC */
279 	if (Status == VL53L0X_ERROR_NONE) {
280 		if (SequenceStepEnabled != 0)
281 			Status = VL53L0X_SetSequenceStepEnable(Dev,
282 					VL53L0X_SEQUENCESTEP_TCC, 1);
283 	}
284 
285 	return Status;
286 }
287 
288 
VL53L0X_set_offset_calibration_data_micro_meter(VL53L0X_DEV Dev,int32_t OffsetCalibrationDataMicroMeter)289 VL53L0X_Error VL53L0X_set_offset_calibration_data_micro_meter(VL53L0X_DEV Dev,
290 		int32_t OffsetCalibrationDataMicroMeter)
291 {
292 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
293 	int32_t cMaxOffsetMicroMeter = 511000;
294 	int32_t cMinOffsetMicroMeter = -512000;
295 	int16_t cOffsetRange = 4096;
296 	uint32_t encodedOffsetVal;
297 
298 	LOG_FUNCTION_START("");
299 
300 	if (OffsetCalibrationDataMicroMeter > cMaxOffsetMicroMeter)
301 		OffsetCalibrationDataMicroMeter = cMaxOffsetMicroMeter;
302 	else if (OffsetCalibrationDataMicroMeter < cMinOffsetMicroMeter)
303 		OffsetCalibrationDataMicroMeter = cMinOffsetMicroMeter;
304 
305 	/* The offset register is 10.2 format and units are mm
306 	 * therefore conversion is applied by a division of
307 	 * 250.
308 	 */
309 	if (OffsetCalibrationDataMicroMeter >= 0) {
310 		encodedOffsetVal =
311 			OffsetCalibrationDataMicroMeter/250;
312 	} else {
313 		encodedOffsetVal =
314 			cOffsetRange +
315 			OffsetCalibrationDataMicroMeter/250;
316 	}
317 
318 	Status = VL53L0X_WrWord(Dev,
319 		VL53L0X_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
320 		encodedOffsetVal);
321 
322 	LOG_FUNCTION_END(Status);
323 	return Status;
324 }
325 
VL53L0X_get_offset_calibration_data_micro_meter(VL53L0X_DEV Dev,int32_t * pOffsetCalibrationDataMicroMeter)326 VL53L0X_Error VL53L0X_get_offset_calibration_data_micro_meter(VL53L0X_DEV Dev,
327 		int32_t *pOffsetCalibrationDataMicroMeter)
328 {
329 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
330 	uint16_t RangeOffsetRegister;
331 	int16_t cMaxOffset = 2047;
332 	int16_t cOffsetRange = 4096;
333 
334 	/* Note that offset has 10.2 format */
335 
336 	Status = VL53L0X_RdWord(Dev,
337 				VL53L0X_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
338 				&RangeOffsetRegister);
339 
340 	if (Status == VL53L0X_ERROR_NONE) {
341 		RangeOffsetRegister = (RangeOffsetRegister & 0x0fff);
342 
343 		/* Apply 12 bit 2's compliment conversion */
344 		if (RangeOffsetRegister > cMaxOffset)
345 			*pOffsetCalibrationDataMicroMeter =
346 				(int16_t)(RangeOffsetRegister - cOffsetRange)
347 					* 250;
348 		else
349 			*pOffsetCalibrationDataMicroMeter =
350 				(int16_t)RangeOffsetRegister * 250;
351 
352 	}
353 
354 	return Status;
355 }
356 
357 
VL53L0X_apply_offset_adjustment(VL53L0X_DEV Dev)358 VL53L0X_Error VL53L0X_apply_offset_adjustment(VL53L0X_DEV Dev)
359 {
360 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
361 	int32_t CorrectedOffsetMicroMeters;
362 	int32_t CurrentOffsetMicroMeters;
363 
364 	/* if we run on this function we can read all the NVM info
365 	 * used by the API */
366 	Status = VL53L0X_get_info_from_device(Dev, 7);
367 
368 	/* Read back current device offset */
369 	if (Status == VL53L0X_ERROR_NONE) {
370 		Status = VL53L0X_GetOffsetCalibrationDataMicroMeter(Dev,
371 					&CurrentOffsetMicroMeters);
372 	}
373 
374 	/* Apply Offset Adjustment derived from 400mm measurements */
375 	if (Status == VL53L0X_ERROR_NONE) {
376 
377 		/* Store initial device offset */
378 		PALDevDataSet(Dev, Part2PartOffsetNVMMicroMeter,
379 			CurrentOffsetMicroMeters);
380 
381 		CorrectedOffsetMicroMeters = CurrentOffsetMicroMeters +
382 			(int32_t)PALDevDataGet(Dev,
383 				Part2PartOffsetAdjustmentNVMMicroMeter);
384 
385 		Status = VL53L0X_SetOffsetCalibrationDataMicroMeter(Dev,
386 					CorrectedOffsetMicroMeters);
387 
388 		/* store current, adjusted offset */
389 		if (Status == VL53L0X_ERROR_NONE) {
390 			VL53L0X_SETPARAMETERFIELD(Dev, RangeOffsetMicroMeters,
391 					CorrectedOffsetMicroMeters);
392 		}
393 	}
394 
395 	return Status;
396 }
397 
get_next_good_spad(uint8_t goodSpadArray[],uint32_t size,uint32_t curr,int32_t * next)398 void get_next_good_spad(uint8_t goodSpadArray[], uint32_t size,
399 			uint32_t curr, int32_t *next)
400 {
401 	uint32_t startIndex;
402 	uint32_t fineOffset;
403 	uint32_t cSpadsPerByte = 8;
404 	uint32_t coarseIndex;
405 	uint32_t fineIndex;
406 	uint8_t dataByte;
407 	uint8_t success = 0;
408 
409 	/*
410 	 * Starting with the current good spad, loop through the array to find
411 	 * the next. i.e. the next bit set in the sequence.
412 	 *
413 	 * The coarse index is the byte index of the array and the fine index is
414 	 * the index of the bit within each byte.
415 	 */
416 
417 	*next = -1;
418 
419 	startIndex = curr / cSpadsPerByte;
420 	fineOffset = curr % cSpadsPerByte;
421 
422 	for (coarseIndex = startIndex; ((coarseIndex < size) && !success);
423 				coarseIndex++) {
424 		fineIndex = 0;
425 		dataByte = goodSpadArray[coarseIndex];
426 
427 		if (coarseIndex == startIndex) {
428 			/* locate the bit position of the provided current
429 			 * spad bit before iterating */
430 			dataByte >>= fineOffset;
431 			fineIndex = fineOffset;
432 		}
433 
434 		while (fineIndex < cSpadsPerByte) {
435 			if ((dataByte & 0x1) == 1) {
436 				success = 1;
437 				*next = coarseIndex * cSpadsPerByte + fineIndex;
438 				break;
439 			}
440 			dataByte >>= 1;
441 			fineIndex++;
442 		}
443 	}
444 }
445 
446 
is_aperture(uint32_t spadIndex)447 uint8_t is_aperture(uint32_t spadIndex)
448 {
449 	/*
450 	 * This function reports if a given spad index is an aperture SPAD by
451 	 * deriving the quadrant.
452 	 */
453 	uint32_t quadrant;
454 	uint8_t isAperture = 1;
455 	quadrant = spadIndex >> 6;
456 	if (refArrayQuadrants[quadrant] == REF_ARRAY_SPAD_0)
457 		isAperture = 0;
458 
459 	return isAperture;
460 }
461 
462 
enable_spad_bit(uint8_t spadArray[],uint32_t size,uint32_t spadIndex)463 VL53L0X_Error enable_spad_bit(uint8_t spadArray[], uint32_t size,
464 	uint32_t spadIndex)
465 {
466 	VL53L0X_Error status = VL53L0X_ERROR_NONE;
467 	uint32_t cSpadsPerByte = 8;
468 	uint32_t coarseIndex;
469 	uint32_t fineIndex;
470 
471 	coarseIndex = spadIndex / cSpadsPerByte;
472 	fineIndex = spadIndex % cSpadsPerByte;
473 	if (coarseIndex >= size)
474 		status = VL53L0X_ERROR_REF_SPAD_INIT;
475 	else
476 		spadArray[coarseIndex] |= (1 << fineIndex);
477 
478 	return status;
479 }
480 
count_enabled_spads(uint8_t spadArray[],uint32_t byteCount,uint32_t maxSpads,uint32_t * pTotalSpadsEnabled,uint8_t * pIsAperture)481 VL53L0X_Error count_enabled_spads(uint8_t spadArray[],
482 		uint32_t byteCount, uint32_t maxSpads,
483 		uint32_t *pTotalSpadsEnabled, uint8_t *pIsAperture)
484 {
485 	VL53L0X_Error status = VL53L0X_ERROR_NONE;
486 	uint32_t cSpadsPerByte = 8;
487 	uint32_t lastByte;
488 	uint32_t lastBit;
489 	uint32_t byteIndex = 0;
490 	uint32_t bitIndex = 0;
491 	uint8_t tempByte;
492 	uint8_t spadTypeIdentified = 0;
493 
494 	/* The entire array will not be used for spads, therefore the last
495 	 * byte and last bit is determined from the max spads value.
496 	 */
497 
498 	lastByte = maxSpads / cSpadsPerByte;
499 	lastBit = maxSpads % cSpadsPerByte;
500 
501 	/* Check that the max spads value does not exceed the array bounds. */
502 	if (lastByte >= byteCount)
503 		status = VL53L0X_ERROR_REF_SPAD_INIT;
504 
505 	*pTotalSpadsEnabled = 0;
506 
507 	/* Count the bits enabled in the whole bytes */
508 	for (byteIndex = 0; byteIndex <= (lastByte - 1); byteIndex++) {
509 		tempByte = spadArray[byteIndex];
510 
511 		for (bitIndex = 0; bitIndex <= cSpadsPerByte; bitIndex++) {
512 			if ((tempByte & 0x01) == 1) {
513 				(*pTotalSpadsEnabled)++;
514 
515 				if (!spadTypeIdentified) {
516 					*pIsAperture = 1;
517 					if ((byteIndex < 2) && (bitIndex < 4))
518 							*pIsAperture = 0;
519 					spadTypeIdentified = 1;
520 				}
521 			}
522 			tempByte >>= 1;
523 		}
524 	}
525 
526 	/* Count the number of bits enabled in the last byte accounting
527 	 * for the fact that not all bits in the byte may be used.
528 	 */
529 	tempByte = spadArray[lastByte];
530 
531 	for (bitIndex = 0; bitIndex <= lastBit; bitIndex++) {
532 		if ((tempByte & 0x01) == 1)
533 			(*pTotalSpadsEnabled)++;
534 	}
535 
536 	return status;
537 }
538 
set_ref_spad_map(VL53L0X_DEV Dev,uint8_t * refSpadArray)539 VL53L0X_Error set_ref_spad_map(VL53L0X_DEV Dev, uint8_t *refSpadArray)
540 {
541 	VL53L0X_Error status = VL53L0X_WriteMulti(Dev,
542 				VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
543 				refSpadArray, 6);
544 	return status;
545 }
546 
get_ref_spad_map(VL53L0X_DEV Dev,uint8_t * refSpadArray)547 VL53L0X_Error get_ref_spad_map(VL53L0X_DEV Dev, uint8_t *refSpadArray)
548 {
549 	VL53L0X_Error status = VL53L0X_ReadMulti(Dev,
550 				VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
551 				refSpadArray,
552 				6);
553 	return status;
554 }
555 
enable_ref_spads(VL53L0X_DEV Dev,uint8_t apertureSpads,uint8_t goodSpadArray[],uint8_t spadArray[],uint32_t size,uint32_t start,uint32_t offset,uint32_t spadCount,uint32_t * lastSpad)556 VL53L0X_Error enable_ref_spads(VL53L0X_DEV Dev,
557 				uint8_t apertureSpads,
558 				uint8_t goodSpadArray[],
559 				uint8_t spadArray[],
560 				uint32_t size,
561 				uint32_t start,
562 				uint32_t offset,
563 				uint32_t spadCount,
564 				uint32_t *lastSpad)
565 {
566 	VL53L0X_Error status = VL53L0X_ERROR_NONE;
567 	uint32_t index;
568 	uint32_t i;
569 	int32_t nextGoodSpad = offset;
570 	uint32_t currentSpad;
571 	uint8_t checkSpadArray[6];
572 
573 	/*
574 	 * This function takes in a spad array which may or may not have SPADS
575 	 * already enabled and appends from a given offset a requested number
576 	 * of new SPAD enables. The 'good spad map' is applied to
577 	 * determine the next SPADs to enable.
578 	 *
579 	 * This function applies to only aperture or only non-aperture spads.
580 	 * Checks are performed to ensure this.
581 	 */
582 
583 	currentSpad = offset;
584 	for (index = 0; index < spadCount; index++) {
585 		get_next_good_spad(goodSpadArray, size, currentSpad,
586 			&nextGoodSpad);
587 
588 		if (nextGoodSpad == -1) {
589 			status = VL53L0X_ERROR_REF_SPAD_INIT;
590 			break;
591 		}
592 
593 		/* Confirm that the next good SPAD is non-aperture */
594 		if (is_aperture(start + nextGoodSpad) != apertureSpads) {
595 			/* if we can't get the required number of good aperture
596 			 * spads from the current quadrant then this is an error
597 			 */
598 			status = VL53L0X_ERROR_REF_SPAD_INIT;
599 			break;
600 		}
601 		currentSpad = (uint32_t)nextGoodSpad;
602 		enable_spad_bit(spadArray, size, currentSpad);
603 		currentSpad++;
604 	}
605 	*lastSpad = currentSpad;
606 
607 	if (status == VL53L0X_ERROR_NONE)
608 		status = set_ref_spad_map(Dev, spadArray);
609 
610 
611 	if (status == VL53L0X_ERROR_NONE) {
612 		status = get_ref_spad_map(Dev, checkSpadArray);
613 
614 		i = 0;
615 
616 		/* Compare spad maps. If not equal report error. */
617 		while (i < size) {
618 			if (spadArray[i] != checkSpadArray[i]) {
619 				status = VL53L0X_ERROR_REF_SPAD_INIT;
620 				break;
621 			}
622 			i++;
623 		}
624 	}
625 	return status;
626 }
627 
628 
perform_ref_signal_measurement(VL53L0X_DEV Dev,uint16_t * refSignalRate)629 VL53L0X_Error perform_ref_signal_measurement(VL53L0X_DEV Dev,
630 		uint16_t *refSignalRate)
631 {
632 	VL53L0X_Error status = VL53L0X_ERROR_NONE;
633 	VL53L0X_RangingMeasurementData_t rangingMeasurementData;
634 
635 	uint8_t SequenceConfig = 0;
636 
637 	/* store the value of the sequence config,
638 	 * this will be reset before the end of the function
639 	 */
640 
641 	SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
642 
643 	/*
644 	 * This function performs a reference signal rate measurement.
645 	 */
646 	if (status == VL53L0X_ERROR_NONE)
647 		status = VL53L0X_WrByte(Dev,
648 			VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0xC0);
649 
650 	if (status == VL53L0X_ERROR_NONE)
651 		status = VL53L0X_PerformSingleRangingMeasurement(Dev,
652 				&rangingMeasurementData);
653 
654 	if (status == VL53L0X_ERROR_NONE)
655 		status = VL53L0X_WrByte(Dev, 0xFF, 0x01);
656 
657 	if (status == VL53L0X_ERROR_NONE)
658 		status = VL53L0X_RdWord(Dev,
659 			VL53L0X_REG_RESULT_PEAK_SIGNAL_RATE_REF,
660 			refSignalRate);
661 
662 	if (status == VL53L0X_ERROR_NONE)
663 		status = VL53L0X_WrByte(Dev, 0xFF, 0x00);
664 
665 	if (status == VL53L0X_ERROR_NONE) {
666 		/* restore the previous Sequence Config */
667 		status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
668 				SequenceConfig);
669 		if (status == VL53L0X_ERROR_NONE)
670 			PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
671 	}
672 
673 	return status;
674 }
675 
VL53L0X_perform_ref_spad_management(VL53L0X_DEV Dev,uint32_t * refSpadCount,uint8_t * isApertureSpads)676 VL53L0X_Error VL53L0X_perform_ref_spad_management(VL53L0X_DEV Dev,
677 				uint32_t *refSpadCount,
678 				uint8_t *isApertureSpads)
679 {
680 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
681 	uint8_t lastSpadArray[6];
682 	uint8_t startSelect = 0xB4;
683 	uint32_t minimumSpadCount = 3;
684 	uint32_t maxSpadCount = 44;
685 	uint32_t currentSpadIndex = 0;
686 	uint32_t lastSpadIndex = 0;
687 	int32_t nextGoodSpad = 0;
688 	uint16_t targetRefRate = 0x0A00; /* 20 MCPS in 9:7 format */
689 	uint16_t peakSignalRateRef;
690 	uint32_t needAptSpads = 0;
691 	uint32_t index = 0;
692 	uint32_t spadArraySize = 6;
693 	uint32_t signalRateDiff = 0;
694 	uint32_t lastSignalRateDiff = 0;
695 	uint8_t complete = 0;
696 	uint8_t VhvSettings = 0;
697 	uint8_t PhaseCal = 0;
698 	uint32_t refSpadCount_int = 0;
699 	uint8_t	 isApertureSpads_int = 0;
700 
701 	/*
702 	 * The reference SPAD initialization procedure determines the minimum
703 	 * amount of reference spads to be enables to achieve a target reference
704 	 * signal rate and should be performed once during initialization.
705 	 *
706 	 * Either aperture or non-aperture spads are applied but never both.
707 	 * Firstly non-aperture spads are set, begining with 5 spads, and
708 	 * increased one spad at a time until the closest measurement to the
709 	 * target rate is achieved.
710 	 *
711 	 * If the target rate is exceeded when 5 non-aperture spads are enabled,
712 	 * initialization is performed instead with aperture spads.
713 	 *
714 	 * When setting spads, a 'Good Spad Map' is applied.
715 	 *
716 	 * This procedure operates within a SPAD window of interest of a maximum
717 	 * 44 spads.
718 	 * The start point is currently fixed to 180, which lies towards the end
719 	 * of the non-aperture quadrant and runs in to the adjacent aperture
720 	 * quadrant.
721 	 */
722 
723 
724 	targetRefRate = PALDevDataGet(Dev, targetRefRate);
725 
726 	/*
727 	 * Initialize Spad arrays.
728 	 * Currently the good spad map is initialised to 'All good'.
729 	 * This is a short term implementation. The good spad map will be
730 	 * provided as an input.
731 	 * Note that there are 6 bytes. Only the first 44 bits will be used to
732 	 * represent spads.
733 	 */
734 	for (index = 0; index < spadArraySize; index++)
735 		Dev->Data.SpadData.RefSpadEnables[index] = 0;
736 
737 
738 	Status = VL53L0X_WrByte(Dev, 0xFF, 0x01);
739 
740 	if (Status == VL53L0X_ERROR_NONE)
741 		Status = VL53L0X_WrByte(Dev,
742 			VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
743 
744 	if (Status == VL53L0X_ERROR_NONE)
745 		Status = VL53L0X_WrByte(Dev,
746 			VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
747 
748 	if (Status == VL53L0X_ERROR_NONE)
749 		Status = VL53L0X_WrByte(Dev, 0xFF, 0x00);
750 
751 	if (Status == VL53L0X_ERROR_NONE)
752 		Status = VL53L0X_WrByte(Dev,
753 			VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
754 			startSelect);
755 
756 
757 	if (Status == VL53L0X_ERROR_NONE)
758 		Status = VL53L0X_WrByte(Dev,
759 				VL53L0X_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0);
760 
761 	/* Perform ref calibration */
762 	if (Status == VL53L0X_ERROR_NONE)
763 		Status = VL53L0X_perform_ref_calibration(Dev, &VhvSettings,
764 			&PhaseCal, 0);
765 
766 	if (Status == VL53L0X_ERROR_NONE) {
767 		/* Enable Minimum NON-APERTURE Spads */
768 		currentSpadIndex = 0;
769 		lastSpadIndex = currentSpadIndex;
770 		needAptSpads = 0;
771 		Status = enable_ref_spads(Dev,
772 					needAptSpads,
773 					Dev->Data.SpadData.RefGoodSpadMap,
774 					Dev->Data.SpadData.RefSpadEnables,
775 					spadArraySize,
776 					startSelect,
777 					currentSpadIndex,
778 					minimumSpadCount,
779 					&lastSpadIndex);
780 	}
781 
782 	if (Status == VL53L0X_ERROR_NONE) {
783 		currentSpadIndex = lastSpadIndex;
784 
785 		Status = perform_ref_signal_measurement(Dev,
786 			&peakSignalRateRef);
787 		if ((Status == VL53L0X_ERROR_NONE) &&
788 			(peakSignalRateRef > targetRefRate)) {
789 			/* Signal rate measurement too high,
790 			 * switch to APERTURE SPADs */
791 
792 			for (index = 0; index < spadArraySize; index++)
793 				Dev->Data.SpadData.RefSpadEnables[index] = 0;
794 
795 
796 			/* Increment to the first APERTURE spad */
797 			while ((is_aperture(startSelect + currentSpadIndex)
798 				== 0) && (currentSpadIndex < maxSpadCount)) {
799 				currentSpadIndex++;
800 			}
801 
802 			needAptSpads = 1;
803 
804 			Status = enable_ref_spads(Dev,
805 					needAptSpads,
806 					Dev->Data.SpadData.RefGoodSpadMap,
807 					Dev->Data.SpadData.RefSpadEnables,
808 					spadArraySize,
809 					startSelect,
810 					currentSpadIndex,
811 					minimumSpadCount,
812 					&lastSpadIndex);
813 
814 			if (Status == VL53L0X_ERROR_NONE) {
815 				currentSpadIndex = lastSpadIndex;
816 				Status = perform_ref_signal_measurement(Dev,
817 						&peakSignalRateRef);
818 
819 				if ((Status == VL53L0X_ERROR_NONE) &&
820 					(peakSignalRateRef > targetRefRate)) {
821 					/* Signal rate still too high after
822 					 * setting the minimum number of
823 					 * APERTURE spads. Can do no more
824 					 * therefore set the min number of
825 					 * aperture spads as the result.
826 					 */
827 					isApertureSpads_int = 1;
828 					refSpadCount_int = minimumSpadCount;
829 				}
830 			}
831 		} else {
832 			needAptSpads = 0;
833 		}
834 	}
835 
836 	if ((Status == VL53L0X_ERROR_NONE) &&
837 		(peakSignalRateRef < targetRefRate)) {
838 		/* At this point, the minimum number of either aperture
839 		 * or non-aperture spads have been set. Proceed to add
840 		 * spads and perform measurements until the target
841 		 * reference is reached.
842 		 */
843 		isApertureSpads_int = needAptSpads;
844 		refSpadCount_int	= minimumSpadCount;
845 
846 		memcpy(lastSpadArray, Dev->Data.SpadData.RefSpadEnables,
847 				spadArraySize);
848 		lastSignalRateDiff = abs(peakSignalRateRef -
849 			targetRefRate);
850 		complete = 0;
851 
852 		while (!complete) {
853 			get_next_good_spad(
854 				Dev->Data.SpadData.RefGoodSpadMap,
855 				spadArraySize, currentSpadIndex,
856 				&nextGoodSpad);
857 
858 			if (nextGoodSpad == -1) {
859 				Status = VL53L0X_ERROR_REF_SPAD_INIT;
860 				break;
861 			}
862 
863 			/* Cannot combine Aperture and Non-Aperture spads, so
864 			 * ensure the current spad is of the correct type.
865 			 */
866 			if (is_aperture((uint32_t)startSelect + nextGoodSpad) !=
867 					needAptSpads) {
868 				/* At this point we have enabled the maximum
869 				 * number of Aperture spads.
870 				 */
871 				complete = 1;
872 				break;
873 			}
874 
875 			(refSpadCount_int)++;
876 
877 			currentSpadIndex = nextGoodSpad;
878 			Status = enable_spad_bit(
879 					Dev->Data.SpadData.RefSpadEnables,
880 					spadArraySize, currentSpadIndex);
881 
882 			if (Status == VL53L0X_ERROR_NONE) {
883 				currentSpadIndex++;
884 				/* Proceed to apply the additional spad and
885 				 * perform measurement. */
886 				Status = set_ref_spad_map(Dev,
887 					Dev->Data.SpadData.RefSpadEnables);
888 			}
889 
890 			if (Status != VL53L0X_ERROR_NONE)
891 				break;
892 
893 			Status = perform_ref_signal_measurement(Dev,
894 					&peakSignalRateRef);
895 
896 			if (Status != VL53L0X_ERROR_NONE)
897 				break;
898 
899 			signalRateDiff = abs(peakSignalRateRef - targetRefRate);
900 
901 			if (peakSignalRateRef > targetRefRate) {
902 				/* Select the spad map that provides the
903 				 * measurement closest to the target rate,
904 				 * either above or below it.
905 				 */
906 				if (signalRateDiff > lastSignalRateDiff) {
907 					/* Previous spad map produced a closer
908 					 * measurement, so choose this. */
909 					Status = set_ref_spad_map(Dev,
910 							lastSpadArray);
911 					memcpy(
912 					Dev->Data.SpadData.RefSpadEnables,
913 					lastSpadArray, spadArraySize);
914 
915 					(refSpadCount_int)--;
916 				}
917 				complete = 1;
918 			} else {
919 				/* Continue to add spads */
920 				lastSignalRateDiff = signalRateDiff;
921 				memcpy(lastSpadArray,
922 					Dev->Data.SpadData.RefSpadEnables,
923 					spadArraySize);
924 			}
925 
926 		} /* while */
927 	}
928 
929 	if (Status == VL53L0X_ERROR_NONE) {
930 		*refSpadCount = refSpadCount_int;
931 		*isApertureSpads = isApertureSpads_int;
932 
933 		VL53L0X_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
934 		VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
935 			ReferenceSpadCount, (uint8_t)(*refSpadCount));
936 		VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
937 			ReferenceSpadType, *isApertureSpads);
938 	}
939 
940 	return Status;
941 }
942 
VL53L0X_set_reference_spads(VL53L0X_DEV Dev,uint32_t count,uint8_t isApertureSpads)943 VL53L0X_Error VL53L0X_set_reference_spads(VL53L0X_DEV Dev,
944 				 uint32_t count, uint8_t isApertureSpads)
945 {
946 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
947 	uint32_t currentSpadIndex = 0;
948 	uint8_t startSelect = 0xB4;
949 	uint32_t spadArraySize = 6;
950 	uint32_t maxSpadCount = 44;
951 	uint32_t lastSpadIndex;
952 	uint32_t index;
953 
954 	/*
955 	 * This function applies a requested number of reference spads, either
956 	 * aperture or
957 	 * non-aperture, as requested.
958 	 * The good spad map will be applied.
959 	 */
960 
961 	Status = VL53L0X_WrByte(Dev, 0xFF, 0x01);
962 
963 	if (Status == VL53L0X_ERROR_NONE)
964 		Status = VL53L0X_WrByte(Dev,
965 			VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
966 
967 	if (Status == VL53L0X_ERROR_NONE)
968 		Status = VL53L0X_WrByte(Dev,
969 			VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
970 
971 	if (Status == VL53L0X_ERROR_NONE)
972 		Status = VL53L0X_WrByte(Dev, 0xFF, 0x00);
973 
974 	if (Status == VL53L0X_ERROR_NONE)
975 		Status = VL53L0X_WrByte(Dev,
976 			VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
977 			startSelect);
978 
979 	for (index = 0; index < spadArraySize; index++)
980 		Dev->Data.SpadData.RefSpadEnables[index] = 0;
981 
982 	if (isApertureSpads) {
983 		/* Increment to the first APERTURE spad */
984 		while ((is_aperture(startSelect + currentSpadIndex) == 0) &&
985 			  (currentSpadIndex < maxSpadCount)) {
986 			currentSpadIndex++;
987 		}
988 	}
989 	Status = enable_ref_spads(Dev,
990 				isApertureSpads,
991 				Dev->Data.SpadData.RefGoodSpadMap,
992 				Dev->Data.SpadData.RefSpadEnables,
993 				spadArraySize,
994 				startSelect,
995 				currentSpadIndex,
996 				count,
997 				&lastSpadIndex);
998 
999 	if (Status == VL53L0X_ERROR_NONE) {
1000 		VL53L0X_SETDEVICESPECIFICPARAMETER(Dev, RefSpadsInitialised, 1);
1001 		VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1002 			ReferenceSpadCount, (uint8_t)(count));
1003 		VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1004 			ReferenceSpadType, isApertureSpads);
1005 	}
1006 
1007 	return Status;
1008 }
1009 
VL53L0X_get_reference_spads(VL53L0X_DEV Dev,uint32_t * pSpadCount,uint8_t * pIsApertureSpads)1010 VL53L0X_Error VL53L0X_get_reference_spads(VL53L0X_DEV Dev,
1011 			uint32_t *pSpadCount, uint8_t *pIsApertureSpads)
1012 {
1013 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1014 	uint8_t refSpadsInitialised;
1015 	uint8_t refSpadArray[6];
1016 	uint32_t cMaxSpadCount = 44;
1017 	uint32_t cSpadArraySize = 6;
1018 	uint32_t spadsEnabled;
1019 	uint8_t isApertureSpads = 0;
1020 
1021 	refSpadsInitialised = VL53L0X_GETDEVICESPECIFICPARAMETER(Dev,
1022 					RefSpadsInitialised);
1023 
1024 	if (refSpadsInitialised == 1) {
1025 
1026 		*pSpadCount = (uint32_t)VL53L0X_GETDEVICESPECIFICPARAMETER(Dev,
1027 			ReferenceSpadCount);
1028 		*pIsApertureSpads = VL53L0X_GETDEVICESPECIFICPARAMETER(Dev,
1029 			ReferenceSpadType);
1030 	} else {
1031 
1032 		/* obtain spad info from device.*/
1033 		Status = get_ref_spad_map(Dev, refSpadArray);
1034 
1035 		if (Status == VL53L0X_ERROR_NONE) {
1036 			/* count enabled spads within spad map array and
1037 			 * determine if Aperture or Non-Aperture.
1038 			 */
1039 			Status = count_enabled_spads(refSpadArray,
1040 							cSpadArraySize,
1041 							cMaxSpadCount,
1042 							&spadsEnabled,
1043 							&isApertureSpads);
1044 
1045 			if (Status == VL53L0X_ERROR_NONE) {
1046 
1047 				*pSpadCount = spadsEnabled;
1048 				*pIsApertureSpads = isApertureSpads;
1049 
1050 				VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1051 					RefSpadsInitialised, 1);
1052 				VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1053 					ReferenceSpadCount,
1054 					(uint8_t)spadsEnabled);
1055 				VL53L0X_SETDEVICESPECIFICPARAMETER(Dev,
1056 					ReferenceSpadType, isApertureSpads);
1057 			}
1058 		}
1059 	}
1060 
1061 	return Status;
1062 }
1063 
1064 
VL53L0X_perform_single_ref_calibration(VL53L0X_DEV Dev,uint8_t vhv_init_byte)1065 VL53L0X_Error VL53L0X_perform_single_ref_calibration(VL53L0X_DEV Dev,
1066 		uint8_t vhv_init_byte)
1067 {
1068 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1069 
1070 	if (Status == VL53L0X_ERROR_NONE)
1071 		Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSRANGE_START,
1072 				VL53L0X_REG_SYSRANGE_MODE_START_STOP |
1073 				vhv_init_byte);
1074 
1075 	if (Status == VL53L0X_ERROR_NONE)
1076 		Status = VL53L0X_measurement_poll_for_completion(Dev);
1077 
1078 	if (Status == VL53L0X_ERROR_NONE)
1079 		Status = VL53L0X_ClearInterruptMask(Dev, 0);
1080 
1081 	if (Status == VL53L0X_ERROR_NONE)
1082 		Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSRANGE_START, 0x00);
1083 
1084 	return Status;
1085 }
1086 
1087 
VL53L0X_ref_calibration_io(VL53L0X_DEV Dev,uint8_t read_not_write,uint8_t VhvSettings,uint8_t PhaseCal,uint8_t * pVhvSettings,uint8_t * pPhaseCal,const uint8_t vhv_enable,const uint8_t phase_enable)1088 VL53L0X_Error VL53L0X_ref_calibration_io(VL53L0X_DEV Dev, uint8_t read_not_write,
1089 	uint8_t VhvSettings, uint8_t PhaseCal,
1090 	uint8_t *pVhvSettings, uint8_t *pPhaseCal,
1091 	const uint8_t vhv_enable, const uint8_t phase_enable)
1092 {
1093 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1094 	uint8_t PhaseCalint = 0;
1095 
1096 	/* Read VHV from device */
1097 	Status |= VL53L0X_WrByte(Dev, 0xFF, 0x01);
1098 	Status |= VL53L0X_WrByte(Dev, 0x00, 0x00);
1099 	Status |= VL53L0X_WrByte(Dev, 0xFF, 0x00);
1100 
1101 	if (read_not_write) {
1102 		if (vhv_enable)
1103 			Status |= VL53L0X_RdByte(Dev, 0xCB, pVhvSettings);
1104 		if (phase_enable)
1105 			Status |= VL53L0X_RdByte(Dev, 0xEE, &PhaseCalint);
1106 	} else {
1107 		if (vhv_enable)
1108 			Status |= VL53L0X_WrByte(Dev, 0xCB, VhvSettings);
1109 		if (phase_enable)
1110 			Status |= VL53L0X_UpdateByte(Dev, 0xEE, 0x80, PhaseCal);
1111 	}
1112 
1113 	Status |= VL53L0X_WrByte(Dev, 0xFF, 0x01);
1114 	Status |= VL53L0X_WrByte(Dev, 0x00, 0x01);
1115 	Status |= VL53L0X_WrByte(Dev, 0xFF, 0x00);
1116 
1117 	*pPhaseCal = (uint8_t)(PhaseCalint&0xEF);
1118 
1119 	return Status;
1120 }
1121 
1122 
VL53L0X_perform_vhv_calibration(VL53L0X_DEV Dev,uint8_t * pVhvSettings,const uint8_t get_data_enable,const uint8_t restore_config)1123 VL53L0X_Error VL53L0X_perform_vhv_calibration(VL53L0X_DEV Dev,
1124 	uint8_t *pVhvSettings, const uint8_t get_data_enable,
1125 	const uint8_t restore_config)
1126 {
1127 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1128 	uint8_t SequenceConfig = 0;
1129 	uint8_t VhvSettings = 0;
1130 	uint8_t PhaseCal = 0;
1131 	uint8_t PhaseCalInt = 0;
1132 
1133 	/* store the value of the sequence config,
1134 	 * this will be reset before the end of the function
1135 	 */
1136 
1137 	if (restore_config)
1138 		SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
1139 
1140 	/* Run VHV */
1141 	Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0x01);
1142 
1143 	if (Status == VL53L0X_ERROR_NONE)
1144 		Status = VL53L0X_perform_single_ref_calibration(Dev, 0x40);
1145 
1146 	/* Read VHV from device */
1147 	if ((Status == VL53L0X_ERROR_NONE) && (get_data_enable == 1)) {
1148 		Status = VL53L0X_ref_calibration_io(Dev, 1,
1149 			VhvSettings, PhaseCal, /* Not used here */
1150 			pVhvSettings, &PhaseCalInt,
1151 			1, 0);
1152 	} else
1153 		*pVhvSettings = 0;
1154 
1155 
1156 	if ((Status == VL53L0X_ERROR_NONE) && restore_config) {
1157 		/* restore the previous Sequence Config */
1158 		Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
1159 				SequenceConfig);
1160 		if (Status == VL53L0X_ERROR_NONE)
1161 			PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
1162 
1163 	}
1164 
1165 	return Status;
1166 }
1167 
VL53L0X_perform_phase_calibration(VL53L0X_DEV Dev,uint8_t * pPhaseCal,const uint8_t get_data_enable,const uint8_t restore_config)1168 VL53L0X_Error VL53L0X_perform_phase_calibration(VL53L0X_DEV Dev,
1169 	uint8_t *pPhaseCal, const uint8_t get_data_enable,
1170 	const uint8_t restore_config)
1171 {
1172 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1173 	uint8_t SequenceConfig = 0;
1174 	uint8_t VhvSettings = 0;
1175 	uint8_t PhaseCal = 0;
1176 	uint8_t VhvSettingsint;
1177 
1178 	/* store the value of the sequence config,
1179 	 * this will be reset before the end of the function
1180 	 */
1181 
1182 	if (restore_config)
1183 		SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
1184 
1185 	/* Run PhaseCal */
1186 	Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0x02);
1187 
1188 	if (Status == VL53L0X_ERROR_NONE)
1189 		Status = VL53L0X_perform_single_ref_calibration(Dev, 0x0);
1190 
1191 	/* Read PhaseCal from device */
1192 	if ((Status == VL53L0X_ERROR_NONE) && (get_data_enable == 1)) {
1193 		Status = VL53L0X_ref_calibration_io(Dev, 1,
1194 			VhvSettings, PhaseCal, /* Not used here */
1195 			&VhvSettingsint, pPhaseCal,
1196 			0, 1);
1197 	} else
1198 		*pPhaseCal = 0;
1199 
1200 
1201 	if ((Status == VL53L0X_ERROR_NONE) && restore_config) {
1202 		/* restore the previous Sequence Config */
1203 		Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
1204 				SequenceConfig);
1205 		if (Status == VL53L0X_ERROR_NONE)
1206 			PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
1207 
1208 	}
1209 
1210 	return Status;
1211 }
1212 
VL53L0X_perform_ref_calibration(VL53L0X_DEV Dev,uint8_t * pVhvSettings,uint8_t * pPhaseCal,uint8_t get_data_enable)1213 VL53L0X_Error VL53L0X_perform_ref_calibration(VL53L0X_DEV Dev,
1214 	uint8_t *pVhvSettings, uint8_t *pPhaseCal, uint8_t get_data_enable)
1215 {
1216 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1217 	uint8_t SequenceConfig = 0;
1218 
1219 	/* store the value of the sequence config,
1220 	 * this will be reset before the end of the function
1221 	 */
1222 
1223 	SequenceConfig = PALDevDataGet(Dev, SequenceConfig);
1224 
1225 	/* In the following function we don't save the config to optimize
1226 	 * writes on device. Config is saved and restored only once. */
1227 	Status = VL53L0X_perform_vhv_calibration(
1228 			Dev, pVhvSettings, get_data_enable, 0);
1229 
1230 
1231 	if (Status == VL53L0X_ERROR_NONE)
1232 		Status = VL53L0X_perform_phase_calibration(
1233 			Dev, pPhaseCal, get_data_enable, 0);
1234 
1235 
1236 	if (Status == VL53L0X_ERROR_NONE) {
1237 		/* restore the previous Sequence Config */
1238 		Status = VL53L0X_WrByte(Dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
1239 				SequenceConfig);
1240 		if (Status == VL53L0X_ERROR_NONE)
1241 			PALDevDataSet(Dev, SequenceConfig, SequenceConfig);
1242 
1243 	}
1244 
1245 	return Status;
1246 }
1247 
VL53L0X_set_ref_calibration(VL53L0X_DEV Dev,uint8_t VhvSettings,uint8_t PhaseCal)1248 VL53L0X_Error VL53L0X_set_ref_calibration(VL53L0X_DEV Dev,
1249 		uint8_t VhvSettings, uint8_t PhaseCal)
1250 {
1251 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1252 	uint8_t pVhvSettings;
1253 	uint8_t pPhaseCal;
1254 
1255 	Status = VL53L0X_ref_calibration_io(Dev, 0,
1256 		VhvSettings, PhaseCal,
1257 		&pVhvSettings, &pPhaseCal,
1258 		1, 1);
1259 
1260 	return Status;
1261 }
1262 
VL53L0X_get_ref_calibration(VL53L0X_DEV Dev,uint8_t * pVhvSettings,uint8_t * pPhaseCal)1263 VL53L0X_Error VL53L0X_get_ref_calibration(VL53L0X_DEV Dev,
1264 		uint8_t *pVhvSettings, uint8_t *pPhaseCal)
1265 {
1266 	VL53L0X_Error Status = VL53L0X_ERROR_NONE;
1267 	uint8_t VhvSettings = 0;
1268 	uint8_t PhaseCal = 0;
1269 
1270 	Status = VL53L0X_ref_calibration_io(Dev, 1,
1271 		VhvSettings, PhaseCal,
1272 		pVhvSettings, pPhaseCal,
1273 		1, 1);
1274 
1275 	return Status;
1276 }
1277