Workshop example

Dependencies:   X_NUCLEO_COMMON ST_INTERFACES

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers VL53L0X.cpp Source File

VL53L0X.cpp

00001 /**
00002  ******************************************************************************
00003  * @file    VL53L0X_class.cpp
00004  * @author  IMG
00005  * @version V0.0.1
00006  * @date    28-June-2016
00007  * @brief   Implementation file for the VL53L0X driver class
00008  ******************************************************************************
00009  * @attention
00010  *
00011  * <h2><center>&copy; COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
00012  *
00013  * Redistribution and use in source and binary forms, with or without modification,
00014  * are permitted provided that the following conditions are met:
00015  *   1. Redistributions of source code must retain the above copyright notice,
00016  *      this list of conditions and the following disclaimer.
00017  *   2. Redistributions in binary form must reproduce the above copyright notice,
00018  *      this list of conditions and the following disclaimer in the documentation
00019  *      and/or other materials provided with the distribution.
00020  *   3. Neither the name of STMicroelectronics nor the names of its contributors
00021  *      may be used to endorse or promote products derived from this software
00022  *      without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00025  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00027  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
00030  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00032  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00033  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00034  *
00035  ******************************************************************************
00036 */
00037 
00038 /* Includes */
00039 #include <stdlib.h>
00040 
00041 #include "VL53L0X.h"
00042 
00043 //#include "VL53L0X_api_core.h"
00044 //#include "VL53L0X_api_calibration.h"
00045 //#include "VL53L0X_api_strings.h"
00046 #include "VL53L0X_interrupt_threshold_settings.h"
00047 #include "VL53L0X_tuning.h"
00048 #include "VL53L0X_types.h"
00049 
00050 
00051 /****************** define for i2c configuration *******************************/
00052 
00053 #define TEMP_BUF_SIZE   64
00054 
00055 /** Maximum buffer size to be used in i2c */
00056 #define VL53L0X_MAX_I2C_XFER_SIZE   64 /* Maximum buffer size to be used in i2c */
00057 #define VL53L0X_I2C_USER_VAR         /* none but could be for a flag var to get/pass to mutex interruptible  return flags and try again */
00058 
00059 
00060 #define LOG_FUNCTION_START(fmt, ...) \
00061     _LOG_FUNCTION_START(TRACE_MODULE_API, fmt, ##__VA_ARGS__)
00062 #define LOG_FUNCTION_END(status, ...) \
00063     _LOG_FUNCTION_END(TRACE_MODULE_API, status, ##__VA_ARGS__)
00064 #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
00065     _LOG_FUNCTION_END_FMT(TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
00066 
00067 #ifdef VL53L0X_LOG_ENABLE
00068 #define trace_print(level, ...) trace_print_module_function(TRACE_MODULE_API, \
00069     level, TRACE_FUNCTION_NONE, ##__VA_ARGS__)
00070 #endif
00071 
00072 #define REF_ARRAY_SPAD_0  0
00073 #define REF_ARRAY_SPAD_5  5
00074 #define REF_ARRAY_SPAD_10 10
00075 
00076 uint32_t refArrayQuadrants[4] = {REF_ARRAY_SPAD_10, REF_ARRAY_SPAD_5,
00077                                  REF_ARRAY_SPAD_0, REF_ARRAY_SPAD_5
00078                                 };
00079 
00080 
00081 
00082 
00083 VL53L0X_Error VL53L0X::VL53L0X_device_read_strobe(VL53L0X_DEV dev)
00084 {
00085     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00086     uint8_t strobe;
00087     uint32_t loop_nb;
00088     LOG_FUNCTION_START("");
00089 
00090     status |= VL53L0X_write_byte(dev, 0x83, 0x00);
00091 
00092     /* polling
00093      * use timeout to avoid deadlock*/
00094     if (status == VL53L0X_ERROR_NONE) {
00095         loop_nb = 0;
00096         do {
00097             status = VL53L0X_read_byte(dev, 0x83, &strobe);
00098             if ((strobe != 0x00) || status != VL53L0X_ERROR_NONE) {
00099                 break;
00100             }
00101 
00102             loop_nb = loop_nb + 1;
00103         } while (loop_nb < VL53L0X_DEFAULT_MAX_LOOP);
00104 
00105         if (loop_nb >= VL53L0X_DEFAULT_MAX_LOOP) {
00106             status = VL53L0X_ERROR_TIME_OUT;
00107         }
00108     }
00109 
00110     status |= VL53L0X_write_byte(dev, 0x83, 0x01);
00111 
00112     LOG_FUNCTION_END(status);
00113     return status;
00114 }
00115 
00116 VL53L0X_Error VL53L0X::VL53L0X_get_info_from_device(VL53L0X_DEV dev, uint8_t option)
00117 {
00118     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00119     uint8_t byte;
00120     uint32_t tmp_dword;
00121     uint8_t module_id;
00122     uint8_t revision;
00123     uint8_t reference_spad_count = 0;
00124     uint8_t reference_spad_type = 0;
00125     uint32_t part_uid_upper = 0;
00126     uint32_t part_uid_lower = 0;
00127     uint32_t offset_fixed1104_mm = 0;
00128     int16_t offset_micro_meters = 0;
00129     uint32_t dist_meas_tgt_fixed1104_mm = 400 << 4;
00130     uint32_t dist_meas_fixed1104_400_mm = 0;
00131     uint32_t signal_rate_meas_fixed1104_400_mm = 0;
00132     char product_id[19];
00133     char *product_id_tmp;
00134     uint8_t read_data_from_device_done;
00135     FixPoint1616_t signal_rate_meas_fixed400_mm_fix = 0;
00136     uint8_t nvm_ref_good_spad_map[VL53L0X_REF_SPAD_BUFFER_SIZE];
00137     int i;
00138 
00139 
00140     LOG_FUNCTION_START("");
00141 
00142     read_data_from_device_done = VL53L0X_GETDEVICESPECIFICPARAMETER(dev,
00143                                  ReadDataFromDeviceDone);
00144 
00145     /* This access is done only once after that a GetDeviceInfo or
00146      * datainit is done*/
00147     if (read_data_from_device_done != 7) {
00148 
00149         status |= VL53L0X_write_byte(dev, 0x80, 0x01);
00150         status |= VL53L0X_write_byte(dev, 0xFF, 0x01);
00151         status |= VL53L0X_write_byte(dev, 0x00, 0x00);
00152 
00153         status |= VL53L0X_write_byte(dev, 0xFF, 0x06);
00154         status |= VL53L0X_read_byte(dev, 0x83, &byte);
00155         status |= VL53L0X_write_byte(dev, 0x83, byte | 4);
00156         status |= VL53L0X_write_byte(dev, 0xFF, 0x07);
00157         status |= VL53L0X_write_byte(dev, 0x81, 0x01);
00158 
00159         status |= VL53L0X_polling_delay(dev);
00160 
00161         status |= VL53L0X_write_byte(dev, 0x80, 0x01);
00162 
00163         if (((option & 1) == 1) &&
00164                 ((read_data_from_device_done & 1) == 0)) {
00165             status |= VL53L0X_write_byte(dev, 0x94, 0x6b);
00166             status |= VL53L0X_device_read_strobe(dev);
00167             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00168 
00169             reference_spad_count = (uint8_t)((tmp_dword >> 8) & 0x07f);
00170             reference_spad_type  = (uint8_t)((tmp_dword >> 15) & 0x01);
00171 
00172             status |= VL53L0X_write_byte(dev, 0x94, 0x24);
00173             status |= VL53L0X_device_read_strobe(dev);
00174             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00175 
00176 
00177             nvm_ref_good_spad_map[0] = (uint8_t)((tmp_dword >> 24)
00178                                                  & 0xff);
00179             nvm_ref_good_spad_map[1] = (uint8_t)((tmp_dword >> 16)
00180                                                  & 0xff);
00181             nvm_ref_good_spad_map[2] = (uint8_t)((tmp_dword >> 8)
00182                                                  & 0xff);
00183             nvm_ref_good_spad_map[3] = (uint8_t)(tmp_dword & 0xff);
00184 
00185             status |= VL53L0X_write_byte(dev, 0x94, 0x25);
00186             status |= VL53L0X_device_read_strobe(dev);
00187             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00188 
00189             nvm_ref_good_spad_map[4] = (uint8_t)((tmp_dword >> 24)
00190                                                  & 0xff);
00191             nvm_ref_good_spad_map[5] = (uint8_t)((tmp_dword >> 16)
00192                                                  & 0xff);
00193         }
00194 
00195         if (((option & 2) == 2) &&
00196                 ((read_data_from_device_done & 2) == 0)) {
00197 
00198             status |= VL53L0X_write_byte(dev, 0x94, 0x02);
00199             status |= VL53L0X_device_read_strobe(dev);
00200             status |= VL53L0X_read_byte(dev, 0x90, &module_id);
00201 
00202             status |= VL53L0X_write_byte(dev, 0x94, 0x7B);
00203             status |= VL53L0X_device_read_strobe(dev);
00204             status |= VL53L0X_read_byte(dev, 0x90, &revision);
00205 
00206             status |= VL53L0X_write_byte(dev, 0x94, 0x77);
00207             status |= VL53L0X_device_read_strobe(dev);
00208             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00209 
00210             product_id[0] = (char)((tmp_dword >> 25) & 0x07f);
00211             product_id[1] = (char)((tmp_dword >> 18) & 0x07f);
00212             product_id[2] = (char)((tmp_dword >> 11) & 0x07f);
00213             product_id[3] = (char)((tmp_dword >> 4) & 0x07f);
00214 
00215             byte = (uint8_t)((tmp_dword & 0x00f) << 3);
00216 
00217             status |= VL53L0X_write_byte(dev, 0x94, 0x78);
00218             status |= VL53L0X_device_read_strobe(dev);
00219             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00220 
00221             product_id[4] = (char)(byte +
00222                                    ((tmp_dword >> 29) & 0x07f));
00223             product_id[5] = (char)((tmp_dword >> 22) & 0x07f);
00224             product_id[6] = (char)((tmp_dword >> 15) & 0x07f);
00225             product_id[7] = (char)((tmp_dword >> 8) & 0x07f);
00226             product_id[8] = (char)((tmp_dword >> 1) & 0x07f);
00227 
00228             byte = (uint8_t)((tmp_dword & 0x001) << 6);
00229 
00230             status |= VL53L0X_write_byte(dev, 0x94, 0x79);
00231 
00232             status |= VL53L0X_device_read_strobe(dev);
00233 
00234             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00235 
00236             product_id[9] = (char)(byte +
00237                                    ((tmp_dword >> 26) & 0x07f));
00238             product_id[10] = (char)((tmp_dword >> 19) & 0x07f);
00239             product_id[11] = (char)((tmp_dword >> 12) & 0x07f);
00240             product_id[12] = (char)((tmp_dword >> 5) & 0x07f);
00241 
00242             byte = (uint8_t)((tmp_dword & 0x01f) << 2);
00243 
00244             status |= VL53L0X_write_byte(dev, 0x94, 0x7A);
00245 
00246             status |= VL53L0X_device_read_strobe(dev);
00247 
00248             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00249 
00250             product_id[13] = (char)(byte +
00251                                     ((tmp_dword >> 30) & 0x07f));
00252             product_id[14] = (char)((tmp_dword >> 23) & 0x07f);
00253             product_id[15] = (char)((tmp_dword >> 16) & 0x07f);
00254             product_id[16] = (char)((tmp_dword >> 9) & 0x07f);
00255             product_id[17] = (char)((tmp_dword >> 2) & 0x07f);
00256             product_id[18] = '\0';
00257 
00258         }
00259 
00260         if (((option & 4) == 4) &&
00261                 ((read_data_from_device_done & 4) == 0)) {
00262 
00263             status |= VL53L0X_write_byte(dev, 0x94, 0x7B);
00264             status |= VL53L0X_device_read_strobe(dev);
00265             status |= VL53L0X_read_dword(dev, 0x90, &part_uid_upper);
00266 
00267             status |= VL53L0X_write_byte(dev, 0x94, 0x7C);
00268             status |= VL53L0X_device_read_strobe(dev);
00269             status |= VL53L0X_read_dword(dev, 0x90, &part_uid_lower);
00270 
00271             status |= VL53L0X_write_byte(dev, 0x94, 0x73);
00272             status |= VL53L0X_device_read_strobe(dev);
00273             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00274 
00275             signal_rate_meas_fixed1104_400_mm = (tmp_dword &
00276                                                  0x0000000ff) << 8;
00277 
00278             status |= VL53L0X_write_byte(dev, 0x94, 0x74);
00279             status |= VL53L0X_device_read_strobe(dev);
00280             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00281 
00282             signal_rate_meas_fixed1104_400_mm |= ((tmp_dword &
00283                                                    0xff000000) >> 24);
00284 
00285             status |= VL53L0X_write_byte(dev, 0x94, 0x75);
00286             status |= VL53L0X_device_read_strobe(dev);
00287             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00288 
00289             dist_meas_fixed1104_400_mm = (tmp_dword & 0x0000000ff)
00290                                          << 8;
00291 
00292             status |= VL53L0X_write_byte(dev, 0x94, 0x76);
00293             status |= VL53L0X_device_read_strobe(dev);
00294             status |= VL53L0X_read_dword(dev, 0x90, &tmp_dword);
00295 
00296             dist_meas_fixed1104_400_mm |= ((tmp_dword & 0xff000000)
00297                                            >> 24);
00298         }
00299 
00300         status |= VL53L0X_write_byte(dev, 0x81, 0x00);
00301         status |= VL53L0X_write_byte(dev, 0xFF, 0x06);
00302         status |= VL53L0X_read_byte(dev, 0x83, &byte);
00303         status |= VL53L0X_write_byte(dev, 0x83, byte & 0xfb);
00304         status |= VL53L0X_write_byte(dev, 0xFF, 0x01);
00305         status |= VL53L0X_write_byte(dev, 0x00, 0x01);
00306 
00307         status |= VL53L0X_write_byte(dev, 0xFF, 0x00);
00308         status |= VL53L0X_write_byte(dev, 0x80, 0x00);
00309     }
00310 
00311     if ((status == VL53L0X_ERROR_NONE) &&
00312             (read_data_from_device_done != 7)) {
00313         /* Assign to variable if status is ok */
00314         if (((option & 1) == 1) &&
00315                 ((read_data_from_device_done & 1) == 0)) {
00316             VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
00317                                                ReferenceSpadCount, reference_spad_count);
00318 
00319             VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
00320                                                ReferenceSpadType, reference_spad_type);
00321 
00322             for (i = 0; i < VL53L0X_REF_SPAD_BUFFER_SIZE; i++) {
00323                 dev->Data .SpadData .RefGoodSpadMap [i] =
00324                     nvm_ref_good_spad_map[i];
00325             }
00326         }
00327 
00328         if (((option & 2) == 2) &&
00329                 ((read_data_from_device_done & 2) == 0)) {
00330             VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
00331                                                ModuleId, module_id);
00332 
00333             VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
00334                                                Revision, revision);
00335 
00336             product_id_tmp = VL53L0X_GETDEVICESPECIFICPARAMETER(dev,
00337                              ProductId);
00338             VL53L0X_COPYSTRING(product_id_tmp, product_id);
00339 
00340         }
00341 
00342         if (((option & 4) == 4) &&
00343                 ((read_data_from_device_done & 4) == 0)) {
00344             VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
00345                                                PartUIDUpper, part_uid_upper);
00346 
00347             VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
00348                                                PartUIDLower, part_uid_lower);
00349 
00350             signal_rate_meas_fixed400_mm_fix =
00351                 VL53L0X_FIXPOINT97TOFIXPOINT1616(
00352                     signal_rate_meas_fixed1104_400_mm);
00353 
00354             VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
00355                                                SignalRateMeasFixed400mm,
00356                                                signal_rate_meas_fixed400_mm_fix);
00357 
00358             offset_micro_meters = 0;
00359             if (dist_meas_fixed1104_400_mm != 0) {
00360                 offset_fixed1104_mm =
00361                     dist_meas_fixed1104_400_mm -
00362                     dist_meas_tgt_fixed1104_mm;
00363                 offset_micro_meters = (offset_fixed1104_mm
00364                                        * 1000) >> 4;
00365                 offset_micro_meters *= -1;
00366             }
00367 
00368             PALDevDataSet(dev,
00369                           Part2PartOffsetAdjustmentNVMMicroMeter,
00370                           offset_micro_meters);
00371         }
00372         byte = (uint8_t)(read_data_from_device_done | option);
00373         VL53L0X_SETDEVICESPECIFICPARAMETER(dev, ReadDataFromDeviceDone,
00374                                            byte);
00375     }
00376 
00377     LOG_FUNCTION_END(status);
00378     return status;
00379 }
00380 
00381 VL53L0X_Error VL53L0X::wrapped_VL53L0X_get_offset_calibration_data_micro_meter(VL53L0X_DEV dev,
00382         int32_t *p_offset_calibration_data_micro_meter)
00383 {
00384     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00385     uint16_t range_offset_register;
00386     int16_t c_max_offset = 2047;
00387     int16_t c_offset_range = 4096;
00388 
00389     /* Note that offset has 10.2 format */
00390 
00391     status = VL53L0X_read_word(dev,
00392                                VL53L0X_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
00393                                &range_offset_register);
00394 
00395     if (status == VL53L0X_ERROR_NONE) {
00396         range_offset_register = (range_offset_register & 0x0fff);
00397 
00398         /* Apply 12 bit 2's compliment conversion */
00399         if (range_offset_register > c_max_offset) {
00400             *p_offset_calibration_data_micro_meter =
00401                 (int16_t)(range_offset_register - c_offset_range)
00402                 * 250;
00403         } else {
00404             *p_offset_calibration_data_micro_meter =
00405                 (int16_t)range_offset_register * 250;
00406         }
00407 
00408     }
00409 
00410     return status;
00411 }
00412 
00413 VL53L0X_Error VL53L0X::VL53L0X_get_offset_calibration_data_micro_meter(VL53L0X_DEV dev,
00414         int32_t *p_offset_calibration_data_micro_meter)
00415 {
00416     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00417     LOG_FUNCTION_START("");
00418 
00419     status = wrapped_VL53L0X_get_offset_calibration_data_micro_meter(dev,
00420              p_offset_calibration_data_micro_meter);
00421 
00422     LOG_FUNCTION_END(status);
00423     return status;
00424 }
00425 
00426 VL53L0X_Error VL53L0X::wrapped_VL53L0X_set_offset_calibration_data_micro_meter(VL53L0X_DEV dev,
00427         int32_t offset_calibration_data_micro_meter)
00428 {
00429     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00430     int32_t c_max_offset_micro_meter = 511000;
00431     int32_t c_min_offset_micro_meter = -512000;
00432     int16_t c_offset_range = 4096;
00433     uint32_t encoded_offset_val;
00434 
00435     LOG_FUNCTION_START("");
00436 
00437     if (offset_calibration_data_micro_meter > c_max_offset_micro_meter) {
00438         offset_calibration_data_micro_meter = c_max_offset_micro_meter;
00439     } else {
00440         if (offset_calibration_data_micro_meter < c_min_offset_micro_meter) {
00441             offset_calibration_data_micro_meter = c_min_offset_micro_meter;
00442         }
00443     }
00444 
00445     /* The offset register is 10.2 format and units are mm
00446      * therefore conversion is applied by a division of
00447      * 250.
00448      */
00449     if (offset_calibration_data_micro_meter >= 0) {
00450         encoded_offset_val =
00451             offset_calibration_data_micro_meter / 250;
00452     } else {
00453         encoded_offset_val =
00454             c_offset_range +
00455             offset_calibration_data_micro_meter / 250;
00456     }
00457 
00458     status = VL53L0X_write_word(dev,
00459                                 VL53L0X_REG_ALGO_PART_TO_PART_RANGE_OFFSET_MM,
00460                                 encoded_offset_val);
00461 
00462     LOG_FUNCTION_END(status);
00463     return status;
00464 }
00465 
00466 VL53L0X_Error VL53L0X::VL53L0X_set_offset_calibration_data_micro_meter(VL53L0X_DEV dev,
00467         int32_t offset_calibration_data_micro_meter)
00468 {
00469     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00470     LOG_FUNCTION_START("");
00471 
00472     status = wrapped_VL53L0X_set_offset_calibration_data_micro_meter(dev,
00473              offset_calibration_data_micro_meter);
00474 
00475     LOG_FUNCTION_END(status);
00476     return status;
00477 }
00478 
00479 VL53L0X_Error VL53L0X::VL53L0X_apply_offset_adjustment(VL53L0X_DEV dev)
00480 {
00481     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00482     int32_t corrected_offset_micro_meters;
00483     int32_t current_offset_micro_meters;
00484 
00485     /* if we run on this function we can read all the NVM info
00486      * used by the API */
00487     status = VL53L0X_get_info_from_device(dev, 7);
00488 
00489     /* Read back current device offset */
00490     if (status == VL53L0X_ERROR_NONE) {
00491         status = VL53L0X_get_offset_calibration_data_micro_meter(dev,
00492                  &current_offset_micro_meters);
00493     }
00494 
00495     /* Apply Offset Adjustment derived from 400mm measurements */
00496     if (status == VL53L0X_ERROR_NONE) {
00497 
00498         /* Store initial device offset */
00499         PALDevDataSet(dev, Part2PartOffsetNVMMicroMeter,
00500                       current_offset_micro_meters);
00501 
00502         corrected_offset_micro_meters = current_offset_micro_meters +
00503                                         (int32_t)PALDevDataGet(dev,
00504                                                 Part2PartOffsetAdjustmentNVMMicroMeter);
00505 
00506         status = VL53L0X_set_offset_calibration_data_micro_meter(dev,
00507                  corrected_offset_micro_meters);
00508 
00509         /* store current, adjusted offset */
00510         if (status == VL53L0X_ERROR_NONE) {
00511             VL53L0X_SETPARAMETERFIELD(dev, RangeOffsetMicroMeters,
00512                                       corrected_offset_micro_meters);
00513         }
00514     }
00515 
00516     return status;
00517 }
00518 
00519 VL53L0X_Error VL53L0X::VL53L0X_get_device_mode(VL53L0X_DEV dev,
00520         VL53L0X_DeviceModes *p_device_mode)
00521 {
00522     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00523     LOG_FUNCTION_START("");
00524 
00525     VL53L0X_GETPARAMETERFIELD(dev, DeviceMode, *p_device_mode);
00526 
00527     LOG_FUNCTION_END(status);
00528     return status;
00529 }
00530 
00531 VL53L0X_Error VL53L0X::VL53L0X_get_inter_measurement_period_milli_seconds(VL53L0X_DEV dev,
00532         uint32_t *p_inter_measurement_period_milli_seconds)
00533 {
00534     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00535     uint16_t osc_calibrate_val;
00536     uint32_t im_period_milli_seconds;
00537 
00538     LOG_FUNCTION_START("");
00539 
00540     status = VL53L0X_read_word(dev, VL53L0X_REG_OSC_CALIBRATE_VAL,
00541                                &osc_calibrate_val);
00542 
00543     if (status == VL53L0X_ERROR_NONE) {
00544         status = VL53L0X_read_dword(dev,
00545                                     VL53L0X_REG_SYSTEM_INTERMEASUREMENT_PERIOD,
00546                                     &im_period_milli_seconds);
00547     }
00548 
00549     if (status == VL53L0X_ERROR_NONE) {
00550         if (osc_calibrate_val != 0) {
00551             *p_inter_measurement_period_milli_seconds =
00552                 im_period_milli_seconds / osc_calibrate_val;
00553         }
00554         VL53L0X_SETPARAMETERFIELD(dev,
00555                                   InterMeasurementPeriodMilliSeconds,
00556                                   *p_inter_measurement_period_milli_seconds);
00557     }
00558 
00559     LOG_FUNCTION_END(status);
00560     return status;
00561 }
00562 
00563 VL53L0X_Error VL53L0X::VL53L0X_get_x_talk_compensation_rate_mega_cps(VL53L0X_DEV dev,
00564         FixPoint1616_t *p_xtalk_compensation_rate_mega_cps)
00565 {
00566     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00567     uint16_t value;
00568     FixPoint1616_t temp_fix1616;
00569 
00570     LOG_FUNCTION_START("");
00571 
00572     status = VL53L0X_read_word(dev,
00573                                VL53L0X_REG_CROSSTALK_COMPENSATION_PEAK_RATE_MCPS, (uint16_t *)&value);
00574     if (status == VL53L0X_ERROR_NONE) {
00575         if (value == 0) {
00576             /* the Xtalk is disabled return value from memory */
00577             VL53L0X_GETPARAMETERFIELD(dev,
00578                                       XTalkCompensationRateMegaCps, temp_fix1616);
00579             *p_xtalk_compensation_rate_mega_cps = temp_fix1616;
00580             VL53L0X_SETPARAMETERFIELD(dev, XTalkCompensationEnable,
00581                                       0);
00582         } else {
00583             temp_fix1616 = VL53L0X_FIXPOINT313TOFIXPOINT1616(value);
00584             *p_xtalk_compensation_rate_mega_cps = temp_fix1616;
00585             VL53L0X_SETPARAMETERFIELD(dev,
00586                                       XTalkCompensationRateMegaCps, temp_fix1616);
00587             VL53L0X_SETPARAMETERFIELD(dev, XTalkCompensationEnable,
00588                                       1);
00589         }
00590     }
00591 
00592     LOG_FUNCTION_END(status);
00593     return status;
00594 }
00595 
00596 VL53L0X_Error VL53L0X::VL53L0X_get_limit_check_value(VL53L0X_DEV dev, uint16_t limit_check_id,
00597         FixPoint1616_t *p_limit_check_value)
00598 {
00599     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00600     uint8_t enable_zero_value = 0;
00601     uint16_t temp16;
00602     FixPoint1616_t temp_fix1616;
00603 
00604     LOG_FUNCTION_START("");
00605 
00606     switch (limit_check_id) {
00607 
00608         case VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE:
00609             /* internal computation: */
00610             VL53L0X_GETARRAYPARAMETERFIELD(dev, LimitChecksValue,
00611                                            VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, temp_fix1616);
00612             enable_zero_value = 0;
00613             break;
00614 
00615         case VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
00616             status = VL53L0X_read_word(dev,
00617                                        VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
00618                                        &temp16);
00619             if (status == VL53L0X_ERROR_NONE) {
00620                 temp_fix1616 = VL53L0X_FIXPOINT97TOFIXPOINT1616(temp16);
00621             }
00622 
00623 
00624             enable_zero_value = 1;
00625             break;
00626 
00627         case VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP:
00628             /* internal computation: */
00629             VL53L0X_GETARRAYPARAMETERFIELD(dev, LimitChecksValue,
00630                                            VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP, temp_fix1616);
00631             enable_zero_value = 0;
00632             break;
00633 
00634         case VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
00635             /* internal computation: */
00636             VL53L0X_GETARRAYPARAMETERFIELD(dev, LimitChecksValue,
00637                                            VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, temp_fix1616);
00638             enable_zero_value = 0;
00639             break;
00640 
00641         case VL53L0X_CHECKENABLE_SIGNAL_RATE_MSRC:
00642         case VL53L0X_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
00643             status = VL53L0X_read_word(dev,
00644                                        VL53L0X_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT,
00645                                        &temp16);
00646             if (status == VL53L0X_ERROR_NONE) {
00647                 temp_fix1616 = VL53L0X_FIXPOINT97TOFIXPOINT1616(temp16);
00648             }
00649 
00650 
00651             enable_zero_value = 0;
00652             break;
00653 
00654         default:
00655             status = VL53L0X_ERROR_INVALID_PARAMS;
00656 
00657     }
00658 
00659     if (status == VL53L0X_ERROR_NONE) {
00660 
00661         if (enable_zero_value == 1) {
00662 
00663             if (temp_fix1616 == 0) {
00664                 /* disabled: return value from memory */
00665                 VL53L0X_GETARRAYPARAMETERFIELD(dev,
00666                                                LimitChecksValue, limit_check_id,
00667                                                temp_fix1616);
00668                 *p_limit_check_value = temp_fix1616;
00669                 VL53L0X_SETARRAYPARAMETERFIELD(dev,
00670                                                LimitChecksEnable, limit_check_id, 0);
00671             } else {
00672                 *p_limit_check_value = temp_fix1616;
00673                 VL53L0X_SETARRAYPARAMETERFIELD(dev,
00674                                                LimitChecksValue, limit_check_id,
00675                                                temp_fix1616);
00676                 VL53L0X_SETARRAYPARAMETERFIELD(dev,
00677                                                LimitChecksEnable, limit_check_id, 1);
00678             }
00679         } else {
00680             *p_limit_check_value = temp_fix1616;
00681         }
00682     }
00683 
00684     LOG_FUNCTION_END(status);
00685     return status;
00686 
00687 }
00688 
00689 VL53L0X_Error VL53L0X::VL53L0X_get_limit_check_enable(VL53L0X_DEV dev, uint16_t limit_check_id,
00690         uint8_t *p_limit_check_enable)
00691 {
00692     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00693     uint8_t temp8;
00694 
00695     LOG_FUNCTION_START("");
00696 
00697     if (limit_check_id >= VL53L0X_CHECKENABLE_NUMBER_OF_CHECKS) {
00698         status = VL53L0X_ERROR_INVALID_PARAMS;
00699         *p_limit_check_enable = 0;
00700     } else {
00701         VL53L0X_GETARRAYPARAMETERFIELD(dev, LimitChecksEnable,
00702                                        limit_check_id, temp8);
00703         *p_limit_check_enable = temp8;
00704     }
00705 
00706     LOG_FUNCTION_END(status);
00707     return status;
00708 }
00709 
00710 VL53L0X_Error VL53L0X::VL53L0X_get_wrap_around_check_enable(VL53L0X_DEV dev,
00711         uint8_t *p_wrap_around_check_enable)
00712 {
00713     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00714     uint8_t data;
00715 
00716     LOG_FUNCTION_START("");
00717 
00718     status = VL53L0X_read_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, &data);
00719     if (status == VL53L0X_ERROR_NONE) {
00720         PALDevDataSet(dev, SequenceConfig, data);
00721         if (data & (0x01 << 7)) {
00722             *p_wrap_around_check_enable = 0x01;
00723         } else {
00724             *p_wrap_around_check_enable = 0x00;
00725         }
00726     }
00727     if (status == VL53L0X_ERROR_NONE) {
00728         VL53L0X_SETPARAMETERFIELD(dev, WrapAroundCheckEnable,
00729                                   *p_wrap_around_check_enable);
00730     }
00731 
00732     LOG_FUNCTION_END(status);
00733     return status;
00734 }
00735 
00736 VL53L0X_Error VL53L0X::sequence_step_enabled(VL53L0X_DEV dev,
00737         VL53L0X_SequenceStepId sequence_step_id, uint8_t sequence_config,
00738         uint8_t *p_sequence_step_enabled)
00739 {
00740     VL53L0X_Error Status = VL53L0X_ERROR_NONE;
00741     *p_sequence_step_enabled = 0;
00742     LOG_FUNCTION_START("");
00743 
00744     switch (sequence_step_id) {
00745         case VL53L0X_SEQUENCESTEP_TCC:
00746             *p_sequence_step_enabled = (sequence_config & 0x10) >> 4;
00747             break;
00748         case VL53L0X_SEQUENCESTEP_DSS:
00749             *p_sequence_step_enabled = (sequence_config & 0x08) >> 3;
00750             break;
00751         case VL53L0X_SEQUENCESTEP_MSRC:
00752             *p_sequence_step_enabled = (sequence_config & 0x04) >> 2;
00753             break;
00754         case VL53L0X_SEQUENCESTEP_PRE_RANGE:
00755             *p_sequence_step_enabled = (sequence_config & 0x40) >> 6;
00756             break;
00757         case VL53L0X_SEQUENCESTEP_FINAL_RANGE:
00758             *p_sequence_step_enabled = (sequence_config & 0x80) >> 7;
00759             break;
00760         default:
00761             Status = VL53L0X_ERROR_INVALID_PARAMS;
00762     }
00763 
00764     LOG_FUNCTION_END(status);
00765     return Status;
00766 }
00767 
00768 VL53L0X_Error VL53L0X::VL53L0X_get_sequence_step_enables(VL53L0X_DEV dev,
00769         VL53L0X_SchedulerSequenceSteps_t *p_scheduler_sequence_steps)
00770 {
00771     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00772     uint8_t sequence_config = 0;
00773     LOG_FUNCTION_START("");
00774 
00775     status = VL53L0X_read_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
00776                                &sequence_config);
00777 
00778     if (status == VL53L0X_ERROR_NONE) {
00779         status = sequence_step_enabled(dev,
00780                                        VL53L0X_SEQUENCESTEP_TCC, sequence_config,
00781                                        &p_scheduler_sequence_steps->TccOn);
00782     }
00783     if (status == VL53L0X_ERROR_NONE) {
00784         status = sequence_step_enabled(dev,
00785                                        VL53L0X_SEQUENCESTEP_DSS, sequence_config,
00786                                        &p_scheduler_sequence_steps->DssOn);
00787     }
00788     if (status == VL53L0X_ERROR_NONE) {
00789         status = sequence_step_enabled(dev,
00790                                        VL53L0X_SEQUENCESTEP_MSRC, sequence_config,
00791                                        &p_scheduler_sequence_steps->MsrcOn);
00792     }
00793     if (status == VL53L0X_ERROR_NONE) {
00794         status = sequence_step_enabled(dev,
00795                                        VL53L0X_SEQUENCESTEP_PRE_RANGE, sequence_config,
00796                                        &p_scheduler_sequence_steps->PreRangeOn);
00797     }
00798     if (status == VL53L0X_ERROR_NONE) {
00799         status = sequence_step_enabled(dev,
00800                                        VL53L0X_SEQUENCESTEP_FINAL_RANGE, sequence_config,
00801                                        &p_scheduler_sequence_steps->FinalRangeOn);
00802     }
00803 
00804     LOG_FUNCTION_END(status);
00805     return status;
00806 }
00807 
00808 uint8_t VL53L0X::VL53L0X_decode_vcsel_period(uint8_t vcsel_period_reg)
00809 {
00810     /*!
00811      * Converts the encoded VCSEL period register value into the real
00812      * period in PLL clocks
00813      */
00814 
00815     uint8_t vcsel_period_pclks = 0;
00816 
00817     vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
00818 
00819     return vcsel_period_pclks;
00820 }
00821 
00822 uint8_t VL53L0X::lv53l0x_encode_vcsel_period(uint8_t vcsel_period_pclks)
00823 {
00824     /*!
00825      * Converts the encoded VCSEL period register value into the real period
00826      * in PLL clocks
00827      */
00828 
00829     uint8_t vcsel_period_reg = 0;
00830 
00831     vcsel_period_reg = (vcsel_period_pclks >> 1) - 1;
00832 
00833     return vcsel_period_reg;
00834 }
00835 
00836 
00837 VL53L0X_Error VL53L0X::wrapped_VL53L0X_set_vcsel_pulse_period(VL53L0X_DEV dev,
00838         VL53L0X_VcselPeriod vcsel_period_type, uint8_t vcsel_pulse_period_pclk)
00839 {
00840     VL53L0X_Error status = VL53L0X_ERROR_NONE;
00841     uint8_t vcsel_period_reg;
00842     uint8_t min_pre_vcsel_period_pclk = 12;
00843     uint8_t max_pre_vcsel_period_pclk = 18;
00844     uint8_t min_final_vcsel_period_pclk = 8;
00845     uint8_t max_final_vcsel_period_pclk = 14;
00846     uint32_t measurement_timing_budget_micro_seconds;
00847     uint32_t final_range_timeout_micro_seconds;
00848     uint32_t pre_range_timeout_micro_seconds;
00849     uint32_t msrc_timeout_micro_seconds;
00850     uint8_t phase_cal_int = 0;
00851 
00852     /* Check if valid clock period requested */
00853 
00854     if ((vcsel_pulse_period_pclk % 2) != 0) {
00855         /* Value must be an even number */
00856         status = VL53L0X_ERROR_INVALID_PARAMS;
00857     } else if (vcsel_period_type == VL53L0X_VCSEL_PERIOD_PRE_RANGE &&
00858                (vcsel_pulse_period_pclk < min_pre_vcsel_period_pclk ||
00859                 vcsel_pulse_period_pclk > max_pre_vcsel_period_pclk)) {
00860         status = VL53L0X_ERROR_INVALID_PARAMS;
00861     } else if (vcsel_period_type == VL53L0X_VCSEL_PERIOD_FINAL_RANGE &&
00862                (vcsel_pulse_period_pclk < min_final_vcsel_period_pclk ||
00863                 vcsel_pulse_period_pclk > max_final_vcsel_period_pclk)) {
00864 
00865         status = VL53L0X_ERROR_INVALID_PARAMS;
00866     }
00867 
00868     /* Apply specific settings for the requested clock period */
00869 
00870     if (status != VL53L0X_ERROR_NONE) {
00871         return status;
00872     }
00873 
00874 
00875     if (vcsel_period_type == VL53L0X_VCSEL_PERIOD_PRE_RANGE) {
00876 
00877         /* Set phase check limits */
00878         if (vcsel_pulse_period_pclk == 12) {
00879 
00880             status = VL53L0X_write_byte(dev,
00881                                         VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
00882                                         0x18);
00883             status = VL53L0X_write_byte(dev,
00884                                         VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
00885                                         0x08);
00886         } else if (vcsel_pulse_period_pclk == 14) {
00887 
00888             status = VL53L0X_write_byte(dev,
00889                                         VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
00890                                         0x30);
00891             status = VL53L0X_write_byte(dev,
00892                                         VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
00893                                         0x08);
00894         } else if (vcsel_pulse_period_pclk == 16) {
00895 
00896             status = VL53L0X_write_byte(dev,
00897                                         VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
00898                                         0x40);
00899             status = VL53L0X_write_byte(dev,
00900                                         VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
00901                                         0x08);
00902         } else if (vcsel_pulse_period_pclk == 18) {
00903 
00904             status = VL53L0X_write_byte(dev,
00905                                         VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_HIGH,
00906                                         0x50);
00907             status = VL53L0X_write_byte(dev,
00908                                         VL53L0X_REG_PRE_RANGE_CONFIG_VALID_PHASE_LOW,
00909                                         0x08);
00910         }
00911     } else if (vcsel_period_type == VL53L0X_VCSEL_PERIOD_FINAL_RANGE) {
00912 
00913         if (vcsel_pulse_period_pclk == 8) {
00914 
00915             status = VL53L0X_write_byte(dev,
00916                                         VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
00917                                         0x10);
00918             status = VL53L0X_write_byte(dev,
00919                                         VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
00920                                         0x08);
00921 
00922             status |= VL53L0X_write_byte(dev,
00923                                          VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x02);
00924             status |= VL53L0X_write_byte(dev,
00925                                          VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x0C);
00926 
00927             status |= VL53L0X_write_byte(dev, 0xff, 0x01);
00928             status |= VL53L0X_write_byte(dev,
00929                                          VL53L0X_REG_ALGO_PHASECAL_LIM,
00930                                          0x30);
00931             status |= VL53L0X_write_byte(dev, 0xff, 0x00);
00932         } else if (vcsel_pulse_period_pclk == 10) {
00933 
00934             status = VL53L0X_write_byte(dev,
00935                                         VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
00936                                         0x28);
00937             status = VL53L0X_write_byte(dev,
00938                                         VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
00939                                         0x08);
00940 
00941             status |= VL53L0X_write_byte(dev,
00942                                          VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
00943             status |= VL53L0X_write_byte(dev,
00944                                          VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x09);
00945 
00946             status |= VL53L0X_write_byte(dev, 0xff, 0x01);
00947             status |= VL53L0X_write_byte(dev,
00948                                          VL53L0X_REG_ALGO_PHASECAL_LIM,
00949                                          0x20);
00950             status |= VL53L0X_write_byte(dev, 0xff, 0x00);
00951         } else if (vcsel_pulse_period_pclk == 12) {
00952 
00953             status = VL53L0X_write_byte(dev,
00954                                         VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
00955                                         0x38);
00956             status = VL53L0X_write_byte(dev,
00957                                         VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
00958                                         0x08);
00959 
00960             status |= VL53L0X_write_byte(dev,
00961                                          VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
00962             status |= VL53L0X_write_byte(dev,
00963                                          VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x08);
00964 
00965             status |= VL53L0X_write_byte(dev, 0xff, 0x01);
00966             status |= VL53L0X_write_byte(dev,
00967                                          VL53L0X_REG_ALGO_PHASECAL_LIM,
00968                                          0x20);
00969             status |= VL53L0X_write_byte(dev, 0xff, 0x00);
00970         } else if (vcsel_pulse_period_pclk == 14) {
00971 
00972             status = VL53L0X_write_byte(dev,
00973                                         VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_HIGH,
00974                                         0x048);
00975             status = VL53L0X_write_byte(dev,
00976                                         VL53L0X_REG_FINAL_RANGE_CONFIG_VALID_PHASE_LOW,
00977                                         0x08);
00978 
00979             status |= VL53L0X_write_byte(dev,
00980                                          VL53L0X_REG_GLOBAL_CONFIG_VCSEL_WIDTH, 0x03);
00981             status |= VL53L0X_write_byte(dev,
00982                                          VL53L0X_REG_ALGO_PHASECAL_CONFIG_TIMEOUT, 0x07);
00983 
00984             status |= VL53L0X_write_byte(dev, 0xff, 0x01);
00985             status |= VL53L0X_write_byte(dev,
00986                                          VL53L0X_REG_ALGO_PHASECAL_LIM,
00987                                          0x20);
00988             status |= VL53L0X_write_byte(dev, 0xff, 0x00);
00989         }
00990     }
00991 
00992 
00993     /* Re-calculate and apply timeouts, in macro periods */
00994 
00995     if (status == VL53L0X_ERROR_NONE) {
00996         vcsel_period_reg = lv53l0x_encode_vcsel_period((uint8_t)
00997                            vcsel_pulse_period_pclk);
00998 
00999         /* When the VCSEL period for the pre or final range is changed,
01000         * the corresponding timeout must be read from the device using
01001         * the current VCSEL period, then the new VCSEL period can be
01002         * applied. The timeout then must be written back to the device
01003         * using the new VCSEL period.
01004         *
01005         * For the MSRC timeout, the same applies - this timeout being
01006         * dependant on the pre-range vcsel period.
01007         */
01008         switch (vcsel_period_type) {
01009             case VL53L0X_VCSEL_PERIOD_PRE_RANGE:
01010                 status = get_sequence_step_timeout(dev,
01011                                                    VL53L0X_SEQUENCESTEP_PRE_RANGE,
01012                                                    &pre_range_timeout_micro_seconds);
01013 
01014                 if (status == VL53L0X_ERROR_NONE)
01015                     status = get_sequence_step_timeout(dev,
01016                                                        VL53L0X_SEQUENCESTEP_MSRC,
01017                                                        &msrc_timeout_micro_seconds);
01018 
01019                 if (status == VL53L0X_ERROR_NONE)
01020                     status = VL53L0X_write_byte(dev,
01021                                                 VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
01022                                                 vcsel_period_reg);
01023 
01024 
01025                 if (status == VL53L0X_ERROR_NONE)
01026                     status = set_sequence_step_timeout(dev,
01027                                                        VL53L0X_SEQUENCESTEP_PRE_RANGE,
01028                                                        pre_range_timeout_micro_seconds);
01029 
01030 
01031                 if (status == VL53L0X_ERROR_NONE)
01032                     status = set_sequence_step_timeout(dev,
01033                                                        VL53L0X_SEQUENCESTEP_MSRC,
01034                                                        msrc_timeout_micro_seconds);
01035 
01036                 VL53L0X_SETDEVICESPECIFICPARAMETER(
01037                     dev,
01038                     PreRangeVcselPulsePeriod,
01039                     vcsel_pulse_period_pclk);
01040                 break;
01041             case VL53L0X_VCSEL_PERIOD_FINAL_RANGE:
01042                 status = get_sequence_step_timeout(dev,
01043                                                    VL53L0X_SEQUENCESTEP_FINAL_RANGE,
01044                                                    &final_range_timeout_micro_seconds);
01045 
01046                 if (status == VL53L0X_ERROR_NONE)
01047                     status = VL53L0X_write_byte(dev,
01048                                                 VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
01049                                                 vcsel_period_reg);
01050 
01051 
01052                 if (status == VL53L0X_ERROR_NONE)
01053                     status = set_sequence_step_timeout(dev,
01054                                                        VL53L0X_SEQUENCESTEP_FINAL_RANGE,
01055                                                        final_range_timeout_micro_seconds);
01056 
01057                 VL53L0X_SETDEVICESPECIFICPARAMETER(
01058                     dev,
01059                     FinalRangeVcselPulsePeriod,
01060                     vcsel_pulse_period_pclk);
01061                 break;
01062             default:
01063                 status = VL53L0X_ERROR_INVALID_PARAMS;
01064         }
01065     }
01066 
01067     /* Finally, the timing budget must be re-applied */
01068     if (status == VL53L0X_ERROR_NONE) {
01069         VL53L0X_GETPARAMETERFIELD(dev,
01070                                   MeasurementTimingBudgetMicroSeconds,
01071                                   measurement_timing_budget_micro_seconds);
01072 
01073         status = VL53L0X_set_measurement_timing_budget_micro_seconds(dev,
01074                  measurement_timing_budget_micro_seconds);
01075     }
01076 
01077     /* Perform the phase calibration. This is needed after changing on
01078      * vcsel period.
01079      * get_data_enable = 0, restore_config = 1 */
01080     if (status == VL53L0X_ERROR_NONE)
01081         status = VL53L0X_perform_phase_calibration(
01082                      dev, &phase_cal_int, 0, 1);
01083 
01084     return status;
01085 }
01086 
01087 VL53L0X_Error VL53L0X::VL53L0X_set_vcsel_pulse_period(VL53L0X_DEV dev,
01088         VL53L0X_VcselPeriod vcsel_period_type, uint8_t vcsel_pulse_period)
01089 {
01090     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01091     LOG_FUNCTION_START("");
01092 
01093     status = wrapped_VL53L0X_set_vcsel_pulse_period(dev, vcsel_period_type,
01094              vcsel_pulse_period);
01095 
01096     LOG_FUNCTION_END(status);
01097     return status;
01098 }
01099 
01100 VL53L0X_Error VL53L0X::wrapped_VL53L0X_get_vcsel_pulse_period(VL53L0X_DEV dev,
01101         VL53L0X_VcselPeriod vcsel_period_type, uint8_t *p_vcsel_pulse_period_pclk)
01102 {
01103     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01104     uint8_t vcsel_period_reg;
01105 
01106     switch (vcsel_period_type) {
01107         case VL53L0X_VCSEL_PERIOD_PRE_RANGE:
01108             status = VL53L0X_read_byte(dev,
01109                                        VL53L0X_REG_PRE_RANGE_CONFIG_VCSEL_PERIOD,
01110                                        &vcsel_period_reg);
01111             break;
01112         case VL53L0X_VCSEL_PERIOD_FINAL_RANGE:
01113             status = VL53L0X_read_byte(dev,
01114                                        VL53L0X_REG_FINAL_RANGE_CONFIG_VCSEL_PERIOD,
01115                                        &vcsel_period_reg);
01116             break;
01117         default:
01118             status = VL53L0X_ERROR_INVALID_PARAMS;
01119     }
01120 
01121     if (status == VL53L0X_ERROR_NONE)
01122         *p_vcsel_pulse_period_pclk =
01123             VL53L0X_decode_vcsel_period(vcsel_period_reg);
01124 
01125     return status;
01126 }
01127 
01128 VL53L0X_Error VL53L0X::VL53L0X_get_vcsel_pulse_period(VL53L0X_DEV dev,
01129         VL53L0X_VcselPeriod vcsel_period_type, uint8_t *p_vcsel_pulse_period_pclk)
01130 {
01131     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01132     LOG_FUNCTION_START("");
01133 
01134     status = wrapped_VL53L0X_get_vcsel_pulse_period(dev, vcsel_period_type,
01135              p_vcsel_pulse_period_pclk);
01136 
01137     LOG_FUNCTION_END(status);
01138     return status;
01139 }
01140 
01141 uint32_t VL53L0X::VL53L0X_decode_timeout(uint16_t encoded_timeout)
01142 {
01143     /*!
01144      * Decode 16-bit timeout register value - format (LSByte * 2^MSByte) + 1
01145      */
01146 
01147     uint32_t timeout_macro_clks = 0;
01148 
01149     timeout_macro_clks = ((uint32_t)(encoded_timeout & 0x00FF)
01150                           << (uint32_t)((encoded_timeout & 0xFF00) >> 8)) + 1;
01151 
01152     return timeout_macro_clks;
01153 }
01154 
01155 uint32_t VL53L0X::VL53L0X_calc_macro_period_ps(VL53L0X_DEV dev, uint8_t vcsel_period_pclks)
01156 {
01157     uint64_t pll_period_ps;
01158     uint32_t macro_period_vclks;
01159     uint32_t macro_period_ps;
01160 
01161     LOG_FUNCTION_START("");
01162 
01163     /* The above calculation will produce rounding errors,
01164        therefore set fixed value
01165     */
01166     pll_period_ps = 1655;
01167 
01168     macro_period_vclks = 2304;
01169     macro_period_ps = (uint32_t)(macro_period_vclks
01170                                  * vcsel_period_pclks * pll_period_ps);
01171 
01172     LOG_FUNCTION_END("");
01173     return macro_period_ps;
01174 }
01175 
01176 /* To convert register value into us */
01177 uint32_t VL53L0X::VL53L0X_calc_timeout_us(VL53L0X_DEV dev,
01178         uint16_t timeout_period_mclks,
01179         uint8_t vcsel_period_pclks)
01180 {
01181     uint32_t macro_period_ps;
01182     uint32_t macro_period_ns;
01183     uint32_t actual_timeout_period_us = 0;
01184 
01185     macro_period_ps = VL53L0X_calc_macro_period_ps(dev, vcsel_period_pclks);
01186     macro_period_ns = (macro_period_ps + 500) / 1000;
01187 
01188     actual_timeout_period_us =
01189         ((timeout_period_mclks * macro_period_ns) + 500) / 1000;
01190 
01191     return actual_timeout_period_us;
01192 }
01193 
01194 VL53L0X_Error VL53L0X::get_sequence_step_timeout(VL53L0X_DEV dev,
01195         VL53L0X_SequenceStepId sequence_step_id,
01196         uint32_t *p_time_out_micro_secs)
01197 {
01198     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01199     uint8_t current_vcsel_pulse_period_p_clk;
01200     uint8_t encoded_time_out_byte = 0;
01201     uint32_t timeout_micro_seconds = 0;
01202     uint16_t pre_range_encoded_time_out = 0;
01203     uint16_t msrc_time_out_m_clks;
01204     uint16_t pre_range_time_out_m_clks;
01205     uint16_t final_range_time_out_m_clks = 0;
01206     uint16_t final_range_encoded_time_out;
01207     VL53L0X_SchedulerSequenceSteps_t scheduler_sequence_steps;
01208 
01209     if ((sequence_step_id == VL53L0X_SEQUENCESTEP_TCC)   ||
01210             (sequence_step_id == VL53L0X_SEQUENCESTEP_DSS)   ||
01211             (sequence_step_id == VL53L0X_SEQUENCESTEP_MSRC)) {
01212 
01213         status = VL53L0X_get_vcsel_pulse_period(dev,
01214                                                 VL53L0X_VCSEL_PERIOD_PRE_RANGE,
01215                                                 &current_vcsel_pulse_period_p_clk);
01216         if (status == VL53L0X_ERROR_NONE) {
01217             status = VL53L0X_read_byte(dev,
01218                                        VL53L0X_REG_MSRC_CONFIG_TIMEOUT_MACROP,
01219                                        &encoded_time_out_byte);
01220         }
01221         msrc_time_out_m_clks = VL53L0X_decode_timeout(encoded_time_out_byte);
01222 
01223         timeout_micro_seconds = VL53L0X_calc_timeout_us(dev,
01224                                 msrc_time_out_m_clks,
01225                                 current_vcsel_pulse_period_p_clk);
01226     } else if (sequence_step_id == VL53L0X_SEQUENCESTEP_PRE_RANGE) {
01227         /* Retrieve PRE-RANGE VCSEL Period */
01228         status = VL53L0X_get_vcsel_pulse_period(dev,
01229                                                 VL53L0X_VCSEL_PERIOD_PRE_RANGE,
01230                                                 &current_vcsel_pulse_period_p_clk);
01231 
01232         /* Retrieve PRE-RANGE Timeout in Macro periods (MCLKS) */
01233         if (status == VL53L0X_ERROR_NONE) {
01234 
01235             /* Retrieve PRE-RANGE VCSEL Period */
01236             status = VL53L0X_get_vcsel_pulse_period(dev,
01237                                                     VL53L0X_VCSEL_PERIOD_PRE_RANGE,
01238                                                     &current_vcsel_pulse_period_p_clk);
01239 
01240             if (status == VL53L0X_ERROR_NONE) {
01241                 status = VL53L0X_read_word(dev,
01242                                            VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
01243                                            &pre_range_encoded_time_out);
01244             }
01245 
01246             pre_range_time_out_m_clks = VL53L0X_decode_timeout(
01247                                             pre_range_encoded_time_out);
01248 
01249             timeout_micro_seconds = VL53L0X_calc_timeout_us(dev,
01250                                     pre_range_time_out_m_clks,
01251                                     current_vcsel_pulse_period_p_clk);
01252         }
01253     } else if (sequence_step_id == VL53L0X_SEQUENCESTEP_FINAL_RANGE) {
01254 
01255         VL53L0X_get_sequence_step_enables(dev, &scheduler_sequence_steps);
01256         pre_range_time_out_m_clks = 0;
01257 
01258         if (scheduler_sequence_steps.PreRangeOn) {
01259             /* Retrieve PRE-RANGE VCSEL Period */
01260             status = VL53L0X_get_vcsel_pulse_period(dev,
01261                                                     VL53L0X_VCSEL_PERIOD_PRE_RANGE,
01262                                                     &current_vcsel_pulse_period_p_clk);
01263 
01264             /* Retrieve PRE-RANGE Timeout in Macro periods
01265              * (MCLKS) */
01266             if (status == VL53L0X_ERROR_NONE) {
01267                 status = VL53L0X_read_word(dev,
01268                                            VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
01269                                            &pre_range_encoded_time_out);
01270                 pre_range_time_out_m_clks = VL53L0X_decode_timeout(
01271                                                 pre_range_encoded_time_out);
01272             }
01273         }
01274 
01275         if (status == VL53L0X_ERROR_NONE) {
01276             /* Retrieve FINAL-RANGE VCSEL Period */
01277             status = VL53L0X_get_vcsel_pulse_period(dev,
01278                                                     VL53L0X_VCSEL_PERIOD_FINAL_RANGE,
01279                                                     &current_vcsel_pulse_period_p_clk);
01280         }
01281 
01282         /* Retrieve FINAL-RANGE Timeout in Macro periods (MCLKS) */
01283         if (status == VL53L0X_ERROR_NONE) {
01284             status = VL53L0X_read_word(dev,
01285                                        VL53L0X_REG_FINAL_RANGE_CONFIG_TIMEOUT_MACROP_HI,
01286                                        &final_range_encoded_time_out);
01287             final_range_time_out_m_clks = VL53L0X_decode_timeout(
01288                                               final_range_encoded_time_out);
01289         }
01290 
01291         final_range_time_out_m_clks -= pre_range_time_out_m_clks;
01292         timeout_micro_seconds = VL53L0X_calc_timeout_us(dev,
01293                                 final_range_time_out_m_clks,
01294                                 current_vcsel_pulse_period_p_clk);
01295     }
01296 
01297     *p_time_out_micro_secs = timeout_micro_seconds;
01298 
01299     return status;
01300 }
01301 
01302 VL53L0X_Error VL53L0X::wrapped_VL53L0X_get_measurement_timing_budget_micro_seconds(VL53L0X_DEV dev,
01303         uint32_t *p_measurement_timing_budget_micro_seconds)
01304 {
01305     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01306     VL53L0X_SchedulerSequenceSteps_t scheduler_sequence_steps;
01307     uint32_t final_range_timeout_micro_seconds;
01308     uint32_t msrc_dcc_tcc_timeout_micro_seconds = 2000;
01309     uint32_t start_overhead_micro_seconds       = 1910;
01310     uint32_t end_overhead_micro_seconds     = 960;
01311     uint32_t msrc_overhead_micro_seconds        = 660;
01312     uint32_t tcc_overhead_micro_seconds     = 590;
01313     uint32_t dss_overhead_micro_seconds     = 690;
01314     uint32_t pre_range_overhead_micro_seconds   = 660;
01315     uint32_t final_range_overhead_micro_seconds = 550;
01316     uint32_t pre_range_timeout_micro_seconds    = 0;
01317 
01318     LOG_FUNCTION_START("");
01319 
01320     /* Start and end overhead times always present */
01321     *p_measurement_timing_budget_micro_seconds
01322         = start_overhead_micro_seconds + end_overhead_micro_seconds;
01323 
01324     status = VL53L0X_get_sequence_step_enables(dev, &scheduler_sequence_steps);
01325 
01326     if (status != VL53L0X_ERROR_NONE) {
01327         LOG_FUNCTION_END(status);
01328         return status;
01329     }
01330 
01331 
01332     if (scheduler_sequence_steps.TccOn  ||
01333             scheduler_sequence_steps.MsrcOn ||
01334             scheduler_sequence_steps.DssOn) {
01335 
01336         status = get_sequence_step_timeout(dev,
01337                                            VL53L0X_SEQUENCESTEP_MSRC,
01338                                            &msrc_dcc_tcc_timeout_micro_seconds);
01339 
01340         if (status == VL53L0X_ERROR_NONE) {
01341             if (scheduler_sequence_steps.TccOn) {
01342                 *p_measurement_timing_budget_micro_seconds +=
01343                     msrc_dcc_tcc_timeout_micro_seconds +
01344                     tcc_overhead_micro_seconds;
01345             }
01346 
01347             if (scheduler_sequence_steps.DssOn) {
01348                 *p_measurement_timing_budget_micro_seconds +=
01349                     2 * (msrc_dcc_tcc_timeout_micro_seconds +
01350                          dss_overhead_micro_seconds);
01351             } else if (scheduler_sequence_steps.MsrcOn) {
01352                 *p_measurement_timing_budget_micro_seconds +=
01353                     msrc_dcc_tcc_timeout_micro_seconds +
01354                     msrc_overhead_micro_seconds;
01355             }
01356         }
01357     }
01358 
01359     if (status == VL53L0X_ERROR_NONE) {
01360         if (scheduler_sequence_steps.PreRangeOn) {
01361             status = get_sequence_step_timeout(dev,
01362                                                VL53L0X_SEQUENCESTEP_PRE_RANGE,
01363                                                &pre_range_timeout_micro_seconds);
01364             *p_measurement_timing_budget_micro_seconds +=
01365                 pre_range_timeout_micro_seconds +
01366                 pre_range_overhead_micro_seconds;
01367         }
01368     }
01369 
01370     if (status == VL53L0X_ERROR_NONE) {
01371         if (scheduler_sequence_steps.FinalRangeOn) {
01372             status = get_sequence_step_timeout(dev,
01373                                                VL53L0X_SEQUENCESTEP_FINAL_RANGE,
01374                                                &final_range_timeout_micro_seconds);
01375             *p_measurement_timing_budget_micro_seconds +=
01376                 (final_range_timeout_micro_seconds +
01377                  final_range_overhead_micro_seconds);
01378         }
01379     }
01380 
01381     if (status == VL53L0X_ERROR_NONE) {
01382         VL53L0X_SETPARAMETERFIELD(dev,
01383                                   MeasurementTimingBudgetMicroSeconds,
01384                                   *p_measurement_timing_budget_micro_seconds);
01385     }
01386 
01387     LOG_FUNCTION_END(status);
01388     return status;
01389 }
01390 
01391 VL53L0X_Error VL53L0X::VL53L0X_get_measurement_timing_budget_micro_seconds(VL53L0X_DEV dev,
01392         uint32_t *p_measurement_timing_budget_micro_seconds)
01393 {
01394     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01395     LOG_FUNCTION_START("");
01396 
01397     status = wrapped_VL53L0X_get_measurement_timing_budget_micro_seconds(dev,
01398              p_measurement_timing_budget_micro_seconds);
01399 
01400     LOG_FUNCTION_END(status);
01401     return status;
01402 }
01403 
01404 VL53L0X_Error VL53L0X::VL53L0X_get_device_parameters(VL53L0X_DEV dev,
01405         VL53L0X_DeviceParameters_t *p_device_parameters)
01406 {
01407     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01408     int i;
01409 
01410     LOG_FUNCTION_START("");
01411 
01412     status = VL53L0X_get_device_mode(dev, &(p_device_parameters->DeviceMode ));
01413 
01414     if (status == VL53L0X_ERROR_NONE)
01415         status = VL53L0X_get_inter_measurement_period_milli_seconds(dev,
01416                  &(p_device_parameters->InterMeasurementPeriodMilliSeconds ));
01417 
01418 
01419     if (status == VL53L0X_ERROR_NONE) {
01420         p_device_parameters->XTalkCompensationEnable  = 0;
01421     }
01422 
01423     if (status == VL53L0X_ERROR_NONE)
01424         status = VL53L0X_get_x_talk_compensation_rate_mega_cps(dev,
01425                  &(p_device_parameters->XTalkCompensationRateMegaCps ));
01426 
01427 
01428     if (status == VL53L0X_ERROR_NONE)
01429         status = VL53L0X_get_offset_calibration_data_micro_meter(dev,
01430                  &(p_device_parameters->RangeOffsetMicroMeters ));
01431 
01432 
01433     if (status == VL53L0X_ERROR_NONE) {
01434         for (i = 0; i < VL53L0X_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
01435             /* get first the values, then the enables.
01436              * VL53L0X_GetLimitCheckValue will modify the enable
01437              * flags
01438              */
01439             if (status == VL53L0X_ERROR_NONE) {
01440                 status |= VL53L0X_get_limit_check_value(dev, i,
01441                                                         &(p_device_parameters->LimitChecksValue [i]));
01442             } else {
01443                 break;
01444             }
01445             if (status == VL53L0X_ERROR_NONE) {
01446                 status |= VL53L0X_get_limit_check_enable(dev, i,
01447                           &(p_device_parameters->LimitChecksEnable [i]));
01448             } else {
01449                 break;
01450             }
01451         }
01452     }
01453 
01454     if (status == VL53L0X_ERROR_NONE) {
01455         status = VL53L0X_get_wrap_around_check_enable(dev,
01456                  &(p_device_parameters->WrapAroundCheckEnable ));
01457     }
01458 
01459     /* Need to be done at the end as it uses VCSELPulsePeriod */
01460     if (status == VL53L0X_ERROR_NONE) {
01461         status = VL53L0X_get_measurement_timing_budget_micro_seconds(dev,
01462                  &(p_device_parameters->MeasurementTimingBudgetMicroSeconds ));
01463     }
01464 
01465     LOG_FUNCTION_END(status);
01466     return status;
01467 }
01468 
01469 VL53L0X_Error VL53L0X::VL53L0X_set_limit_check_value(VL53L0X_DEV dev, uint16_t limit_check_id,
01470         FixPoint1616_t limit_check_value)
01471 {
01472     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01473     uint8_t temp8;
01474 
01475     LOG_FUNCTION_START("");
01476 
01477     VL53L0X_GETARRAYPARAMETERFIELD(dev, LimitChecksEnable, limit_check_id,
01478                                    temp8);
01479 
01480     if (temp8 == 0) { /* disabled write only internal value */
01481         VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksValue,
01482                                        limit_check_id, limit_check_value);
01483     } else {
01484 
01485         switch (limit_check_id) {
01486 
01487             case VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE:
01488                 /* internal computation: */
01489                 VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksValue,
01490                                                VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
01491                                                limit_check_value);
01492                 break;
01493 
01494             case VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
01495 
01496                 status = VL53L0X_write_word(dev,
01497                                             VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
01498                                             VL53L0X_FIXPOINT1616TOFIXPOINT97(
01499                                                 limit_check_value));
01500 
01501                 break;
01502 
01503             case VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP:
01504 
01505                 /* internal computation: */
01506                 VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksValue,
01507                                                VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP,
01508                                                limit_check_value);
01509 
01510                 break;
01511 
01512             case VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
01513 
01514                 /* internal computation: */
01515                 VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksValue,
01516                                                VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
01517                                                limit_check_value);
01518 
01519                 break;
01520 
01521             case VL53L0X_CHECKENABLE_SIGNAL_RATE_MSRC:
01522             case VL53L0X_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
01523 
01524                 status = VL53L0X_write_word(dev,
01525                                             VL53L0X_REG_PRE_RANGE_MIN_COUNT_RATE_RTN_LIMIT,
01526                                             VL53L0X_FIXPOINT1616TOFIXPOINT97(
01527                                                 limit_check_value));
01528 
01529                 break;
01530 
01531             default:
01532                 status = VL53L0X_ERROR_INVALID_PARAMS;
01533 
01534         }
01535 
01536         if (status == VL53L0X_ERROR_NONE) {
01537             VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksValue,
01538                                            limit_check_id, limit_check_value);
01539         }
01540     }
01541 
01542     LOG_FUNCTION_END(status);
01543     return status;
01544 }
01545 
01546 VL53L0X_Error VL53L0X::VL53L0X_data_init(VL53L0X_DEV dev)
01547 {
01548     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01549     VL53L0X_DeviceParameters_t CurrentParameters;
01550     int i;
01551     uint8_t StopVariable;
01552 
01553     LOG_FUNCTION_START("");
01554 
01555     /* by default the I2C is running at 1V8 if you want to change it you
01556      * need to include this define at compilation level. */
01557 #ifdef USE_I2C_2V8
01558     Status = VL53L0X_UpdateByte(Dev,
01559                                 VL53L0X_REG_VHV_CONFIG_PAD_SCL_SDA__EXTSUP_HV,
01560                                 0xFE,
01561                                 0x01);
01562 #endif
01563 
01564     /* Set I2C standard mode */
01565     if (status == VL53L0X_ERROR_NONE) {
01566         status = VL53L0X_write_byte(dev, 0x88, 0x00);
01567     }
01568 
01569     VL53L0X_SETDEVICESPECIFICPARAMETER(dev, ReadDataFromDeviceDone, 0);
01570 
01571 #ifdef USE_IQC_STATION
01572     if (Status == VL53L0X_ERROR_NONE) {
01573         Status = VL53L0X_apply_offset_adjustment(Dev);
01574     }
01575 #endif
01576 
01577     /* Default value is 1000 for Linearity Corrective Gain */
01578     PALDevDataSet(dev, LinearityCorrectiveGain, 1000);
01579 
01580     /* Dmax default Parameter */
01581     PALDevDataSet(dev, DmaxCalRangeMilliMeter, 400);
01582     PALDevDataSet(dev, DmaxCalSignalRateRtnMegaCps,
01583                   (FixPoint1616_t)((0x00016B85))); /* 1.42 No Cover Glass*/
01584 
01585     /* Set Default static parameters
01586      *set first temporary values 9.44MHz * 65536 = 618660 */
01587     VL53L0X_SETDEVICESPECIFICPARAMETER(dev, OscFrequencyMHz, 618660);
01588 
01589     /* Set Default XTalkCompensationRateMegaCps to 0  */
01590     VL53L0X_SETPARAMETERFIELD(dev, XTalkCompensationRateMegaCps, 0);
01591 
01592     /* Get default parameters */
01593     status = VL53L0X_get_device_parameters(dev, &CurrentParameters);
01594     if (status == VL53L0X_ERROR_NONE) {
01595         /* initialize PAL values */
01596         CurrentParameters.DeviceMode  = VL53L0X_DEVICEMODE_SINGLE_RANGING;
01597         CurrentParameters.HistogramMode  = VL53L0X_HISTOGRAMMODE_DISABLED;
01598         PALDevDataSet(dev, CurrentParameters, CurrentParameters);
01599     }
01600 
01601     /* Sigma estimator variable */
01602     PALDevDataSet(dev, SigmaEstRefArray, 100);
01603     PALDevDataSet(dev, SigmaEstEffPulseWidth, 900);
01604     PALDevDataSet(dev, SigmaEstEffAmbWidth, 500);
01605     PALDevDataSet(dev, targetRefRate, 0x0A00); /* 20 MCPS in 9:7 format */
01606 
01607     /* Use internal default settings */
01608     PALDevDataSet(dev, UseInternalTuningSettings, 1);
01609 
01610     status |= VL53L0X_write_byte(dev, 0x80, 0x01);
01611     status |= VL53L0X_write_byte(dev, 0xFF, 0x01);
01612     status |= VL53L0X_write_byte(dev, 0x00, 0x00);
01613     status |= VL53L0X_read_byte(dev, 0x91, &StopVariable);
01614     PALDevDataSet(dev, StopVariable, StopVariable);
01615     status |= VL53L0X_write_byte(dev, 0x00, 0x01);
01616     status |= VL53L0X_write_byte(dev, 0xFF, 0x00);
01617     status |= VL53L0X_write_byte(dev, 0x80, 0x00);
01618 
01619     /* Enable all check */
01620     for (i = 0; i < VL53L0X_CHECKENABLE_NUMBER_OF_CHECKS; i++) {
01621         if (status == VL53L0X_ERROR_NONE) {
01622             status |= VL53L0X_set_limit_check_enable(dev, i, 1);
01623         } else {
01624             break;
01625         }
01626 
01627     }
01628 
01629     /* Disable the following checks */
01630     if (status == VL53L0X_ERROR_NONE)
01631         status = VL53L0X_set_limit_check_enable(dev,
01632                                                 VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP, 0);
01633 
01634     if (status == VL53L0X_ERROR_NONE)
01635         status = VL53L0X_set_limit_check_enable(dev,
01636                                                 VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD, 0);
01637 
01638     if (status == VL53L0X_ERROR_NONE)
01639         status = VL53L0X_set_limit_check_enable(dev,
01640                                                 VL53L0X_CHECKENABLE_SIGNAL_RATE_MSRC, 0);
01641 
01642     if (status == VL53L0X_ERROR_NONE)
01643         status = VL53L0X_set_limit_check_enable(dev,
01644                                                 VL53L0X_CHECKENABLE_SIGNAL_RATE_PRE_RANGE, 0);
01645 
01646     /* Limit default values */
01647     if (status == VL53L0X_ERROR_NONE) {
01648         status = VL53L0X_set_limit_check_value(dev,
01649                                                VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
01650                                                (FixPoint1616_t)(18 * 65536));
01651     }
01652     if (status == VL53L0X_ERROR_NONE) {
01653         status = VL53L0X_set_limit_check_value(dev,
01654                                                VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
01655                                                (FixPoint1616_t)(25 * 65536 / 100));
01656         /* 0.25 * 65536 */
01657     }
01658 
01659     if (status == VL53L0X_ERROR_NONE) {
01660         status = VL53L0X_set_limit_check_value(dev,
01661                                                VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP,
01662                                                (FixPoint1616_t)(35 * 65536));
01663     }
01664 
01665     if (status == VL53L0X_ERROR_NONE) {
01666         status = VL53L0X_set_limit_check_value(dev,
01667                                                VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
01668                                                (FixPoint1616_t)(0 * 65536));
01669     }
01670 
01671     if (status == VL53L0X_ERROR_NONE) {
01672 
01673         PALDevDataSet(dev, SequenceConfig, 0xFF);
01674         status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
01675                                     0xFF);
01676 
01677         /* Set PAL state to tell that we are waiting for call to
01678          * VL53L0X_StaticInit */
01679         PALDevDataSet(dev, PalState, VL53L0X_STATE_WAIT_STATICINIT);
01680     }
01681 
01682     if (status == VL53L0X_ERROR_NONE) {
01683         VL53L0X_SETDEVICESPECIFICPARAMETER(dev, RefSpadsInitialised, 0);
01684     }
01685 
01686 
01687     LOG_FUNCTION_END(status);
01688     return status;
01689 }
01690 
01691 VL53L0X_Error VL53L0X::VL53L0X_check_part_used(VL53L0X_DEV dev,
01692         uint8_t *revision,
01693         VL53L0X_DeviceInfo_t *p_VL53L0X_device_info)
01694 {
01695     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01696     uint8_t module_id_int;
01697     char *product_id_tmp;
01698 
01699     LOG_FUNCTION_START("");
01700 
01701     status = VL53L0X_get_info_from_device(dev, 2);
01702 
01703     if (status == VL53L0X_ERROR_NONE) {
01704         module_id_int = VL53L0X_GETDEVICESPECIFICPARAMETER(dev, ModuleId);
01705 
01706         if (module_id_int == 0) {
01707             *revision = 0;
01708             VL53L0X_COPYSTRING(p_VL53L0X_device_info->ProductId , "");
01709         } else {
01710             *revision = VL53L0X_GETDEVICESPECIFICPARAMETER(dev, Revision);
01711             product_id_tmp = VL53L0X_GETDEVICESPECIFICPARAMETER(dev,
01712                              ProductId);
01713             VL53L0X_COPYSTRING(p_VL53L0X_device_info->ProductId , product_id_tmp);
01714         }
01715     }
01716 
01717     LOG_FUNCTION_END(status);
01718     return status;
01719 }
01720 
01721 VL53L0X_Error VL53L0X::wrapped_VL53L0X_get_device_info(VL53L0X_DEV dev,
01722         VL53L0X_DeviceInfo_t *p_VL53L0X_device_info)
01723 {
01724     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01725     uint8_t revision_id;
01726     uint8_t revision;
01727 
01728     status = VL53L0X_check_part_used(dev, &revision, p_VL53L0X_device_info);
01729 
01730     if (status == VL53L0X_ERROR_NONE) {
01731         if (revision == 0) {
01732             VL53L0X_COPYSTRING(p_VL53L0X_device_info->Name ,
01733                                VL53L0X_STRING_DEVICE_INFO_NAME_TS0);
01734         } else if ((revision <= 34) && (revision != 32)) {
01735             VL53L0X_COPYSTRING(p_VL53L0X_device_info->Name ,
01736                                VL53L0X_STRING_DEVICE_INFO_NAME_TS1);
01737         } else if (revision < 39) {
01738             VL53L0X_COPYSTRING(p_VL53L0X_device_info->Name ,
01739                                VL53L0X_STRING_DEVICE_INFO_NAME_TS2);
01740         } else {
01741             VL53L0X_COPYSTRING(p_VL53L0X_device_info->Name ,
01742                                VL53L0X_STRING_DEVICE_INFO_NAME_ES1);
01743         }
01744 
01745         VL53L0X_COPYSTRING(p_VL53L0X_device_info->Type ,
01746                            VL53L0X_STRING_DEVICE_INFO_TYPE);
01747 
01748     }
01749 
01750     if (status == VL53L0X_ERROR_NONE) {
01751         status = VL53L0X_read_byte(dev, VL53L0X_REG_IDENTIFICATION_MODEL_ID,
01752                                    &p_VL53L0X_device_info->ProductType );
01753     }
01754 
01755     if (status == VL53L0X_ERROR_NONE) {
01756         status = VL53L0X_read_byte(dev,
01757                                    VL53L0X_REG_IDENTIFICATION_REVISION_ID,
01758                                    &revision_id);
01759         p_VL53L0X_device_info->ProductRevisionMajor  = 1;
01760         p_VL53L0X_device_info->ProductRevisionMinor  =
01761             (revision_id & 0xF0) >> 4;
01762     }
01763 
01764     return status;
01765 }
01766 
01767 VL53L0X_Error VL53L0X::VL53L0X_get_device_info(VL53L0X_DEV dev,
01768         VL53L0X_DeviceInfo_t *p_VL53L0X_device_info)
01769 {
01770     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01771     LOG_FUNCTION_START("");
01772 
01773     status = wrapped_VL53L0X_get_device_info(dev, p_VL53L0X_device_info);
01774 
01775     LOG_FUNCTION_END(status);
01776     return status;
01777 }
01778 
01779 VL53L0X_Error VL53L0X::VL53L0X_get_interrupt_mask_status(VL53L0X_DEV dev,
01780         uint32_t *p_interrupt_mask_status)
01781 {
01782     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01783     uint8_t byte;
01784     LOG_FUNCTION_START("");
01785 
01786     status = VL53L0X_read_byte(dev, VL53L0X_REG_RESULT_INTERRUPT_STATUS, &byte);
01787     *p_interrupt_mask_status = byte & 0x07;
01788 
01789     if (byte & 0x18) {
01790         status = VL53L0X_ERROR_RANGE_ERROR;
01791     }
01792 
01793     LOG_FUNCTION_END(status);
01794     return status;
01795 }
01796 
01797 VL53L0X_Error VL53L0X::VL53L0X_get_measurement_data_ready(VL53L0X_DEV dev,
01798         uint8_t *p_measurement_data_ready)
01799 {
01800     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01801     uint8_t sys_range_status_register;
01802     uint8_t interrupt_config;
01803     uint32_t interrupt_mask;
01804     LOG_FUNCTION_START("");
01805 
01806     interrupt_config = VL53L0X_GETDEVICESPECIFICPARAMETER(dev,
01807                        Pin0GpioFunctionality);
01808 
01809     if (interrupt_config ==
01810             VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) {
01811         status = VL53L0X_get_interrupt_mask_status(dev, &interrupt_mask);
01812         if (interrupt_mask ==
01813                 VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY) {
01814             *p_measurement_data_ready = 1;
01815         } else {
01816             *p_measurement_data_ready = 0;
01817         }
01818     } else {
01819         status = VL53L0X_read_byte(dev, VL53L0X_REG_RESULT_RANGE_STATUS,
01820                                    &sys_range_status_register);
01821         if (status == VL53L0X_ERROR_NONE) {
01822             if (sys_range_status_register & 0x01) {
01823                 *p_measurement_data_ready = 1;
01824             } else {
01825                 *p_measurement_data_ready = 0;
01826             }
01827         }
01828     }
01829 
01830     LOG_FUNCTION_END(status);
01831     return status;
01832 }
01833 
01834 VL53L0X_Error VL53L0X::VL53L0X_polling_delay(VL53L0X_DEV dev)
01835 {
01836     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01837 
01838     // do nothing
01839     VL53L0X_OsDelay();
01840     return status;
01841 }
01842 
01843 VL53L0X_Error VL53L0X::VL53L0X_measurement_poll_for_completion(VL53L0X_DEV dev)
01844 {
01845     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01846     uint8_t new_data_ready = 0;
01847     uint32_t loop_nb;
01848 
01849     LOG_FUNCTION_START("");
01850 
01851     loop_nb = 0;
01852 
01853     do {
01854         status = VL53L0X_get_measurement_data_ready(dev, &new_data_ready);
01855         if (status != 0) {
01856             break; /* the error is set */
01857         }
01858 
01859         if (new_data_ready == 1) {
01860             break; /* done note that status == 0 */
01861         }
01862 
01863         loop_nb++;
01864         if (loop_nb >= VL53L0X_DEFAULT_MAX_LOOP) {
01865             status = VL53L0X_ERROR_TIME_OUT;
01866             break;
01867         }
01868 
01869         VL53L0X_polling_delay(dev);
01870     } while (1);
01871 
01872     LOG_FUNCTION_END(status);
01873 
01874     return status;
01875 }
01876 
01877 /* Group PAL Interrupt Functions */
01878 VL53L0X_Error VL53L0X::VL53L0X_clear_interrupt_mask(VL53L0X_DEV dev, uint32_t interrupt_mask)
01879 {
01880     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01881     uint8_t loop_count;
01882     uint8_t byte;
01883     LOG_FUNCTION_START("");
01884 
01885     /* clear bit 0 range interrupt, bit 1 error interrupt */
01886     loop_count = 0;
01887     do {
01888         status = VL53L0X_write_byte(dev,
01889                                     VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR, 0x01);
01890         status |= VL53L0X_write_byte(dev,
01891                                      VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR, 0x00);
01892         status |= VL53L0X_read_byte(dev,
01893                                     VL53L0X_REG_RESULT_INTERRUPT_STATUS, &byte);
01894         loop_count++;
01895     } while (((byte & 0x07) != 0x00)
01896              && (loop_count < 3)
01897              && (status == VL53L0X_ERROR_NONE));
01898 
01899 
01900     if (loop_count >= 3) {
01901         status = VL53L0X_ERROR_INTERRUPT_NOT_CLEARED;
01902     }
01903 
01904     LOG_FUNCTION_END(status);
01905     return status;
01906 }
01907 
01908 VL53L0X_Error VL53L0X::VL53L0X_perform_single_ref_calibration(VL53L0X_DEV dev,
01909         uint8_t vhv_init_byte)
01910 {
01911     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01912 
01913     if (status == VL53L0X_ERROR_NONE) {
01914         status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSRANGE_START,
01915                                     VL53L0X_REG_SYSRANGE_MODE_START_STOP |
01916                                     vhv_init_byte);
01917     }
01918 
01919     if (status == VL53L0X_ERROR_NONE) {
01920         status = VL53L0X_measurement_poll_for_completion(dev);
01921     }
01922 
01923     if (status == VL53L0X_ERROR_NONE) {
01924         status = VL53L0X_clear_interrupt_mask(dev, 0);
01925     }
01926 
01927     if (status == VL53L0X_ERROR_NONE) {
01928         status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSRANGE_START, 0x00);
01929     }
01930 
01931     return status;
01932 }
01933 
01934 VL53L0X_Error VL53L0X::VL53L0X_ref_calibration_io(VL53L0X_DEV dev, uint8_t read_not_write,
01935         uint8_t vhv_settings, uint8_t phase_cal,
01936         uint8_t *p_vhv_settings, uint8_t *p_phase_cal,
01937         const uint8_t vhv_enable, const uint8_t phase_enable)
01938 {
01939     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01940     uint8_t phase_calint = 0;
01941 
01942     /* Read VHV from device */
01943     status |= VL53L0X_write_byte(dev, 0xFF, 0x01);
01944     status |= VL53L0X_write_byte(dev, 0x00, 0x00);
01945     status |= VL53L0X_write_byte(dev, 0xFF, 0x00);
01946 
01947     if (read_not_write) {
01948         if (vhv_enable) {
01949             status |= VL53L0X_read_byte(dev, 0xCB, p_vhv_settings);
01950         }
01951         if (phase_enable) {
01952             status |= VL53L0X_read_byte(dev, 0xEE, &phase_calint);
01953         }
01954     } else {
01955         if (vhv_enable) {
01956             status |= VL53L0X_write_byte(dev, 0xCB, vhv_settings);
01957         }
01958         if (phase_enable) {
01959             status |= VL53L0X_update_byte(dev, 0xEE, 0x80, phase_cal);
01960         }
01961     }
01962 
01963     status |= VL53L0X_write_byte(dev, 0xFF, 0x01);
01964     status |= VL53L0X_write_byte(dev, 0x00, 0x01);
01965     status |= VL53L0X_write_byte(dev, 0xFF, 0x00);
01966 
01967     *p_phase_cal = (uint8_t)(phase_calint & 0xEF);
01968 
01969     return status;
01970 }
01971 
01972 VL53L0X_Error VL53L0X::VL53L0X_perform_vhv_calibration(VL53L0X_DEV dev,
01973         uint8_t *p_vhv_settings, const uint8_t get_data_enable,
01974         const uint8_t restore_config)
01975 {
01976     VL53L0X_Error status = VL53L0X_ERROR_NONE;
01977     uint8_t sequence_config = 0;
01978     uint8_t vhv_settings = 0;
01979     uint8_t phase_cal = 0;
01980     uint8_t phase_cal_int = 0;
01981 
01982     /* store the value of the sequence config,
01983      * this will be reset before the end of the function
01984      */
01985 
01986     if (restore_config) {
01987         sequence_config = PALDevDataGet(dev, SequenceConfig);
01988     }
01989 
01990     /* Run VHV */
01991     status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0x01);
01992 
01993     if (status == VL53L0X_ERROR_NONE) {
01994         status = VL53L0X_perform_single_ref_calibration(dev, 0x40);
01995     }
01996 
01997     /* Read VHV from device */
01998     if ((status == VL53L0X_ERROR_NONE) && (get_data_enable == 1)) {
01999         status = VL53L0X_ref_calibration_io(dev, 1,
02000                                             vhv_settings, phase_cal, /* Not used here */
02001                                             p_vhv_settings, &phase_cal_int,
02002                                             1, 0);
02003     } else {
02004         *p_vhv_settings = 0;
02005     }
02006 
02007 
02008     if ((status == VL53L0X_ERROR_NONE) && restore_config) {
02009         /* restore the previous Sequence Config */
02010         status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
02011                                     sequence_config);
02012         if (status == VL53L0X_ERROR_NONE) {
02013             PALDevDataSet(dev, SequenceConfig, sequence_config);
02014         }
02015 
02016     }
02017 
02018     return status;
02019 }
02020 
02021 VL53L0X_Error VL53L0X::VL53L0X_perform_phase_calibration(VL53L0X_DEV dev,
02022         uint8_t *p_phase_cal, const uint8_t get_data_enable,
02023         const uint8_t restore_config)
02024 {
02025     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02026     uint8_t sequence_config = 0;
02027     uint8_t vhv_settings = 0;
02028     uint8_t phase_cal = 0;
02029     uint8_t vhv_settingsint;
02030 
02031     /* store the value of the sequence config,
02032      * this will be reset before the end of the function
02033      */
02034 
02035     if (restore_config) {
02036         sequence_config = PALDevDataGet(dev, SequenceConfig);
02037     }
02038 
02039     /* Run PhaseCal */
02040     status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0x02);
02041 
02042     if (status == VL53L0X_ERROR_NONE) {
02043         status = VL53L0X_perform_single_ref_calibration(dev, 0x0);
02044     }
02045 
02046     /* Read PhaseCal from device */
02047     if ((status == VL53L0X_ERROR_NONE) && (get_data_enable == 1)) {
02048         status = VL53L0X_ref_calibration_io(dev, 1,
02049                                             vhv_settings, phase_cal, /* Not used here */
02050                                             &vhv_settingsint, p_phase_cal,
02051                                             0, 1);
02052     } else {
02053         *p_phase_cal = 0;
02054     }
02055 
02056 
02057     if ((status == VL53L0X_ERROR_NONE) && restore_config) {
02058         /* restore the previous Sequence Config */
02059         status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
02060                                     sequence_config);
02061         if (status == VL53L0X_ERROR_NONE) {
02062             PALDevDataSet(dev, SequenceConfig, sequence_config);
02063         }
02064 
02065     }
02066 
02067     return status;
02068 }
02069 
02070 VL53L0X_Error VL53L0X::VL53L0X_perform_ref_calibration(VL53L0X_DEV dev,
02071         uint8_t *p_vhv_settings, uint8_t *p_phase_cal, uint8_t get_data_enable)
02072 {
02073     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02074     uint8_t sequence_config = 0;
02075 
02076     /* store the value of the sequence config,
02077      * this will be reset before the end of the function
02078      */
02079 
02080     sequence_config = PALDevDataGet(dev, SequenceConfig);
02081 
02082     /* In the following function we don't save the config to optimize
02083      * writes on device. Config is saved and restored only once. */
02084     status = VL53L0X_perform_vhv_calibration(
02085                  dev, p_vhv_settings, get_data_enable, 0);
02086 
02087     if (status == VL53L0X_ERROR_NONE) {
02088         status = VL53L0X_perform_phase_calibration(
02089                      dev, p_phase_cal, get_data_enable, 0);
02090     }
02091 
02092 
02093     if (status == VL53L0X_ERROR_NONE) {
02094         /* restore the previous Sequence Config */
02095         status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
02096                                     sequence_config);
02097         if (status == VL53L0X_ERROR_NONE) {
02098             PALDevDataSet(dev, SequenceConfig, sequence_config);
02099         }
02100 
02101     }
02102 
02103     return status;
02104 }
02105 
02106 void VL53L0X::get_next_good_spad(uint8_t good_spad_array[], uint32_t size,
02107                                  uint32_t curr, int32_t *p_next)
02108 {
02109     uint32_t start_index;
02110     uint32_t fine_offset;
02111     uint32_t c_spads_per_byte = 8;
02112     uint32_t coarse_index;
02113     uint32_t fine_index;
02114     uint8_t data_byte;
02115     uint8_t success = 0;
02116 
02117     /*
02118      * Starting with the current good spad, loop through the array to find
02119      * the next. i.e. the next bit set in the sequence.
02120      *
02121      * The coarse index is the byte index of the array and the fine index is
02122      * the index of the bit within each byte.
02123      */
02124 
02125     *p_next = -1;
02126 
02127     start_index = curr / c_spads_per_byte;
02128     fine_offset = curr % c_spads_per_byte;
02129 
02130     for (coarse_index = start_index; ((coarse_index < size) && !success);
02131             coarse_index++) {
02132         fine_index = 0;
02133         data_byte = good_spad_array[coarse_index];
02134 
02135         if (coarse_index == start_index) {
02136             /* locate the bit position of the provided current
02137              * spad bit before iterating */
02138             data_byte >>= fine_offset;
02139             fine_index = fine_offset;
02140         }
02141 
02142         while (fine_index < c_spads_per_byte) {
02143             if ((data_byte & 0x1) == 1) {
02144                 success = 1;
02145                 *p_next = coarse_index * c_spads_per_byte + fine_index;
02146                 break;
02147             }
02148             data_byte >>= 1;
02149             fine_index++;
02150         }
02151     }
02152 }
02153 
02154 uint8_t VL53L0X::is_aperture(uint32_t spad_index)
02155 {
02156     /*
02157      * This function reports if a given spad index is an aperture SPAD by
02158      * deriving the quadrant.
02159      */
02160     uint32_t quadrant;
02161     uint8_t is_aperture = 1;
02162     quadrant = spad_index >> 6;
02163     if (refArrayQuadrants[quadrant] == REF_ARRAY_SPAD_0) {
02164         is_aperture = 0;
02165     }
02166 
02167     return is_aperture;
02168 }
02169 
02170 VL53L0X_Error VL53L0X::enable_spad_bit(uint8_t spad_array[], uint32_t size,
02171                                        uint32_t spad_index)
02172 {
02173     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02174     uint32_t c_spads_per_byte = 8;
02175     uint32_t coarse_index;
02176     uint32_t fine_index;
02177 
02178     coarse_index = spad_index / c_spads_per_byte;
02179     fine_index = spad_index % c_spads_per_byte;
02180     if (coarse_index >= size) {
02181         status = VL53L0X_ERROR_REF_SPAD_INIT;
02182     } else {
02183         spad_array[coarse_index] |= (1 << fine_index);
02184     }
02185 
02186     return status;
02187 }
02188 
02189 VL53L0X_Error VL53L0X::set_ref_spad_map(VL53L0X_DEV dev, uint8_t *p_ref_spad_array)
02190 {
02191     VL53L0X_Error status = VL53L0X_write_multi(dev,
02192                            VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
02193                            p_ref_spad_array, 6);
02194 
02195     return status;
02196 }
02197 
02198 VL53L0X_Error VL53L0X::get_ref_spad_map(VL53L0X_DEV dev, uint8_t *p_ref_spad_array)
02199 {
02200     VL53L0X_Error status = VL53L0X_read_multi(dev,
02201                            VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0,
02202                            p_ref_spad_array,
02203                            6);
02204 //  VL53L0X_Error status = VL53L0X_ERROR_NONE;
02205 //  uint8_t count=0;
02206 
02207 //  for (count = 0; count < 6; count++)
02208 //        status = VL53L0X_RdByte(Dev, (VL53L0X_REG_GLOBAL_CONFIG_SPAD_ENABLES_REF_0 + count), &refSpadArray[count]);
02209     return status;
02210 }
02211 
02212 VL53L0X_Error VL53L0X::enable_ref_spads(VL53L0X_DEV dev,
02213                                         uint8_t aperture_spads,
02214                                         uint8_t good_spad_array[],
02215                                         uint8_t spad_array[],
02216                                         uint32_t size,
02217                                         uint32_t start,
02218                                         uint32_t offset,
02219                                         uint32_t spad_count,
02220                                         uint32_t *p_last_spad)
02221 {
02222     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02223     uint32_t index;
02224     uint32_t i;
02225     int32_t next_good_spad = offset;
02226     uint32_t current_spad;
02227     uint8_t check_spad_array[6];
02228 
02229     /*
02230      * This function takes in a spad array which may or may not have SPADS
02231      * already enabled and appends from a given offset a requested number
02232      * of new SPAD enables. The 'good spad map' is applied to
02233      * determine the next SPADs to enable.
02234      *
02235      * This function applies to only aperture or only non-aperture spads.
02236      * Checks are performed to ensure this.
02237      */
02238 
02239     current_spad = offset;
02240     for (index = 0; index < spad_count; index++) {
02241         get_next_good_spad(good_spad_array, size, current_spad,
02242                            &next_good_spad);
02243 
02244         if (next_good_spad == -1) {
02245             status = VL53L0X_ERROR_REF_SPAD_INIT;
02246             break;
02247         }
02248 
02249         /* Confirm that the next good SPAD is non-aperture */
02250         if (is_aperture(start + next_good_spad) != aperture_spads) {
02251             /* if we can't get the required number of good aperture
02252              * spads from the current quadrant then this is an error
02253              */
02254             status = VL53L0X_ERROR_REF_SPAD_INIT;
02255             break;
02256         }
02257         current_spad = (uint32_t)next_good_spad;
02258         enable_spad_bit(spad_array, size, current_spad);
02259         current_spad++;
02260     }
02261     *p_last_spad = current_spad;
02262 
02263     if (status == VL53L0X_ERROR_NONE) {
02264         status = set_ref_spad_map(dev, spad_array);
02265     }
02266 
02267 
02268     if (status == VL53L0X_ERROR_NONE) {
02269         status = get_ref_spad_map(dev, check_spad_array);
02270 
02271         i = 0;
02272 
02273         /* Compare spad maps. If not equal report error. */
02274         while (i < size) {
02275             if (spad_array[i] != check_spad_array[i]) {
02276                 status = VL53L0X_ERROR_REF_SPAD_INIT;
02277                 break;
02278             }
02279             i++;
02280         }
02281     }
02282     return status;
02283 }
02284 
02285 VL53L0X_Error VL53L0X::VL53L0X_set_device_mode(VL53L0X_DEV dev, VL53L0X_DeviceModes device_mode)
02286 {
02287     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02288 
02289     LOG_FUNCTION_START("%d", (int)DeviceMode);
02290 
02291     switch (device_mode) {
02292         case VL53L0X_DEVICEMODE_SINGLE_RANGING:
02293         case VL53L0X_DEVICEMODE_CONTINUOUS_RANGING:
02294         case VL53L0X_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
02295         case VL53L0X_DEVICEMODE_GPIO_DRIVE:
02296         case VL53L0X_DEVICEMODE_GPIO_OSC:
02297             /* Supported modes */
02298             VL53L0X_SETPARAMETERFIELD(dev, DeviceMode, device_mode);
02299             break;
02300         default:
02301             /* Unsupported mode */
02302             status = VL53L0X_ERROR_MODE_NOT_SUPPORTED;
02303     }
02304 
02305     LOG_FUNCTION_END(status);
02306     return status;
02307 }
02308 
02309 VL53L0X_Error VL53L0X::VL53L0X_set_interrupt_thresholds(VL53L0X_DEV dev,
02310         VL53L0X_DeviceModes device_mode, FixPoint1616_t threshold_low,
02311         FixPoint1616_t threshold_high)
02312 {
02313     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02314     uint16_t threshold16;
02315     LOG_FUNCTION_START("");
02316 
02317     /* no dependency on DeviceMode for Ewok */
02318     /* Need to divide by 2 because the FW will apply a x2 */
02319     threshold16 = (uint16_t)((threshold_low >> 17) & 0x00fff);
02320     status = VL53L0X_write_word(dev, VL53L0X_REG_SYSTEM_THRESH_LOW, threshold16);
02321 
02322     if (status == VL53L0X_ERROR_NONE) {
02323         /* Need to divide by 2 because the FW will apply a x2 */
02324         threshold16 = (uint16_t)((threshold_high >> 17) & 0x00fff);
02325         status = VL53L0X_write_word(dev, VL53L0X_REG_SYSTEM_THRESH_HIGH,
02326                                     threshold16);
02327     }
02328 
02329     LOG_FUNCTION_END(status);
02330     return status;
02331 }
02332 
02333 VL53L0X_Error VL53L0X::VL53L0X_get_interrupt_thresholds(VL53L0X_DEV dev,
02334         VL53L0X_DeviceModes device_mode, FixPoint1616_t *p_threshold_low,
02335         FixPoint1616_t *p_threshold_high)
02336 {
02337     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02338     uint16_t threshold16;
02339     LOG_FUNCTION_START("");
02340 
02341     /* no dependency on DeviceMode for Ewok */
02342 
02343     status = VL53L0X_read_word(dev, VL53L0X_REG_SYSTEM_THRESH_LOW, &threshold16);
02344     /* Need to multiply by 2 because the FW will apply a x2 */
02345     *p_threshold_low = (FixPoint1616_t)((0x00fff & threshold16) << 17);
02346 
02347     if (status == VL53L0X_ERROR_NONE) {
02348         status = VL53L0X_read_word(dev, VL53L0X_REG_SYSTEM_THRESH_HIGH,
02349                                    &threshold16);
02350         /* Need to multiply by 2 because the FW will apply a x2 */
02351         *p_threshold_high =
02352             (FixPoint1616_t)((0x00fff & threshold16) << 17);
02353     }
02354 
02355     LOG_FUNCTION_END(status);
02356     return status;
02357 }
02358 
02359 VL53L0X_Error VL53L0X::VL53L0X_load_tuning_settings(VL53L0X_DEV dev,
02360         uint8_t *p_tuning_setting_buffer)
02361 {
02362     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02363     int i;
02364     int index;
02365     uint8_t msb;
02366     uint8_t lsb;
02367     uint8_t select_param;
02368     uint8_t number_of_writes;
02369     uint8_t address;
02370     uint8_t local_buffer[4]; /* max */
02371     uint16_t temp16;
02372 
02373     LOG_FUNCTION_START("");
02374 
02375     index = 0;
02376 
02377     while ((*(p_tuning_setting_buffer + index) != 0) &&
02378             (status == VL53L0X_ERROR_NONE)) {
02379         number_of_writes = *(p_tuning_setting_buffer + index);
02380         index++;
02381         if (number_of_writes == 0xFF) {
02382             /* internal parameters */
02383             select_param = *(p_tuning_setting_buffer + index);
02384             index++;
02385             switch (select_param) {
02386                 case 0: /* uint16_t SigmaEstRefArray -> 2 bytes */
02387                     msb = *(p_tuning_setting_buffer + index);
02388                     index++;
02389                     lsb = *(p_tuning_setting_buffer + index);
02390                     index++;
02391                     temp16 = VL53L0X_MAKEUINT16(lsb, msb);
02392                     PALDevDataSet(dev, SigmaEstRefArray, temp16);
02393                     break;
02394                 case 1: /* uint16_t SigmaEstEffPulseWidth -> 2 bytes */
02395                     msb = *(p_tuning_setting_buffer + index);
02396                     index++;
02397                     lsb = *(p_tuning_setting_buffer + index);
02398                     index++;
02399                     temp16 = VL53L0X_MAKEUINT16(lsb, msb);
02400                     PALDevDataSet(dev, SigmaEstEffPulseWidth,
02401                                   temp16);
02402                     break;
02403                 case 2: /* uint16_t SigmaEstEffAmbWidth -> 2 bytes */
02404                     msb = *(p_tuning_setting_buffer + index);
02405                     index++;
02406                     lsb = *(p_tuning_setting_buffer + index);
02407                     index++;
02408                     temp16 = VL53L0X_MAKEUINT16(lsb, msb);
02409                     PALDevDataSet(dev, SigmaEstEffAmbWidth, temp16);
02410                     break;
02411                 case 3: /* uint16_t targetRefRate -> 2 bytes */
02412                     msb = *(p_tuning_setting_buffer + index);
02413                     index++;
02414                     lsb = *(p_tuning_setting_buffer + index);
02415                     index++;
02416                     temp16 = VL53L0X_MAKEUINT16(lsb, msb);
02417                     PALDevDataSet(dev, targetRefRate, temp16);
02418                     break;
02419                 default: /* invalid parameter */
02420                     status = VL53L0X_ERROR_INVALID_PARAMS;
02421             }
02422 
02423         } else if (number_of_writes <= 4) {
02424             address = *(p_tuning_setting_buffer + index);
02425             index++;
02426 
02427             for (i = 0; i < number_of_writes; i++) {
02428                 local_buffer[i] = *(p_tuning_setting_buffer +
02429                                     index);
02430                 index++;
02431             }
02432 
02433             status = VL53L0X_write_multi(dev, address, local_buffer,
02434                                          number_of_writes);
02435 
02436         } else {
02437             status = VL53L0X_ERROR_INVALID_PARAMS;
02438         }
02439     }
02440 
02441     LOG_FUNCTION_END(status);
02442     return status;
02443 }
02444 
02445 VL53L0X_Error VL53L0X::VL53L0X_check_and_load_interrupt_settings(VL53L0X_DEV dev,
02446         uint8_t start_not_stopflag)
02447 {
02448     uint8_t interrupt_config;
02449     FixPoint1616_t threshold_low;
02450     FixPoint1616_t threshold_high;
02451     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02452 
02453     interrupt_config = VL53L0X_GETDEVICESPECIFICPARAMETER(dev,
02454                        Pin0GpioFunctionality);
02455 
02456     if ((interrupt_config ==
02457             VL53L0X_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW) ||
02458             (interrupt_config ==
02459              VL53L0X_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH) ||
02460             (interrupt_config ==
02461              VL53L0X_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT)) {
02462 
02463         status = VL53L0X_get_interrupt_thresholds(dev,
02464                  VL53L0X_DEVICEMODE_CONTINUOUS_RANGING,
02465                  &threshold_low, &threshold_high);
02466 
02467         if (((threshold_low > 255 * 65536) ||
02468                 (threshold_high > 255 * 65536)) &&
02469                 (status == VL53L0X_ERROR_NONE)) {
02470 
02471             if (start_not_stopflag != 0) {
02472                 status = VL53L0X_load_tuning_settings(dev,
02473                                                       InterruptThresholdSettings);
02474             } else {
02475                 status |= VL53L0X_write_byte(dev, 0xFF, 0x04);
02476                 status |= VL53L0X_write_byte(dev, 0x70, 0x00);
02477                 status |= VL53L0X_write_byte(dev, 0xFF, 0x00);
02478                 status |= VL53L0X_write_byte(dev, 0x80, 0x00);
02479             }
02480 
02481         }
02482 
02483 
02484     }
02485 
02486     return status;
02487 
02488 }
02489 
02490 VL53L0X_Error VL53L0X::VL53L0X_start_measurement(VL53L0X_DEV dev)
02491 {
02492     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02493     VL53L0X_DeviceModes device_mode;
02494     uint8_t byte;
02495     uint8_t start_stop_byte = VL53L0X_REG_SYSRANGE_MODE_START_STOP;
02496     uint32_t loop_nb;
02497     LOG_FUNCTION_START("");
02498 
02499     /* Get Current DeviceMode */
02500     VL53L0X_get_device_mode(dev, &device_mode);
02501 
02502     status = VL53L0X_write_byte(dev, 0x80, 0x01);
02503     status = VL53L0X_write_byte(dev, 0xFF, 0x01);
02504     status = VL53L0X_write_byte(dev, 0x00, 0x00);
02505     status = VL53L0X_write_byte(dev, 0x91, PALDevDataGet(dev, StopVariable));
02506     status = VL53L0X_write_byte(dev, 0x00, 0x01);
02507     status = VL53L0X_write_byte(dev, 0xFF, 0x00);
02508     status = VL53L0X_write_byte(dev, 0x80, 0x00);
02509 
02510     switch (device_mode) {
02511         case VL53L0X_DEVICEMODE_SINGLE_RANGING:
02512             status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSRANGE_START, 0x01);
02513 
02514             byte = start_stop_byte;
02515             if (status == VL53L0X_ERROR_NONE) {
02516                 /* Wait until start bit has been cleared */
02517                 loop_nb = 0;
02518                 do {
02519                     if (loop_nb > 0)
02520                         status = VL53L0X_read_byte(dev,
02521                                                    VL53L0X_REG_SYSRANGE_START, &byte);
02522                     loop_nb = loop_nb + 1;
02523                 } while (((byte & start_stop_byte) == start_stop_byte)
02524                          && (status == VL53L0X_ERROR_NONE)
02525                          && (loop_nb < VL53L0X_DEFAULT_MAX_LOOP));
02526 
02527                 if (loop_nb >= VL53L0X_DEFAULT_MAX_LOOP) {
02528                     status = VL53L0X_ERROR_TIME_OUT;
02529                 }
02530 
02531             }
02532 
02533             break;
02534         case VL53L0X_DEVICEMODE_CONTINUOUS_RANGING:
02535             /* Back-to-back mode */
02536 
02537             /* Check if need to apply interrupt settings */
02538             if (status == VL53L0X_ERROR_NONE) {
02539                 status = VL53L0X_check_and_load_interrupt_settings(dev, 1);
02540             }
02541 
02542             status = VL53L0X_write_byte(dev,
02543                                         VL53L0X_REG_SYSRANGE_START,
02544                                         VL53L0X_REG_SYSRANGE_MODE_BACKTOBACK);
02545             if (status == VL53L0X_ERROR_NONE) {
02546                 /* Set PAL State to Running */
02547                 PALDevDataSet(dev, PalState, VL53L0X_STATE_RUNNING);
02548             }
02549             break;
02550         case VL53L0X_DEVICEMODE_CONTINUOUS_TIMED_RANGING:
02551             /* Continuous mode */
02552             /* Check if need to apply interrupt settings */
02553             if (status == VL53L0X_ERROR_NONE) {
02554                 status = VL53L0X_check_and_load_interrupt_settings(dev, 1);
02555             }
02556 
02557             status = VL53L0X_write_byte(dev,
02558                                         VL53L0X_REG_SYSRANGE_START,
02559                                         VL53L0X_REG_SYSRANGE_MODE_TIMED);
02560 
02561             if (status == VL53L0X_ERROR_NONE) {
02562                 /* Set PAL State to Running */
02563                 PALDevDataSet(dev, PalState, VL53L0X_STATE_RUNNING);
02564             }
02565             break;
02566         default:
02567             /* Selected mode not supported */
02568             status = VL53L0X_ERROR_MODE_NOT_SUPPORTED;
02569     }
02570 
02571 
02572     LOG_FUNCTION_END(status);
02573     return status;
02574 }
02575 
02576 /* Group PAL Measurement Functions */
02577 VL53L0X_Error VL53L0X::VL53L0X_perform_single_measurement(VL53L0X_DEV dev)
02578 {
02579     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02580     VL53L0X_DeviceModes device_mode;
02581 
02582     LOG_FUNCTION_START("");
02583 
02584     /* Get Current DeviceMode */
02585     status = VL53L0X_get_device_mode(dev, &device_mode);
02586 
02587     /* Start immediately to run a single ranging measurement in case of
02588      * single ranging or single histogram */
02589     if (status == VL53L0X_ERROR_NONE
02590             && device_mode == VL53L0X_DEVICEMODE_SINGLE_RANGING) {
02591         status = VL53L0X_start_measurement(dev);
02592     }
02593 
02594 
02595     if (status == VL53L0X_ERROR_NONE) {
02596         status = VL53L0X_measurement_poll_for_completion(dev);
02597     }
02598 
02599 
02600     /* Change PAL State in case of single ranging or single histogram */
02601     if (status == VL53L0X_ERROR_NONE
02602             && device_mode == VL53L0X_DEVICEMODE_SINGLE_RANGING) {
02603         PALDevDataSet(dev, PalState, VL53L0X_STATE_IDLE);
02604     }
02605 
02606 
02607     LOG_FUNCTION_END(status);
02608     return status;
02609 }
02610 
02611 VL53L0X_Error VL53L0X::VL53L0X_get_x_talk_compensation_enable(VL53L0X_DEV dev,
02612         uint8_t *p_x_talk_compensation_enable)
02613 {
02614     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02615     uint8_t temp8;
02616     LOG_FUNCTION_START("");
02617 
02618     VL53L0X_GETPARAMETERFIELD(dev, XTalkCompensationEnable, temp8);
02619     *p_x_talk_compensation_enable = temp8;
02620 
02621     LOG_FUNCTION_END(status);
02622     return status;
02623 }
02624 
02625 VL53L0X_Error VL53L0X::VL53L0X_get_total_xtalk_rate(VL53L0X_DEV dev,
02626         VL53L0X_RangingMeasurementData_t *p_ranging_measurement_data,
02627         FixPoint1616_t *p_total_xtalk_rate_mcps)
02628 {
02629     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02630 
02631     uint8_t xtalk_comp_enable;
02632     FixPoint1616_t total_xtalk_mega_cps;
02633     FixPoint1616_t xtalk_per_spad_mega_cps;
02634 
02635     *p_total_xtalk_rate_mcps = 0;
02636 
02637     status = VL53L0X_get_x_talk_compensation_enable(dev, &xtalk_comp_enable);
02638     if (status == VL53L0X_ERROR_NONE) {
02639 
02640         if (xtalk_comp_enable) {
02641 
02642             VL53L0X_GETPARAMETERFIELD(
02643                 dev,
02644                 XTalkCompensationRateMegaCps,
02645                 xtalk_per_spad_mega_cps);
02646 
02647             /* FixPoint1616 * FixPoint 8:8 = FixPoint0824 */
02648             total_xtalk_mega_cps =
02649                 p_ranging_measurement_data->EffectiveSpadRtnCount *
02650                 xtalk_per_spad_mega_cps;
02651 
02652             /* FixPoint0824 >> 8 = FixPoint1616 */
02653             *p_total_xtalk_rate_mcps =
02654                 (total_xtalk_mega_cps + 0x80) >> 8;
02655         }
02656     }
02657 
02658     return status;
02659 }
02660 
02661 VL53L0X_Error VL53L0X::VL53L0X_get_total_signal_rate(VL53L0X_DEV dev,
02662         VL53L0X_RangingMeasurementData_t *p_ranging_measurement_data,
02663         FixPoint1616_t *p_total_signal_rate_mcps)
02664 {
02665     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02666     FixPoint1616_t total_xtalk_mega_cps;
02667 
02668     LOG_FUNCTION_START("");
02669 
02670     *p_total_signal_rate_mcps =
02671         p_ranging_measurement_data->SignalRateRtnMegaCps;
02672 
02673     status = VL53L0X_get_total_xtalk_rate(
02674                  dev, p_ranging_measurement_data, &total_xtalk_mega_cps);
02675 
02676     if (status == VL53L0X_ERROR_NONE) {
02677         *p_total_signal_rate_mcps += total_xtalk_mega_cps;
02678     }
02679 
02680     return status;
02681 }
02682 
02683 /* To convert ms into register value */
02684 uint32_t VL53L0X::VL53L0X_calc_timeout_mclks(VL53L0X_DEV dev,
02685         uint32_t timeout_period_us,
02686         uint8_t vcsel_period_pclks)
02687 {
02688     uint32_t macro_period_ps;
02689     uint32_t macro_period_ns;
02690     uint32_t timeout_period_mclks = 0;
02691 
02692     macro_period_ps = VL53L0X_calc_macro_period_ps(dev, vcsel_period_pclks);
02693     macro_period_ns = (macro_period_ps + 500) / 1000;
02694 
02695     timeout_period_mclks =
02696         (uint32_t)(((timeout_period_us * 1000)
02697                     + (macro_period_ns / 2)) / macro_period_ns);
02698 
02699     return timeout_period_mclks;
02700 }
02701 
02702 uint32_t VL53L0X::VL53L0X_isqrt(uint32_t num)
02703 {
02704     /*
02705      * Implements an integer square root
02706      *
02707      * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
02708      */
02709 
02710     uint32_t  res = 0;
02711     uint32_t  bit = 1 << 30;
02712     /* The second-to-top bit is set:
02713      *  1 << 14 for 16-bits, 1 << 30 for 32 bits */
02714 
02715     /* "bit" starts at the highest power of four <= the argument. */
02716     while (bit > num) {
02717         bit >>= 2;
02718     }
02719 
02720 
02721     while (bit != 0) {
02722         if (num >= res + bit) {
02723             num -= res + bit;
02724             res = (res >> 1) + bit;
02725         } else {
02726             res >>= 1;
02727         }
02728 
02729         bit >>= 2;
02730     }
02731 
02732     return res;
02733 }
02734 
02735 VL53L0X_Error VL53L0X::VL53L0X_calc_dmax(
02736     VL53L0X_DEV dev,
02737     FixPoint1616_t total_signal_rate_mcps,
02738     FixPoint1616_t total_corr_signal_rate_mcps,
02739     FixPoint1616_t pw_mult,
02740     uint32_t sigma_estimate_p1,
02741     FixPoint1616_t sigma_estimate_p2,
02742     uint32_t peak_vcsel_duration_us,
02743     uint32_t *pd_max_mm)
02744 {
02745     const uint32_t c_sigma_limit        = 18;
02746     const FixPoint1616_t c_signal_limit = 0x4000; /* 0.25 */
02747     const FixPoint1616_t c_sigma_est_ref    = 0x00000042; /* 0.001 */
02748     const uint32_t c_amb_eff_width_sigma_est_ns = 6;
02749     const uint32_t c_amb_eff_width_d_max_ns    = 7;
02750     uint32_t dmax_cal_range_mm;
02751     FixPoint1616_t dmax_cal_signal_rate_rtn_mcps;
02752     FixPoint1616_t min_signal_needed;
02753     FixPoint1616_t min_signal_needed_p1;
02754     FixPoint1616_t min_signal_needed_p2;
02755     FixPoint1616_t min_signal_needed_p3;
02756     FixPoint1616_t min_signal_needed_p4;
02757     FixPoint1616_t sigma_limit_tmp;
02758     FixPoint1616_t sigma_est_sq_tmp;
02759     FixPoint1616_t signal_limit_tmp;
02760     FixPoint1616_t signal_at0_mm;
02761     FixPoint1616_t dmax_dark;
02762     FixPoint1616_t dmax_ambient;
02763     FixPoint1616_t dmax_dark_tmp;
02764     FixPoint1616_t sigma_est_p2_tmp;
02765     uint32_t signal_rate_temp_mcps;
02766 
02767     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02768 
02769     LOG_FUNCTION_START("");
02770 
02771     dmax_cal_range_mm =
02772         PALDevDataGet(dev, DmaxCalRangeMilliMeter);
02773 
02774     dmax_cal_signal_rate_rtn_mcps =
02775         PALDevDataGet(dev, DmaxCalSignalRateRtnMegaCps);
02776 
02777     /* uint32 * FixPoint1616 = FixPoint1616 */
02778     signal_at0_mm = dmax_cal_range_mm * dmax_cal_signal_rate_rtn_mcps;
02779 
02780     /* FixPoint1616 >> 8 = FixPoint2408 */
02781     signal_at0_mm = (signal_at0_mm + 0x80) >> 8;
02782     signal_at0_mm *= dmax_cal_range_mm;
02783 
02784     min_signal_needed_p1 = 0;
02785     if (total_corr_signal_rate_mcps > 0) {
02786 
02787         /* Shift by 10 bits to increase resolution prior to the
02788          * division */
02789         signal_rate_temp_mcps = total_signal_rate_mcps << 10;
02790 
02791         /* Add rounding value prior to division */
02792         min_signal_needed_p1 = signal_rate_temp_mcps +
02793                                (total_corr_signal_rate_mcps / 2);
02794 
02795         /* FixPoint0626/FixPoint1616 = FixPoint2210 */
02796         min_signal_needed_p1 /= total_corr_signal_rate_mcps;
02797 
02798         /* Apply a factored version of the speed of light.
02799          Correction to be applied at the end */
02800         min_signal_needed_p1 *= 3;
02801 
02802         /* FixPoint2210 * FixPoint2210 = FixPoint1220 */
02803         min_signal_needed_p1 *= min_signal_needed_p1;
02804 
02805         /* FixPoint1220 >> 16 = FixPoint2804 */
02806         min_signal_needed_p1 = (min_signal_needed_p1 + 0x8000) >> 16;
02807     }
02808 
02809     min_signal_needed_p2 = pw_mult * sigma_estimate_p1;
02810 
02811     /* FixPoint1616 >> 16 =  uint32 */
02812     min_signal_needed_p2 = (min_signal_needed_p2 + 0x8000) >> 16;
02813 
02814     /* uint32 * uint32  =  uint32 */
02815     min_signal_needed_p2 *= min_signal_needed_p2;
02816 
02817     /* Check sigmaEstimateP2
02818      * If this value is too high there is not enough signal rate
02819      * to calculate dmax value so set a suitable value to ensure
02820      * a very small dmax.
02821      */
02822     sigma_est_p2_tmp = (sigma_estimate_p2 + 0x8000) >> 16;
02823     sigma_est_p2_tmp = (sigma_est_p2_tmp + c_amb_eff_width_sigma_est_ns / 2) /
02824                        c_amb_eff_width_sigma_est_ns;
02825     sigma_est_p2_tmp *= c_amb_eff_width_d_max_ns;
02826 
02827     if (sigma_est_p2_tmp > 0xffff) {
02828         min_signal_needed_p3 = 0xfff00000;
02829     } else {
02830 
02831         /* DMAX uses a different ambient width from sigma, so apply
02832          * correction.
02833          * Perform division before multiplication to prevent overflow.
02834          */
02835         sigma_estimate_p2 = (sigma_estimate_p2 + c_amb_eff_width_sigma_est_ns / 2) /
02836                             c_amb_eff_width_sigma_est_ns;
02837         sigma_estimate_p2 *= c_amb_eff_width_d_max_ns;
02838 
02839         /* FixPoint1616 >> 16 = uint32 */
02840         min_signal_needed_p3 = (sigma_estimate_p2 + 0x8000) >> 16;
02841 
02842         min_signal_needed_p3 *= min_signal_needed_p3;
02843 
02844     }
02845 
02846     /* FixPoint1814 / uint32 = FixPoint1814 */
02847     sigma_limit_tmp = ((c_sigma_limit << 14) + 500) / 1000;
02848 
02849     /* FixPoint1814 * FixPoint1814 = FixPoint3628 := FixPoint0428 */
02850     sigma_limit_tmp *= sigma_limit_tmp;
02851 
02852     /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
02853     sigma_est_sq_tmp = c_sigma_est_ref * c_sigma_est_ref;
02854 
02855     /* FixPoint3232 >> 4 = FixPoint0428 */
02856     sigma_est_sq_tmp = (sigma_est_sq_tmp + 0x08) >> 4;
02857 
02858     /* FixPoint0428 - FixPoint0428  = FixPoint0428 */
02859     sigma_limit_tmp -=  sigma_est_sq_tmp;
02860 
02861     /* uint32_t * FixPoint0428 = FixPoint0428 */
02862     min_signal_needed_p4 = 4 * 12 * sigma_limit_tmp;
02863 
02864     /* FixPoint0428 >> 14 = FixPoint1814 */
02865     min_signal_needed_p4 = (min_signal_needed_p4 + 0x2000) >> 14;
02866 
02867     /* uint32 + uint32 = uint32 */
02868     min_signal_needed = (min_signal_needed_p2 + min_signal_needed_p3);
02869 
02870     /* uint32 / uint32 = uint32 */
02871     min_signal_needed += (peak_vcsel_duration_us / 2);
02872     min_signal_needed /= peak_vcsel_duration_us;
02873 
02874     /* uint32 << 14 = FixPoint1814 */
02875     min_signal_needed <<= 14;
02876 
02877     /* FixPoint1814 / FixPoint1814 = uint32 */
02878     min_signal_needed += (min_signal_needed_p4 / 2);
02879     min_signal_needed /= min_signal_needed_p4;
02880 
02881     /* FixPoint3200 * FixPoint2804 := FixPoint2804*/
02882     min_signal_needed *= min_signal_needed_p1;
02883 
02884     /* Apply correction by dividing by 1000000.
02885      * This assumes 10E16 on the numerator of the equation
02886      * and 10E-22 on the denominator.
02887      * We do this because 32bit fix point calculation can't
02888      * handle the larger and smaller elements of this equation,
02889      * i.e. speed of light and pulse widths.
02890      */
02891     min_signal_needed = (min_signal_needed + 500) / 1000;
02892     min_signal_needed <<= 4;
02893 
02894     min_signal_needed = (min_signal_needed + 500) / 1000;
02895 
02896     /* FixPoint1616 >> 8 = FixPoint2408 */
02897     signal_limit_tmp = (c_signal_limit + 0x80) >> 8;
02898 
02899     /* FixPoint2408/FixPoint2408 = uint32 */
02900     if (signal_limit_tmp != 0) {
02901         dmax_dark_tmp = (signal_at0_mm + (signal_limit_tmp / 2))
02902                         / signal_limit_tmp;
02903     } else {
02904         dmax_dark_tmp = 0;
02905     }
02906 
02907     dmax_dark = VL53L0X_isqrt(dmax_dark_tmp);
02908 
02909     /* FixPoint2408/FixPoint2408 = uint32 */
02910     if (min_signal_needed != 0) {
02911         dmax_ambient = (signal_at0_mm + min_signal_needed / 2)
02912                        / min_signal_needed;
02913     } else {
02914         dmax_ambient = 0;
02915     }
02916 
02917     dmax_ambient = VL53L0X_isqrt(dmax_ambient);
02918 
02919     *pd_max_mm = dmax_dark;
02920     if (dmax_dark > dmax_ambient) {
02921         *pd_max_mm = dmax_ambient;
02922     }
02923 
02924     LOG_FUNCTION_END(status);
02925 
02926     return status;
02927 }
02928 
02929 VL53L0X_Error VL53L0X::VL53L0X_calc_sigma_estimate(VL53L0X_DEV dev,
02930         VL53L0X_RangingMeasurementData_t *p_ranging_measurement_data,
02931         FixPoint1616_t *p_sigma_estimate,
02932         uint32_t *p_dmax_mm)
02933 {
02934     /* Expressed in 100ths of a ns, i.e. centi-ns */
02935     const uint32_t c_pulse_effective_width_centi_ns   = 800;
02936     /* Expressed in 100ths of a ns, i.e. centi-ns */
02937     const uint32_t c_ambient_effective_width_centi_ns = 600;
02938     const FixPoint1616_t c_dflt_final_range_integration_time_milli_secs = 0x00190000; /* 25ms */
02939     const uint32_t c_vcsel_pulse_width_ps   = 4700; /* pico secs */
02940     const FixPoint1616_t c_sigma_est_max    = 0x028F87AE;
02941     const FixPoint1616_t c_sigma_est_rtn_max    = 0xF000;
02942     const FixPoint1616_t c_amb_to_signal_ratio_max = 0xF0000000 /
02943             c_ambient_effective_width_centi_ns;
02944     /* Time Of Flight per mm (6.6 pico secs) */
02945     const FixPoint1616_t c_tof_per_mm_ps        = 0x0006999A;
02946     const uint32_t c_16bit_rounding_param       = 0x00008000;
02947     const FixPoint1616_t c_max_x_talk_kcps      = 0x00320000;
02948     const uint32_t c_pll_period_ps          = 1655;
02949 
02950     uint32_t vcsel_total_events_rtn;
02951     uint32_t final_range_timeout_micro_secs;
02952     uint32_t pre_range_timeout_micro_secs;
02953     uint32_t final_range_integration_time_milli_secs;
02954     FixPoint1616_t sigma_estimate_p1;
02955     FixPoint1616_t sigma_estimate_p2;
02956     FixPoint1616_t sigma_estimate_p3;
02957     FixPoint1616_t delta_t_ps;
02958     FixPoint1616_t pw_mult;
02959     FixPoint1616_t sigma_est_rtn;
02960     FixPoint1616_t sigma_estimate;
02961     FixPoint1616_t x_talk_correction;
02962     FixPoint1616_t ambient_rate_kcps;
02963     FixPoint1616_t peak_signal_rate_kcps;
02964     FixPoint1616_t x_talk_comp_rate_mcps;
02965     uint32_t x_talk_comp_rate_kcps;
02966     VL53L0X_Error status = VL53L0X_ERROR_NONE;
02967     FixPoint1616_t diff1_mcps;
02968     FixPoint1616_t diff2_mcps;
02969     FixPoint1616_t sqr1;
02970     FixPoint1616_t sqr2;
02971     FixPoint1616_t sqr_sum;
02972     FixPoint1616_t sqrt_result_centi_ns;
02973     FixPoint1616_t sqrt_result;
02974     FixPoint1616_t total_signal_rate_mcps;
02975     FixPoint1616_t corrected_signal_rate_mcps;
02976     FixPoint1616_t sigma_est_ref;
02977     uint32_t vcsel_width;
02978     uint32_t final_range_macro_pclks;
02979     uint32_t pre_range_macro_pclks;
02980     uint32_t peak_vcsel_duration_us;
02981     uint8_t final_range_vcsel_pclks;
02982     uint8_t pre_range_vcsel_pclks;
02983     /*! \addtogroup calc_sigma_estimate
02984      * @{
02985      *
02986      * Estimates the range sigma
02987      */
02988 
02989     LOG_FUNCTION_START("");
02990 
02991     VL53L0X_GETPARAMETERFIELD(dev, XTalkCompensationRateMegaCps,
02992                               x_talk_comp_rate_mcps);
02993 
02994     /*
02995      * We work in kcps rather than mcps as this helps keep within the
02996      * confines of the 32 Fix1616 type.
02997      */
02998 
02999     ambient_rate_kcps =
03000         (p_ranging_measurement_data->AmbientRateRtnMegaCps * 1000) >> 16;
03001 
03002     corrected_signal_rate_mcps =
03003         p_ranging_measurement_data->SignalRateRtnMegaCps;
03004 
03005 
03006     status = VL53L0X_get_total_signal_rate(
03007                  dev, p_ranging_measurement_data, &total_signal_rate_mcps);
03008     status = VL53L0X_get_total_xtalk_rate(
03009                  dev, p_ranging_measurement_data, &x_talk_comp_rate_mcps);
03010 
03011 
03012     /* Signal rate measurement provided by device is the
03013      * peak signal rate, not average.
03014      */
03015     peak_signal_rate_kcps = (total_signal_rate_mcps * 1000);
03016     peak_signal_rate_kcps = (peak_signal_rate_kcps + 0x8000) >> 16;
03017 
03018     x_talk_comp_rate_kcps = x_talk_comp_rate_mcps * 1000;
03019 
03020     if (x_talk_comp_rate_kcps > c_max_x_talk_kcps) {
03021         x_talk_comp_rate_kcps = c_max_x_talk_kcps;
03022     }
03023 
03024     if (status == VL53L0X_ERROR_NONE) {
03025 
03026         /* Calculate final range macro periods */
03027         final_range_timeout_micro_secs = VL53L0X_GETDEVICESPECIFICPARAMETER(
03028                                              dev, FinalRangeTimeoutMicroSecs);
03029 
03030         final_range_vcsel_pclks = VL53L0X_GETDEVICESPECIFICPARAMETER(
03031                                       dev, FinalRangeVcselPulsePeriod);
03032 
03033         final_range_macro_pclks = VL53L0X_calc_timeout_mclks(
03034                                       dev, final_range_timeout_micro_secs, final_range_vcsel_pclks);
03035 
03036         /* Calculate pre-range macro periods */
03037         pre_range_timeout_micro_secs = VL53L0X_GETDEVICESPECIFICPARAMETER(
03038                                            dev, PreRangeTimeoutMicroSecs);
03039 
03040         pre_range_vcsel_pclks = VL53L0X_GETDEVICESPECIFICPARAMETER(
03041                                     dev, PreRangeVcselPulsePeriod);
03042 
03043         pre_range_macro_pclks = VL53L0X_calc_timeout_mclks(
03044                                     dev, pre_range_timeout_micro_secs, pre_range_vcsel_pclks);
03045 
03046         vcsel_width = 3;
03047         if (final_range_vcsel_pclks == 8) {
03048             vcsel_width = 2;
03049         }
03050 
03051 
03052         peak_vcsel_duration_us = vcsel_width * 2048 *
03053                                  (pre_range_macro_pclks + final_range_macro_pclks);
03054         peak_vcsel_duration_us = (peak_vcsel_duration_us + 500) / 1000;
03055         peak_vcsel_duration_us *= c_pll_period_ps;
03056         peak_vcsel_duration_us = (peak_vcsel_duration_us + 500) / 1000;
03057 
03058         /* Fix1616 >> 8 = Fix2408 */
03059         total_signal_rate_mcps = (total_signal_rate_mcps + 0x80) >> 8;
03060 
03061         /* Fix2408 * uint32 = Fix2408 */
03062         vcsel_total_events_rtn = total_signal_rate_mcps *
03063                                  peak_vcsel_duration_us;
03064 
03065         /* Fix2408 >> 8 = uint32 */
03066         vcsel_total_events_rtn = (vcsel_total_events_rtn + 0x80) >> 8;
03067 
03068         /* Fix2408 << 8 = Fix1616 = */
03069         total_signal_rate_mcps <<= 8;
03070     }
03071 
03072     if (status != VL53L0X_ERROR_NONE) {
03073         LOG_FUNCTION_END(status);
03074         return status;
03075     }
03076 
03077     if (peak_signal_rate_kcps == 0) {
03078         *p_sigma_estimate = c_sigma_est_max;
03079         PALDevDataSet(dev, SigmaEstimate, c_sigma_est_max);
03080         *p_dmax_mm = 0;
03081     } else {
03082         if (vcsel_total_events_rtn < 1) {
03083             vcsel_total_events_rtn = 1;
03084         }
03085 
03086         sigma_estimate_p1 = c_pulse_effective_width_centi_ns;
03087 
03088         /* ((FixPoint1616 << 16)* uint32)/uint32 = FixPoint1616 */
03089         sigma_estimate_p2 = (ambient_rate_kcps << 16) / peak_signal_rate_kcps;
03090         if (sigma_estimate_p2 > c_amb_to_signal_ratio_max) {
03091             /* Clip to prevent overflow. Will ensure safe
03092              * max result. */
03093             sigma_estimate_p2 = c_amb_to_signal_ratio_max;
03094         }
03095         sigma_estimate_p2 *= c_ambient_effective_width_centi_ns;
03096 
03097         sigma_estimate_p3 = 2 * VL53L0X_isqrt(vcsel_total_events_rtn * 12);
03098 
03099         /* uint32 * FixPoint1616 = FixPoint1616 */
03100         delta_t_ps = p_ranging_measurement_data->RangeMilliMeter *
03101                      c_tof_per_mm_ps;
03102 
03103         /*
03104          * vcselRate - xtalkCompRate
03105          * (uint32 << 16) - FixPoint1616 = FixPoint1616.
03106          * Divide result by 1000 to convert to mcps.
03107          * 500 is added to ensure rounding when integer division
03108          * truncates.
03109          */
03110         diff1_mcps = (((peak_signal_rate_kcps << 16) -
03111                        2 * x_talk_comp_rate_kcps) + 500) / 1000;
03112 
03113         /* vcselRate + xtalkCompRate */
03114         diff2_mcps = ((peak_signal_rate_kcps << 16) + 500) / 1000;
03115 
03116         /* Shift by 8 bits to increase resolution prior to the
03117          * division */
03118         diff1_mcps <<= 8;
03119 
03120         /* FixPoint0824/FixPoint1616 = FixPoint2408 */
03121 //      xTalkCorrection  = abs(diff1_mcps/diff2_mcps);
03122 // abs is causing compiler overloading isue in C++, but unsigned types. So, redundant call anyway!
03123         x_talk_correction    = diff1_mcps / diff2_mcps;
03124 
03125         /* FixPoint2408 << 8 = FixPoint1616 */
03126         x_talk_correction <<= 8;
03127 
03128         if (p_ranging_measurement_data->RangeStatus != 0) {
03129             pw_mult = 1 << 16;
03130         } else {
03131             /* FixPoint1616/uint32 = FixPoint1616 */
03132             pw_mult = delta_t_ps / c_vcsel_pulse_width_ps; /* smaller than 1.0f */
03133 
03134             /*
03135              * FixPoint1616 * FixPoint1616 = FixPoint3232, however both
03136              * values are small enough such that32 bits will not be
03137              * exceeded.
03138              */
03139             pw_mult *= ((1 << 16) - x_talk_correction);
03140 
03141             /* (FixPoint3232 >> 16) = FixPoint1616 */
03142             pw_mult = (pw_mult + c_16bit_rounding_param) >> 16;
03143 
03144             /* FixPoint1616 + FixPoint1616 = FixPoint1616 */
03145             pw_mult += (1 << 16);
03146 
03147             /*
03148              * At this point the value will be 1.xx, therefore if we square
03149              * the value this will exceed 32 bits. To address this perform
03150              * a single shift to the right before the multiplication.
03151              */
03152             pw_mult >>= 1;
03153             /* FixPoint1715 * FixPoint1715 = FixPoint3430 */
03154             pw_mult = pw_mult * pw_mult;
03155 
03156             /* (FixPoint3430 >> 14) = Fix1616 */
03157             pw_mult >>= 14;
03158         }
03159 
03160         /* FixPoint1616 * uint32 = FixPoint1616 */
03161         sqr1 = pw_mult * sigma_estimate_p1;
03162 
03163         /* (FixPoint1616 >> 16) = FixPoint3200 */
03164         sqr1 = (sqr1 + 0x8000) >> 16;
03165 
03166         /* FixPoint3200 * FixPoint3200 = FixPoint6400 */
03167         sqr1 *= sqr1;
03168 
03169         sqr2 = sigma_estimate_p2;
03170 
03171         /* (FixPoint1616 >> 16) = FixPoint3200 */
03172         sqr2 = (sqr2 + 0x8000) >> 16;
03173 
03174         /* FixPoint3200 * FixPoint3200 = FixPoint6400 */
03175         sqr2 *= sqr2;
03176 
03177         /* FixPoint64000 + FixPoint6400 = FixPoint6400 */
03178         sqr_sum = sqr1 + sqr2;
03179 
03180         /* SQRT(FixPoin6400) = FixPoint3200 */
03181         sqrt_result_centi_ns = VL53L0X_isqrt(sqr_sum);
03182 
03183         /* (FixPoint3200 << 16) = FixPoint1616 */
03184         sqrt_result_centi_ns <<= 16;
03185 
03186         /*
03187          * Note that the Speed Of Light is expressed in um per 1E-10
03188          * seconds (2997) Therefore to get mm/ns we have to divide by
03189          * 10000
03190          */
03191         sigma_est_rtn = (((sqrt_result_centi_ns + 50) / 100) /
03192                          sigma_estimate_p3);
03193         sigma_est_rtn        *= VL53L0X_SPEED_OF_LIGHT_IN_AIR;
03194 
03195         /* Add 5000 before dividing by 10000 to ensure rounding. */
03196         sigma_est_rtn        += 5000;
03197         sigma_est_rtn        /= 10000;
03198 
03199         if (sigma_est_rtn > c_sigma_est_rtn_max) {
03200             /* Clip to prevent overflow. Will ensure safe
03201              * max result. */
03202             sigma_est_rtn = c_sigma_est_rtn_max;
03203         }
03204         final_range_integration_time_milli_secs =
03205             (final_range_timeout_micro_secs + pre_range_timeout_micro_secs + 500) / 1000;
03206 
03207         /* sigmaEstRef = 1mm * 25ms/final range integration time (inc pre-range)
03208          * sqrt(FixPoint1616/int) = FixPoint2408)
03209          */
03210         sigma_est_ref =
03211             VL53L0X_isqrt((c_dflt_final_range_integration_time_milli_secs +
03212                            final_range_integration_time_milli_secs / 2) /
03213                           final_range_integration_time_milli_secs);
03214 
03215         /* FixPoint2408 << 8 = FixPoint1616 */
03216         sigma_est_ref <<= 8;
03217         sigma_est_ref = (sigma_est_ref + 500) / 1000;
03218 
03219         /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
03220         sqr1 = sigma_est_rtn * sigma_est_rtn;
03221         /* FixPoint1616 * FixPoint1616 = FixPoint3232 */
03222         sqr2 = sigma_est_ref * sigma_est_ref;
03223 
03224         /* sqrt(FixPoint3232) = FixPoint1616 */
03225         sqrt_result = VL53L0X_isqrt((sqr1 + sqr2));
03226         /*
03227          * Note that the Shift by 4 bits increases resolution prior to
03228          * the sqrt, therefore the result must be shifted by 2 bits to
03229          * the right to revert back to the FixPoint1616 format.
03230          */
03231 
03232         sigma_estimate   = 1000 * sqrt_result;
03233 
03234         if ((peak_signal_rate_kcps < 1) || (vcsel_total_events_rtn < 1) ||
03235                 (sigma_estimate > c_sigma_est_max)) {
03236             sigma_estimate = c_sigma_est_max;
03237         }
03238 
03239         *p_sigma_estimate = (uint32_t)(sigma_estimate);
03240         PALDevDataSet(dev, SigmaEstimate, *p_sigma_estimate);
03241         status = VL53L0X_calc_dmax(
03242                      dev,
03243                      total_signal_rate_mcps,
03244                      corrected_signal_rate_mcps,
03245                      pw_mult,
03246                      sigma_estimate_p1,
03247                      sigma_estimate_p2,
03248                      peak_vcsel_duration_us,
03249                      p_dmax_mm);
03250     }
03251 
03252     LOG_FUNCTION_END(status);
03253     return status;
03254 }
03255 
03256 VL53L0X_Error VL53L0X::VL53L0X_get_pal_range_status(VL53L0X_DEV dev,
03257         uint8_t device_range_status,
03258         FixPoint1616_t signal_rate,
03259         uint16_t effective_spad_rtn_count,
03260         VL53L0X_RangingMeasurementData_t *p_ranging_measurement_data,
03261         uint8_t *p_pal_range_status)
03262 {
03263     VL53L0X_Error status = VL53L0X_ERROR_NONE;
03264     uint8_t none_flag;
03265     uint8_t sigma_limitflag = 0;
03266     uint8_t signal_ref_clipflag = 0;
03267     uint8_t range_ignore_thresholdflag = 0;
03268     uint8_t sigma_limit_check_enable = 0;
03269     uint8_t signal_rate_final_range_limit_check_enable = 0;
03270     uint8_t signal_ref_clip_limit_check_enable = 0;
03271     uint8_t range_ignore_threshold_limit_check_enable = 0;
03272     FixPoint1616_t sigma_estimate;
03273     FixPoint1616_t sigma_limit_value;
03274     FixPoint1616_t signal_ref_clip_value;
03275     FixPoint1616_t range_ignore_threshold_value;
03276     FixPoint1616_t signal_rate_per_spad;
03277     uint8_t device_range_status_internal = 0;
03278     uint16_t tmp_word = 0;
03279     uint8_t temp8;
03280     uint32_t dmax_mm = 0;
03281     FixPoint1616_t last_signal_ref_mcps;
03282 
03283     LOG_FUNCTION_START("");
03284 
03285 
03286     /*
03287      * VL53L0X has a good ranging when the value of the
03288      * DeviceRangeStatus = 11. This function will replace the value 0 with
03289      * the value 11 in the DeviceRangeStatus.
03290      * In addition, the SigmaEstimator is not included in the VL53L0X
03291      * DeviceRangeStatus, this will be added in the PalRangeStatus.
03292      */
03293 
03294     device_range_status_internal = ((device_range_status & 0x78) >> 3);
03295 
03296     if (device_range_status_internal == 0 ||
03297             device_range_status_internal == 5 ||
03298             device_range_status_internal == 7 ||
03299             device_range_status_internal == 12 ||
03300             device_range_status_internal == 13 ||
03301             device_range_status_internal == 14 ||
03302             device_range_status_internal == 15
03303        ) {
03304         none_flag = 1;
03305     } else {
03306         none_flag = 0;
03307     }
03308 
03309     /*
03310      * Check if Sigma limit is enabled, if yes then do comparison with limit
03311      * value and put the result back into pPalRangeStatus.
03312      */
03313     if (status == VL53L0X_ERROR_NONE) {
03314         status =  VL53L0X_get_limit_check_enable(dev,
03315                   VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
03316                   &sigma_limit_check_enable);
03317     }
03318 
03319     if ((sigma_limit_check_enable != 0) && (status == VL53L0X_ERROR_NONE)) {
03320         /*
03321         * compute the Sigma and check with limit
03322         */
03323         status = VL53L0X_calc_sigma_estimate(
03324                      dev,
03325                      p_ranging_measurement_data,
03326                      &sigma_estimate,
03327                      &dmax_mm);
03328         if (status == VL53L0X_ERROR_NONE) {
03329             p_ranging_measurement_data->RangeDMaxMilliMeter = dmax_mm;
03330         }
03331 
03332         if (status == VL53L0X_ERROR_NONE) {
03333             status = VL53L0X_get_limit_check_value(dev,
03334                                                    VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
03335                                                    &sigma_limit_value);
03336 
03337             if ((sigma_limit_value > 0) &&
03338                     (sigma_estimate > sigma_limit_value)) {
03339                 /* Limit Fail */
03340                 sigma_limitflag = 1;
03341             }
03342         }
03343     }
03344 
03345     /*
03346      * Check if Signal ref clip limit is enabled, if yes then do comparison
03347      * with limit value and put the result back into pPalRangeStatus.
03348      */
03349     if (status == VL53L0X_ERROR_NONE) {
03350         status =  VL53L0X_get_limit_check_enable(dev,
03351                   VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP,
03352                   &signal_ref_clip_limit_check_enable);
03353     }
03354 
03355     if ((signal_ref_clip_limit_check_enable != 0) &&
03356             (status == VL53L0X_ERROR_NONE)) {
03357 
03358         status = VL53L0X_get_limit_check_value(dev,
03359                                                VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP,
03360                                                &signal_ref_clip_value);
03361 
03362         /* Read LastSignalRefMcps from device */
03363         if (status == VL53L0X_ERROR_NONE) {
03364             status = VL53L0X_write_byte(dev, 0xFF, 0x01);
03365         }
03366 
03367         if (status == VL53L0X_ERROR_NONE) {
03368             status = VL53L0X_read_word(dev,
03369                                        VL53L0X_REG_RESULT_PEAK_SIGNAL_RATE_REF,
03370                                        &tmp_word);
03371         }
03372 
03373         if (status == VL53L0X_ERROR_NONE) {
03374             status = VL53L0X_write_byte(dev, 0xFF, 0x00);
03375         }
03376 
03377         last_signal_ref_mcps = VL53L0X_FIXPOINT97TOFIXPOINT1616(tmp_word);
03378         PALDevDataSet(dev, LastSignalRefMcps, last_signal_ref_mcps);
03379 
03380         if ((signal_ref_clip_value > 0) &&
03381                 (last_signal_ref_mcps > signal_ref_clip_value)) {
03382             /* Limit Fail */
03383             signal_ref_clipflag = 1;
03384         }
03385     }
03386 
03387     /*
03388      * Check if Signal ref clip limit is enabled, if yes then do comparison
03389      * with limit value and put the result back into pPalRangeStatus.
03390      * EffectiveSpadRtnCount has a format 8.8
03391      * If (Return signal rate < (1.5 x Xtalk x number of Spads)) : FAIL
03392      */
03393     if (status == VL53L0X_ERROR_NONE) {
03394         status =  VL53L0X_get_limit_check_enable(dev,
03395                   VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
03396                   &range_ignore_threshold_limit_check_enable);
03397     }
03398 
03399     if ((range_ignore_threshold_limit_check_enable != 0) &&
03400             (status == VL53L0X_ERROR_NONE)) {
03401 
03402         /* Compute the signal rate per spad */
03403         if (effective_spad_rtn_count == 0) {
03404             signal_rate_per_spad = 0;
03405         } else {
03406             signal_rate_per_spad = (FixPoint1616_t)((256 * signal_rate)
03407                                                     / effective_spad_rtn_count);
03408         }
03409 
03410         status = VL53L0X_get_limit_check_value(dev,
03411                                                VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
03412                                                &range_ignore_threshold_value);
03413 
03414         if ((range_ignore_threshold_value > 0) &&
03415                 (signal_rate_per_spad < range_ignore_threshold_value)) {
03416             /* Limit Fail add 2^6 to range status */
03417             range_ignore_thresholdflag = 1;
03418         }
03419     }
03420 
03421     if (status == VL53L0X_ERROR_NONE) {
03422         if (none_flag == 1) {
03423             *p_pal_range_status = 255;   /* NONE */
03424         } else if (device_range_status_internal == 1 ||
03425                    device_range_status_internal == 2 ||
03426                    device_range_status_internal == 3) {
03427             *p_pal_range_status = 5; /* HW fail */
03428         } else if (device_range_status_internal == 6 ||
03429                    device_range_status_internal == 9) {
03430             *p_pal_range_status = 4;  /* Phase fail */
03431         } else if (device_range_status_internal == 8 ||
03432                    device_range_status_internal == 10 ||
03433                    signal_ref_clipflag == 1) {
03434             *p_pal_range_status = 3;  /* Min range */
03435         } else if (device_range_status_internal == 4 ||
03436                    range_ignore_thresholdflag == 1) {
03437             *p_pal_range_status = 2;  /* Signal Fail */
03438         } else if (sigma_limitflag == 1) {
03439             *p_pal_range_status = 1;  /* Sigma   Fail */
03440         } else {
03441             *p_pal_range_status = 0; /* Range Valid */
03442         }
03443     }
03444 
03445     /* DMAX only relevant during range error */
03446     if (*p_pal_range_status == 0) {
03447         p_ranging_measurement_data->RangeDMaxMilliMeter = 0;
03448     }
03449 
03450     /* fill the Limit Check Status */
03451 
03452     status =  VL53L0X_get_limit_check_enable(dev,
03453               VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
03454               &signal_rate_final_range_limit_check_enable);
03455 
03456     if (status == VL53L0X_ERROR_NONE) {
03457         if ((sigma_limit_check_enable == 0) || (sigma_limitflag == 1)) {
03458             temp8 = 1;
03459         } else {
03460             temp8 = 0;
03461         }
03462         VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksStatus,
03463                                        VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, temp8);
03464 
03465         if ((device_range_status_internal == 4) ||
03466                 (signal_rate_final_range_limit_check_enable == 0)) {
03467             temp8 = 1;
03468         } else {
03469             temp8 = 0;
03470         }
03471         VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksStatus,
03472                                        VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE,
03473                                        temp8);
03474 
03475         if ((signal_ref_clip_limit_check_enable == 0) ||
03476                 (signal_ref_clipflag == 1)) {
03477             temp8 = 1;
03478         } else {
03479             temp8 = 0;
03480         }
03481 
03482         VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksStatus,
03483                                        VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP, temp8);
03484 
03485         if ((range_ignore_threshold_limit_check_enable == 0) ||
03486                 (range_ignore_thresholdflag == 1)) {
03487             temp8 = 1;
03488         } else {
03489             temp8 = 0;
03490         }
03491 
03492         VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksStatus,
03493                                        VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
03494                                        temp8);
03495     }
03496 
03497     LOG_FUNCTION_END(status);
03498     return status;
03499 
03500 }
03501 
03502 VL53L0X_Error VL53L0X::VL53L0X_get_ranging_measurement_data(VL53L0X_DEV dev,
03503         VL53L0X_RangingMeasurementData_t *p_ranging_measurement_data)
03504 {
03505     VL53L0X_Error status = VL53L0X_ERROR_NONE;
03506     uint8_t device_range_status;
03507     uint8_t range_fractional_enable;
03508     uint8_t pal_range_status;
03509     uint8_t x_talk_compensation_enable;
03510     uint16_t ambient_rate;
03511     FixPoint1616_t signal_rate;
03512     uint16_t x_talk_compensation_rate_mega_cps;
03513     uint16_t effective_spad_rtn_count;
03514     uint16_t tmpuint16;
03515     uint16_t xtalk_range_milli_meter;
03516     uint16_t linearity_corrective_gain;
03517     uint8_t localBuffer[12];
03518     VL53L0X_RangingMeasurementData_t last_range_data_buffer;
03519 
03520     LOG_FUNCTION_START("");
03521 
03522     /*
03523      * use multi read even if some registers are not useful, result will
03524      * be more efficient
03525      * start reading at 0x14 dec20
03526      * end reading at 0x21 dec33 total 14 bytes to read
03527      */
03528     status = VL53L0X_read_multi(dev, 0x14, localBuffer, 12);
03529 
03530     if (status == VL53L0X_ERROR_NONE) {
03531 
03532         p_ranging_measurement_data->ZoneId = 0; /* Only one zone */
03533         p_ranging_measurement_data->TimeStamp = 0; /* Not Implemented */
03534 
03535         tmpuint16 = VL53L0X_MAKEUINT16(localBuffer[11], localBuffer[10]);
03536         /* cut1.1 if SYSTEM__RANGE_CONFIG if 1 range is 2bits fractional
03537          *(format 11.2) else no fractional
03538          */
03539 
03540         p_ranging_measurement_data->MeasurementTimeUsec = 0;
03541 
03542         signal_rate = VL53L0X_FIXPOINT97TOFIXPOINT1616(
03543                           VL53L0X_MAKEUINT16(localBuffer[7], localBuffer[6]));
03544         /* peak_signal_count_rate_rtn_mcps */
03545         p_ranging_measurement_data->SignalRateRtnMegaCps = signal_rate;
03546 
03547         ambient_rate = VL53L0X_MAKEUINT16(localBuffer[9], localBuffer[8]);
03548         p_ranging_measurement_data->AmbientRateRtnMegaCps =
03549             VL53L0X_FIXPOINT97TOFIXPOINT1616(ambient_rate);
03550 
03551         effective_spad_rtn_count = VL53L0X_MAKEUINT16(localBuffer[3],
03552                                    localBuffer[2]);
03553         /* EffectiveSpadRtnCount is 8.8 format */
03554         p_ranging_measurement_data->EffectiveSpadRtnCount =
03555             effective_spad_rtn_count;
03556 
03557         device_range_status = localBuffer[0];
03558 
03559         /* Get Linearity Corrective Gain */
03560         linearity_corrective_gain = PALDevDataGet(dev,
03561                                     LinearityCorrectiveGain);
03562 
03563         /* Get ranging configuration */
03564         range_fractional_enable = PALDevDataGet(dev,
03565                                                 RangeFractionalEnable);
03566 
03567         if (linearity_corrective_gain != 1000) {
03568 
03569             tmpuint16 = (uint16_t)((linearity_corrective_gain
03570                                     * tmpuint16 + 500) / 1000);
03571 
03572             /* Implement Xtalk */
03573             VL53L0X_GETPARAMETERFIELD(dev,
03574                                       XTalkCompensationRateMegaCps,
03575                                       x_talk_compensation_rate_mega_cps);
03576             VL53L0X_GETPARAMETERFIELD(dev, XTalkCompensationEnable,
03577                                       x_talk_compensation_enable);
03578 
03579             if (x_talk_compensation_enable) {
03580 
03581                 if ((signal_rate
03582                         - ((x_talk_compensation_rate_mega_cps
03583                             * effective_spad_rtn_count) >> 8))
03584                         <= 0) {
03585                     if (range_fractional_enable) {
03586                         xtalk_range_milli_meter = 8888;
03587                     } else {
03588                         xtalk_range_milli_meter = 8888 << 2;
03589                     }
03590                 } else {
03591                     xtalk_range_milli_meter =
03592                         (tmpuint16 * signal_rate)
03593                         / (signal_rate
03594                            - ((x_talk_compensation_rate_mega_cps
03595                                * effective_spad_rtn_count)
03596                               >> 8));
03597                 }
03598 
03599                 tmpuint16 = xtalk_range_milli_meter;
03600             }
03601 
03602         }
03603 
03604         if (range_fractional_enable) {
03605             p_ranging_measurement_data->RangeMilliMeter =
03606                 (uint16_t)((tmpuint16) >> 2);
03607             p_ranging_measurement_data->RangeFractionalPart =
03608                 (uint8_t)((tmpuint16 & 0x03) << 6);
03609         } else {
03610             p_ranging_measurement_data->RangeMilliMeter = tmpuint16;
03611             p_ranging_measurement_data->RangeFractionalPart = 0;
03612         }
03613 
03614         /*
03615          * For a standard definition of RangeStatus, this should
03616          * return 0 in case of good result after a ranging
03617          * The range status depends on the device so call a device
03618          * specific function to obtain the right Status.
03619          */
03620         status |= VL53L0X_get_pal_range_status(dev, device_range_status,
03621                                                signal_rate, effective_spad_rtn_count,
03622                                                p_ranging_measurement_data, &pal_range_status);
03623 
03624         if (status == VL53L0X_ERROR_NONE) {
03625             p_ranging_measurement_data->RangeStatus = pal_range_status;
03626         }
03627 
03628     }
03629 
03630     if (status == VL53L0X_ERROR_NONE) {
03631         /* Copy last read data into Dev buffer */
03632         last_range_data_buffer = PALDevDataGet(dev, LastRangeMeasure);
03633 
03634         last_range_data_buffer.RangeMilliMeter =
03635             p_ranging_measurement_data->RangeMilliMeter;
03636         last_range_data_buffer.RangeFractionalPart =
03637             p_ranging_measurement_data->RangeFractionalPart;
03638         last_range_data_buffer.RangeDMaxMilliMeter =
03639             p_ranging_measurement_data->RangeDMaxMilliMeter;
03640         last_range_data_buffer.MeasurementTimeUsec =
03641             p_ranging_measurement_data->MeasurementTimeUsec;
03642         last_range_data_buffer.SignalRateRtnMegaCps =
03643             p_ranging_measurement_data->SignalRateRtnMegaCps;
03644         last_range_data_buffer.AmbientRateRtnMegaCps =
03645             p_ranging_measurement_data->AmbientRateRtnMegaCps;
03646         last_range_data_buffer.EffectiveSpadRtnCount =
03647             p_ranging_measurement_data->EffectiveSpadRtnCount;
03648         last_range_data_buffer.RangeStatus =
03649             p_ranging_measurement_data->RangeStatus;
03650 
03651         PALDevDataSet(dev, LastRangeMeasure, last_range_data_buffer);
03652     }
03653 
03654     LOG_FUNCTION_END(status);
03655     return status;
03656 }
03657 
03658 VL53L0X_Error VL53L0X::VL53L0X_perform_single_ranging_measurement(VL53L0X_DEV dev,
03659         VL53L0X_RangingMeasurementData_t *p_ranging_measurement_data)
03660 {
03661     VL53L0X_Error status = VL53L0X_ERROR_NONE;
03662 
03663     LOG_FUNCTION_START("");
03664 
03665     /* This function will do a complete single ranging
03666      * Here we fix the mode! */
03667     status = VL53L0X_set_device_mode(dev, VL53L0X_DEVICEMODE_SINGLE_RANGING);
03668 
03669     if (status == VL53L0X_ERROR_NONE) {
03670         status = VL53L0X_perform_single_measurement(dev);
03671     }
03672 
03673     if (status == VL53L0X_ERROR_NONE) {
03674         status = VL53L0X_get_ranging_measurement_data(dev,
03675                  p_ranging_measurement_data);
03676     }
03677 
03678     if (status == VL53L0X_ERROR_NONE) {
03679         status = VL53L0X_clear_interrupt_mask(dev, 0);
03680     }
03681 
03682     LOG_FUNCTION_END(status);
03683     return status;
03684 }
03685 
03686 VL53L0X_Error VL53L0X::perform_ref_signal_measurement(VL53L0X_DEV dev,
03687         uint16_t *p_ref_signal_rate)
03688 {
03689     VL53L0X_Error status = VL53L0X_ERROR_NONE;
03690     VL53L0X_RangingMeasurementData_t ranging_measurement_data;
03691 
03692     uint8_t sequence_config = 0;
03693 
03694     /* store the value of the sequence config,
03695      * this will be reset before the end of the function
03696      */
03697 
03698     sequence_config = PALDevDataGet(dev, SequenceConfig);
03699 
03700     /*
03701      * This function performs a reference signal rate measurement.
03702      */
03703     if (status == VL53L0X_ERROR_NONE) {
03704         status = VL53L0X_write_byte(dev,
03705                                     VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, 0xC0);
03706     }
03707 
03708     if (status == VL53L0X_ERROR_NONE) {
03709         status = VL53L0X_perform_single_ranging_measurement(dev,
03710                  &ranging_measurement_data);
03711     }
03712 
03713     if (status == VL53L0X_ERROR_NONE) {
03714         status = VL53L0X_write_byte(dev, 0xFF, 0x01);
03715     }
03716 
03717     if (status == VL53L0X_ERROR_NONE) {
03718         status = VL53L0X_read_word(dev,
03719                                    VL53L0X_REG_RESULT_PEAK_SIGNAL_RATE_REF,
03720                                    p_ref_signal_rate);
03721     }
03722 
03723     if (status == VL53L0X_ERROR_NONE) {
03724         status = VL53L0X_write_byte(dev, 0xFF, 0x00);
03725     }
03726 
03727     if (status == VL53L0X_ERROR_NONE) {
03728         /* restore the previous Sequence Config */
03729         status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
03730                                     sequence_config);
03731         if (status == VL53L0X_ERROR_NONE) {
03732             PALDevDataSet(dev, SequenceConfig, sequence_config);
03733         }
03734     }
03735 
03736     return status;
03737 }
03738 
03739 VL53L0X_Error VL53L0X::wrapped_VL53L0X_perform_ref_spad_management(VL53L0X_DEV dev,
03740         uint32_t *ref_spad_count,
03741         uint8_t *is_aperture_spads)
03742 {
03743     VL53L0X_Error status = VL53L0X_ERROR_NONE;
03744     uint8_t last_spad_array[6];
03745     uint8_t start_select = 0xB4;
03746     uint32_t minimum_spad_count = 3;
03747     uint32_t max_spad_count = 44;
03748     uint32_t current_spad_index = 0;
03749     uint32_t last_spad_index = 0;
03750     int32_t next_good_spad = 0;
03751     uint16_t target_ref_rate = 0x0A00; /* 20 MCPS in 9:7 format */
03752     uint16_t peak_signal_rate_ref;
03753     uint32_t need_apt_spads = 0;
03754     uint32_t index = 0;
03755     uint32_t spad_array_size = 6;
03756     uint32_t signal_rate_diff = 0;
03757     uint32_t last_signal_rate_diff = 0;
03758     uint8_t complete = 0;
03759     uint8_t vhv_settings = 0;
03760     uint8_t phase_cal = 0;
03761     uint32_t ref_spad_count_int = 0;
03762     uint8_t  is_aperture_spads_int = 0;
03763 
03764     /*
03765      * The reference SPAD initialization procedure determines the minimum
03766      * amount of reference spads to be enables to achieve a target reference
03767      * signal rate and should be performed once during initialization.
03768      *
03769      * Either aperture or non-aperture spads are applied but never both.
03770      * Firstly non-aperture spads are set, begining with 5 spads, and
03771      * increased one spad at a time until the closest measurement to the
03772      * target rate is achieved.
03773      *
03774      * If the target rate is exceeded when 5 non-aperture spads are enabled,
03775      * initialization is performed instead with aperture spads.
03776      *
03777      * When setting spads, a 'Good Spad Map' is applied.
03778      *
03779      * This procedure operates within a SPAD window of interest of a maximum
03780      * 44 spads.
03781      * The start point is currently fixed to 180, which lies towards the end
03782      * of the non-aperture quadrant and runs in to the adjacent aperture
03783      * quadrant.
03784      */
03785     target_ref_rate = PALDevDataGet(dev, targetRefRate);
03786 
03787     /*
03788      * Initialize Spad arrays.
03789      * Currently the good spad map is initialised to 'All good'.
03790      * This is a short term implementation. The good spad map will be
03791      * provided as an input.
03792      * Note that there are 6 bytes. Only the first 44 bits will be used to
03793      * represent spads.
03794      */
03795     for (index = 0; index < spad_array_size; index++) {
03796         dev->Data .SpadData .RefSpadEnables [index] = 0;
03797     }
03798 
03799 
03800     status = VL53L0X_write_byte(dev, 0xFF, 0x01);
03801 
03802     if (status == VL53L0X_ERROR_NONE) {
03803         status = VL53L0X_write_byte(dev,
03804                                     VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
03805     }
03806 
03807     if (status == VL53L0X_ERROR_NONE) {
03808         status = VL53L0X_write_byte(dev,
03809                                     VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
03810     }
03811 
03812     if (status == VL53L0X_ERROR_NONE) {
03813         status = VL53L0X_write_byte(dev, 0xFF, 0x00);
03814     }
03815 
03816     if (status == VL53L0X_ERROR_NONE) {
03817         status = VL53L0X_write_byte(dev,
03818                                     VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
03819                                     start_select);
03820     }
03821 
03822     if (status == VL53L0X_ERROR_NONE) {
03823         status = VL53L0X_write_byte(dev,
03824                                     VL53L0X_REG_POWER_MANAGEMENT_GO1_POWER_FORCE, 0);
03825     }
03826 
03827     /* Perform ref calibration */
03828     if (status == VL53L0X_ERROR_NONE) {
03829         status = VL53L0X_perform_ref_calibration(dev, &vhv_settings,
03830                  &phase_cal, 0);
03831     }
03832 
03833     if (status == VL53L0X_ERROR_NONE) {
03834         /* Enable Minimum NON-APERTURE Spads */
03835         current_spad_index = 0;
03836         last_spad_index = current_spad_index;
03837         need_apt_spads = 0;
03838         status = enable_ref_spads(dev,
03839                                   need_apt_spads,
03840                                   dev->Data .SpadData .RefGoodSpadMap ,
03841                                   dev->Data .SpadData .RefSpadEnables ,
03842                                   spad_array_size,
03843                                   start_select,
03844                                   current_spad_index,
03845                                   minimum_spad_count,
03846                                   &last_spad_index);
03847     }
03848 
03849     if (status == VL53L0X_ERROR_NONE) {
03850         current_spad_index = last_spad_index;
03851 
03852         status = perform_ref_signal_measurement(dev,
03853                                                 &peak_signal_rate_ref);
03854         if ((status == VL53L0X_ERROR_NONE) &&
03855                 (peak_signal_rate_ref > target_ref_rate)) {
03856             /* Signal rate measurement too high,
03857              * switch to APERTURE SPADs */
03858 
03859             for (index = 0; index < spad_array_size; index++) {
03860                 dev->Data .SpadData .RefSpadEnables [index] = 0;
03861             }
03862 
03863 
03864             /* Increment to the first APERTURE spad */
03865             while ((is_aperture(start_select + current_spad_index)
03866                     == 0) && (current_spad_index < max_spad_count)) {
03867                 current_spad_index++;
03868             }
03869 
03870             need_apt_spads = 1;
03871 
03872             status = enable_ref_spads(dev,
03873                                       need_apt_spads,
03874                                       dev->Data .SpadData .RefGoodSpadMap ,
03875                                       dev->Data .SpadData .RefSpadEnables ,
03876                                       spad_array_size,
03877                                       start_select,
03878                                       current_spad_index,
03879                                       minimum_spad_count,
03880                                       &last_spad_index);
03881 
03882             if (status == VL53L0X_ERROR_NONE) {
03883                 current_spad_index = last_spad_index;
03884                 status = perform_ref_signal_measurement(dev,
03885                                                         &peak_signal_rate_ref);
03886 
03887                 if ((status == VL53L0X_ERROR_NONE) &&
03888                         (peak_signal_rate_ref > target_ref_rate)) {
03889                     /* Signal rate still too high after
03890                      * setting the minimum number of
03891                      * APERTURE spads. Can do no more
03892                      * therefore set the min number of
03893                      * aperture spads as the result.
03894                      */
03895                     is_aperture_spads_int = 1;
03896                     ref_spad_count_int = minimum_spad_count;
03897                 }
03898             }
03899         } else {
03900             need_apt_spads = 0;
03901         }
03902     }
03903 
03904     if ((status == VL53L0X_ERROR_NONE) &&
03905             (peak_signal_rate_ref < target_ref_rate)) {
03906         /* At this point, the minimum number of either aperture
03907          * or non-aperture spads have been set. Proceed to add
03908          * spads and perform measurements until the target
03909          * reference is reached.
03910          */
03911         is_aperture_spads_int = need_apt_spads;
03912         ref_spad_count_int  = minimum_spad_count;
03913 
03914         memcpy(last_spad_array, dev->Data .SpadData .RefSpadEnables ,
03915                spad_array_size);
03916         last_signal_rate_diff = abs(peak_signal_rate_ref -
03917                                     target_ref_rate);
03918         complete = 0;
03919 
03920         while (!complete) {
03921             get_next_good_spad(
03922                 dev->Data .SpadData .RefGoodSpadMap ,
03923                 spad_array_size, current_spad_index,
03924                 &next_good_spad);
03925 
03926             if (next_good_spad == -1) {
03927                 status = VL53L0X_ERROR_REF_SPAD_INIT;
03928                 break;
03929             }
03930 
03931             /* Cannot combine Aperture and Non-Aperture spads, so
03932              * ensure the current spad is of the correct type.
03933              */
03934             if (is_aperture((uint32_t)start_select + next_good_spad) !=
03935                     need_apt_spads) {
03936                 /* At this point we have enabled the maximum
03937                  * number of Aperture spads.
03938                  */
03939                 complete = 1;
03940                 break;
03941             }
03942 
03943             (ref_spad_count_int)++;
03944 
03945             current_spad_index = next_good_spad;
03946             status = enable_spad_bit(
03947                          dev->Data .SpadData .RefSpadEnables ,
03948                          spad_array_size, current_spad_index);
03949 
03950             if (status == VL53L0X_ERROR_NONE) {
03951                 current_spad_index++;
03952                 /* Proceed to apply the additional spad and
03953                  * perform measurement. */
03954                 status = set_ref_spad_map(dev,
03955                                           dev->Data .SpadData .RefSpadEnables );
03956             }
03957 
03958             if (status != VL53L0X_ERROR_NONE) {
03959                 break;
03960             }
03961 
03962             status = perform_ref_signal_measurement(dev,
03963                                                     &peak_signal_rate_ref);
03964 
03965             if (status != VL53L0X_ERROR_NONE) {
03966                 break;
03967             }
03968 
03969             signal_rate_diff = abs(peak_signal_rate_ref - target_ref_rate);
03970 
03971             if (peak_signal_rate_ref > target_ref_rate) {
03972                 /* Select the spad map that provides the
03973                  * measurement closest to the target rate,
03974                  * either above or below it.
03975                  */
03976                 if (signal_rate_diff > last_signal_rate_diff) {
03977                     /* Previous spad map produced a closer
03978                      * measurement, so choose this. */
03979                     status = set_ref_spad_map(dev,
03980                                               last_spad_array);
03981                     memcpy(
03982                         dev->Data .SpadData .RefSpadEnables ,
03983                         last_spad_array, spad_array_size);
03984 
03985                     (ref_spad_count_int)--;
03986                 }
03987                 complete = 1;
03988             } else {
03989                 /* Continue to add spads */
03990                 last_signal_rate_diff = signal_rate_diff;
03991                 memcpy(last_spad_array,
03992                        dev->Data .SpadData .RefSpadEnables ,
03993                        spad_array_size);
03994             }
03995 
03996         } /* while */
03997     }
03998 
03999     if (status == VL53L0X_ERROR_NONE) {
04000         *ref_spad_count = ref_spad_count_int;
04001         *is_aperture_spads = is_aperture_spads_int;
04002 
04003         VL53L0X_SETDEVICESPECIFICPARAMETER(dev, RefSpadsInitialised, 1);
04004         VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
04005                                            ReferenceSpadCount, (uint8_t)(*ref_spad_count));
04006         VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
04007                                            ReferenceSpadType, *is_aperture_spads);
04008     }
04009 
04010     return status;
04011 }
04012 
04013 VL53L0X_Error VL53L0X::VL53L0X_set_reference_spads(VL53L0X_DEV dev,
04014         uint32_t count, uint8_t is_aperture_spads)
04015 {
04016     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04017     uint32_t current_spad_index = 0;
04018     uint8_t start_select = 0xB4;
04019     uint32_t spad_array_size = 6;
04020     uint32_t max_spad_count = 44;
04021     uint32_t last_spad_index;
04022     uint32_t index;
04023 
04024     /*
04025      * This function applies a requested number of reference spads, either
04026      * aperture or
04027      * non-aperture, as requested.
04028      * The good spad map will be applied.
04029      */
04030 
04031     status = VL53L0X_write_byte(dev, 0xFF, 0x01);
04032 
04033     if (status == VL53L0X_ERROR_NONE) {
04034         status = VL53L0X_write_byte(dev,
04035                                     VL53L0X_REG_DYNAMIC_SPAD_REF_EN_START_OFFSET, 0x00);
04036     }
04037 
04038     if (status == VL53L0X_ERROR_NONE) {
04039         status = VL53L0X_write_byte(dev,
04040                                     VL53L0X_REG_DYNAMIC_SPAD_NUM_REQUESTED_REF_SPAD, 0x2C);
04041     }
04042 
04043     if (status == VL53L0X_ERROR_NONE) {
04044         status = VL53L0X_write_byte(dev, 0xFF, 0x00);
04045     }
04046 
04047     if (status == VL53L0X_ERROR_NONE) {
04048         status = VL53L0X_write_byte(dev,
04049                                     VL53L0X_REG_GLOBAL_CONFIG_REF_EN_START_SELECT,
04050                                     start_select);
04051     }
04052 
04053     for (index = 0; index < spad_array_size; index++) {
04054         dev->Data .SpadData .RefSpadEnables [index] = 0;
04055     }
04056 
04057     if (is_aperture_spads) {
04058         /* Increment to the first APERTURE spad */
04059         while ((is_aperture(start_select + current_spad_index) == 0) &&
04060                 (current_spad_index < max_spad_count)) {
04061             current_spad_index++;
04062         }
04063     }
04064     status = enable_ref_spads(dev,
04065                               is_aperture_spads,
04066                               dev->Data .SpadData .RefGoodSpadMap ,
04067                               dev->Data .SpadData .RefSpadEnables ,
04068                               spad_array_size,
04069                               start_select,
04070                               current_spad_index,
04071                               count,
04072                               &last_spad_index);
04073 
04074     if (status == VL53L0X_ERROR_NONE) {
04075         VL53L0X_SETDEVICESPECIFICPARAMETER(dev, RefSpadsInitialised, 1);
04076         VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
04077                                            ReferenceSpadCount, (uint8_t)(count));
04078         VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
04079                                            ReferenceSpadType, is_aperture_spads);
04080     }
04081 
04082     return status;
04083 }
04084 
04085 VL53L0X_Error VL53L0X::VL53L0X_wait_device_booted(VL53L0X_DEV dev)
04086 {
04087     VL53L0X_Error status = VL53L0X_ERROR_NOT_IMPLEMENTED;
04088     LOG_FUNCTION_START("");
04089 
04090     /* not implemented on VL53L0X */
04091 
04092     LOG_FUNCTION_END(status);
04093     return status;
04094 }
04095 
04096 VL53L0X_Error VL53L0X::VL53L0X_perform_ref_calibration(VL53L0X_DEV dev, uint8_t *p_vhv_settings,
04097         uint8_t *p_phase_cal)
04098 {
04099     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04100     LOG_FUNCTION_START("");
04101 
04102     status = VL53L0X_perform_ref_calibration(dev, p_vhv_settings,
04103              p_phase_cal, 1);
04104 
04105     LOG_FUNCTION_END(status);
04106     return status;
04107 }
04108 
04109 VL53L0X_Error VL53L0X::VL53L0X_perform_ref_spad_management(VL53L0X_DEV dev,
04110         uint32_t *ref_spad_count, uint8_t *is_aperture_spads)
04111 {
04112     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04113     LOG_FUNCTION_START("");
04114 
04115     status = wrapped_VL53L0X_perform_ref_spad_management(dev, ref_spad_count,
04116              is_aperture_spads);
04117 
04118     LOG_FUNCTION_END(status);
04119 
04120     return status;
04121 }
04122 
04123 /* Group PAL Init Functions */
04124 VL53L0X_Error VL53L0X::VL53L0X_set_device_address(VL53L0X_DEV dev, uint8_t device_address)
04125 {
04126     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04127     LOG_FUNCTION_START("");
04128 
04129     status = VL53L0X_write_byte(dev, VL53L0X_REG_I2C_SLAVE_DEVICE_ADDRESS,
04130                                 device_address / 2);
04131 
04132     LOG_FUNCTION_END(status);
04133     return status;
04134 }
04135 
04136 VL53L0X_Error VL53L0X::VL53L0X_set_gpio_config(VL53L0X_DEV dev, uint8_t pin,
04137         VL53L0X_DeviceModes device_mode, VL53L0X_GpioFunctionality functionality,
04138         VL53L0X_InterruptPolarity polarity)
04139 {
04140     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04141     uint8_t data;
04142 
04143     LOG_FUNCTION_START("");
04144 
04145     if (pin != 0) {
04146         status = VL53L0X_ERROR_GPIO_NOT_EXISTING;
04147     } else if (device_mode == VL53L0X_DEVICEMODE_GPIO_DRIVE) {
04148         if (polarity == VL53L0X_INTERRUPTPOLARITY_LOW) {
04149             data = 0x10;
04150         } else {
04151             data = 1;
04152         }
04153 
04154         status = VL53L0X_write_byte(dev,
04155                                     VL53L0X_REG_GPIO_HV_MUX_ACTIVE_HIGH, data);
04156 
04157     } else {
04158         if (device_mode == VL53L0X_DEVICEMODE_GPIO_OSC) {
04159 
04160             status |= VL53L0X_write_byte(dev, 0xff, 0x01);
04161             status |= VL53L0X_write_byte(dev, 0x00, 0x00);
04162 
04163             status |= VL53L0X_write_byte(dev, 0xff, 0x00);
04164             status |= VL53L0X_write_byte(dev, 0x80, 0x01);
04165             status |= VL53L0X_write_byte(dev, 0x85, 0x02);
04166 
04167             status |= VL53L0X_write_byte(dev, 0xff, 0x04);
04168             status |= VL53L0X_write_byte(dev, 0xcd, 0x00);
04169             status |= VL53L0X_write_byte(dev, 0xcc, 0x11);
04170 
04171             status |= VL53L0X_write_byte(dev, 0xff, 0x07);
04172             status |= VL53L0X_write_byte(dev, 0xbe, 0x00);
04173 
04174             status |= VL53L0X_write_byte(dev, 0xff, 0x06);
04175             status |= VL53L0X_write_byte(dev, 0xcc, 0x09);
04176 
04177             status |= VL53L0X_write_byte(dev, 0xff, 0x00);
04178             status |= VL53L0X_write_byte(dev, 0xff, 0x01);
04179             status |= VL53L0X_write_byte(dev, 0x00, 0x00);
04180 
04181         } else {
04182 
04183             if (status == VL53L0X_ERROR_NONE) {
04184                 switch (functionality) {
04185                     case VL53L0X_GPIOFUNCTIONALITY_OFF:
04186                         data = 0x00;
04187                         break;
04188                     case VL53L0X_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_LOW:
04189                         data = 0x01;
04190                         break;
04191                     case VL53L0X_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_HIGH:
04192                         data = 0x02;
04193                         break;
04194                     case VL53L0X_GPIOFUNCTIONALITY_THRESHOLD_CROSSED_OUT:
04195                         data = 0x03;
04196                         break;
04197                     case VL53L0X_GPIOFUNCTIONALITY_NEW_MEASURE_READY:
04198                         data = 0x04;
04199                         break;
04200                     default:
04201                         status =
04202                             VL53L0X_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED;
04203                 }
04204             }
04205 
04206             if (status == VL53L0X_ERROR_NONE) {
04207                 status = VL53L0X_write_byte(dev,
04208                                             VL53L0X_REG_SYSTEM_INTERRUPT_CONFIG_GPIO, data);
04209             }
04210 
04211             if (status == VL53L0X_ERROR_NONE) {
04212                 if (polarity == VL53L0X_INTERRUPTPOLARITY_LOW) {
04213                     data = 0;
04214                 } else {
04215                     data = (uint8_t)(1 << 4);
04216                 }
04217                 status = VL53L0X_update_byte(dev,
04218                                              VL53L0X_REG_GPIO_HV_MUX_ACTIVE_HIGH, 0xEF, data);
04219             }
04220 
04221             if (status == VL53L0X_ERROR_NONE) {
04222                 VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
04223                                                    Pin0GpioFunctionality, functionality);
04224             }
04225 
04226             if (status == VL53L0X_ERROR_NONE) {
04227                 status = VL53L0X_clear_interrupt_mask(dev, 0);
04228             }
04229         }
04230     }
04231     LOG_FUNCTION_END(status);
04232     return status;
04233 }
04234 
04235 VL53L0X_Error VL53L0X::VL53L0X_get_fraction_enable(VL53L0X_DEV dev, uint8_t *p_enabled)
04236 {
04237     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04238     LOG_FUNCTION_START("");
04239 
04240     status = VL53L0X_read_byte(dev, VL53L0X_REG_SYSTEM_RANGE_CONFIG, p_enabled);
04241 
04242     if (status == VL53L0X_ERROR_NONE) {
04243         *p_enabled = (*p_enabled & 1);
04244     }
04245 
04246     LOG_FUNCTION_END(status);
04247     return status;
04248 }
04249 
04250 uint16_t VL53L0X::VL53L0X_encode_timeout(uint32_t timeout_macro_clks)
04251 {
04252     /*!
04253      * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format
04254      */
04255 
04256     uint16_t encoded_timeout = 0;
04257     uint32_t ls_byte = 0;
04258     uint16_t ms_byte = 0;
04259 
04260     if (timeout_macro_clks > 0) {
04261         ls_byte = timeout_macro_clks - 1;
04262 
04263         while ((ls_byte & 0xFFFFFF00) > 0) {
04264             ls_byte = ls_byte >> 1;
04265             ms_byte++;
04266         }
04267 
04268         encoded_timeout = (ms_byte << 8)
04269                           + (uint16_t)(ls_byte & 0x000000FF);
04270     }
04271 
04272     return encoded_timeout;
04273 
04274 }
04275 
04276 VL53L0X_Error VL53L0X::set_sequence_step_timeout(VL53L0X_DEV dev,
04277         VL53L0X_SequenceStepId sequence_step_id,
04278         uint32_t timeout_micro_secs)
04279 {
04280     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04281     uint8_t current_vcsel_pulse_period_p_clk;
04282     uint8_t msrc_encoded_time_out;
04283     uint16_t pre_range_encoded_time_out;
04284     uint16_t pre_range_time_out_m_clks;
04285     uint16_t msrc_range_time_out_m_clks;
04286     uint32_t final_range_time_out_m_clks;
04287     uint16_t final_range_encoded_time_out;
04288     VL53L0X_SchedulerSequenceSteps_t scheduler_sequence_steps;
04289 
04290     if ((sequence_step_id == VL53L0X_SEQUENCESTEP_TCC)   ||
04291             (sequence_step_id == VL53L0X_SEQUENCESTEP_DSS)   ||
04292             (sequence_step_id == VL53L0X_SEQUENCESTEP_MSRC)) {
04293 
04294         status = VL53L0X_get_vcsel_pulse_period(dev,
04295                                                 VL53L0X_VCSEL_PERIOD_PRE_RANGE,
04296                                                 &current_vcsel_pulse_period_p_clk);
04297 
04298         if (status == VL53L0X_ERROR_NONE) {
04299             msrc_range_time_out_m_clks = VL53L0X_calc_timeout_mclks(dev,
04300                                          timeout_micro_secs,
04301                                          (uint8_t)current_vcsel_pulse_period_p_clk);
04302 
04303             if (msrc_range_time_out_m_clks > 256) {
04304                 msrc_encoded_time_out = 255;
04305             } else {
04306                 msrc_encoded_time_out =
04307                     (uint8_t)msrc_range_time_out_m_clks - 1;
04308             }
04309 
04310             VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
04311                                                LastEncodedTimeout,
04312                                                msrc_encoded_time_out);
04313         }
04314 
04315         if (status == VL53L0X_ERROR_NONE) {
04316             status = VL53L0X_write_byte(dev,
04317                                         VL53L0X_REG_MSRC_CONFIG_TIMEOUT_MACROP,
04318                                         msrc_encoded_time_out);
04319         }
04320     } else {
04321 
04322         if (sequence_step_id == VL53L0X_SEQUENCESTEP_PRE_RANGE) {
04323 
04324             if (status == VL53L0X_ERROR_NONE) {
04325                 status = VL53L0X_get_vcsel_pulse_period(dev,
04326                                                         VL53L0X_VCSEL_PERIOD_PRE_RANGE,
04327                                                         &current_vcsel_pulse_period_p_clk);
04328                 pre_range_time_out_m_clks =
04329                     VL53L0X_calc_timeout_mclks(dev,
04330                                                timeout_micro_secs,
04331                                                (uint8_t)current_vcsel_pulse_period_p_clk);
04332                 pre_range_encoded_time_out = VL53L0X_encode_timeout(
04333                                                  pre_range_time_out_m_clks);
04334 
04335                 VL53L0X_SETDEVICESPECIFICPARAMETER(dev,
04336                                                    LastEncodedTimeout,
04337                                                    pre_range_encoded_time_out);
04338             }
04339 
04340             if (status == VL53L0X_ERROR_NONE) {
04341                 status = VL53L0X_write_word(dev,
04342                                             VL53L0X_REG_PRE_RANGE_CONFIG_TIMEOUT_MACROP_HI,
04343                                             pre_range_encoded_time_out);
04344             }
04345 
04346             if (status == VL53L0X_ERROR_NONE) {
04347                 VL53L0X_SETDEVICESPECIFICPARAMETER(
04348                     dev,
04349                     PreRangeTimeoutMicroSecs,
04350                     timeout_micro_secs);
04351             }
04352         } else if (sequence_step_id == VL53L0X_SEQUENCESTEP_FINAL_RANGE) {
04353 
04354             /* For the final range timeout, the pre-range timeout
04355              * must be added. To do this both final and pre-range
04356              * timeouts must be expressed in macro periods MClks
04357              * because they have different vcsel periods.
04358              */
04359 
04360             VL53L0X_get_sequence_step_enables(dev,
04361                                               &scheduler_sequence_steps);
04362             pre_range_time_out_m_clks = 0;
04363             if (scheduler_sequence_steps.PreRangeOn) {
04364 
04365                 /* Retrieve PRE-RANGE VCSEL Period */
04366                 status = VL53L0X_get_vcsel_pulse_period(dev,
04367                                                         VL53L0X_VCSEL_PERIOD_PRE_RANGE,
04368                                                         &current_vcsel_pulse_period_p_clk);
04369 
04370                 /* Retrieve PRE-RANGE Timeout in Macro periods
04371                  * (MCLKS) */
04372                 if (status == VL53L0X_ERROR_NONE) {
04373                     status = VL53L0X_read_word(dev, 0x51,
04374                                                &pre_range_encoded_time_out);
04375                     pre_range_time_out_m_clks =
04376                         VL53L0X_decode_timeout(
04377                             pre_range_encoded_time_out);
04378                 }
04379             }
04380 
04381             /* Calculate FINAL RANGE Timeout in Macro Periods
04382              * (MCLKS) and add PRE-RANGE value
04383              */
04384             if (status == VL53L0X_ERROR_NONE) {
04385                 status = VL53L0X_get_vcsel_pulse_period(dev,
04386                                                         VL53L0X_VCSEL_PERIOD_FINAL_RANGE,
04387                                                         &current_vcsel_pulse_period_p_clk);
04388             }
04389             if (status == VL53L0X_ERROR_NONE) {
04390                 final_range_time_out_m_clks =
04391                     VL53L0X_calc_timeout_mclks(dev,
04392                                                timeout_micro_secs,
04393                                                (uint8_t) current_vcsel_pulse_period_p_clk);
04394 
04395                 final_range_time_out_m_clks += pre_range_time_out_m_clks;
04396 
04397                 final_range_encoded_time_out =
04398                     VL53L0X_encode_timeout(final_range_time_out_m_clks);
04399 
04400                 if (status == VL53L0X_ERROR_NONE) {
04401                     status = VL53L0X_write_word(dev, 0x71,
04402                                                 final_range_encoded_time_out);
04403                 }
04404 
04405                 if (status == VL53L0X_ERROR_NONE) {
04406                     VL53L0X_SETDEVICESPECIFICPARAMETER(
04407                         dev,
04408                         FinalRangeTimeoutMicroSecs,
04409                         timeout_micro_secs);
04410                 }
04411             }
04412         } else {
04413             status = VL53L0X_ERROR_INVALID_PARAMS;
04414         }
04415 
04416     }
04417     return status;
04418 }
04419 
04420 VL53L0X_Error VL53L0X::wrapped_VL53L0X_set_measurement_timing_budget_micro_seconds(VL53L0X_DEV dev,
04421         uint32_t measurement_timing_budget_micro_seconds)
04422 {
04423     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04424     uint32_t final_range_timing_budget_micro_seconds;
04425     VL53L0X_SchedulerSequenceSteps_t scheduler_sequence_steps;
04426     uint32_t msrc_dcc_tcc_timeout_micro_seconds = 2000;
04427     uint32_t start_overhead_micro_seconds       = 1910;
04428     uint32_t end_overhead_micro_seconds     = 960;
04429     uint32_t msrc_overhead_micro_seconds        = 660;
04430     uint32_t tcc_overhead_micro_seconds     = 590;
04431     uint32_t dss_overhead_micro_seconds     = 690;
04432     uint32_t pre_range_overhead_micro_seconds   = 660;
04433     uint32_t final_range_overhead_micro_seconds = 550;
04434     uint32_t pre_range_timeout_micro_seconds    = 0;
04435     uint32_t c_min_timing_budget_micro_seconds  = 20000;
04436     uint32_t sub_timeout = 0;
04437 
04438     LOG_FUNCTION_START("");
04439 
04440     if (measurement_timing_budget_micro_seconds
04441             < c_min_timing_budget_micro_seconds) {
04442         status = VL53L0X_ERROR_INVALID_PARAMS;
04443         return status;
04444     }
04445 
04446     final_range_timing_budget_micro_seconds =
04447         measurement_timing_budget_micro_seconds -
04448         (start_overhead_micro_seconds + end_overhead_micro_seconds);
04449 
04450     status = VL53L0X_get_sequence_step_enables(dev, &scheduler_sequence_steps);
04451 
04452     if (status == VL53L0X_ERROR_NONE &&
04453             (scheduler_sequence_steps.TccOn  ||
04454              scheduler_sequence_steps.MsrcOn ||
04455              scheduler_sequence_steps.DssOn)) {
04456 
04457         /* TCC, MSRC and DSS all share the same timeout */
04458         status = get_sequence_step_timeout(dev,
04459                                            VL53L0X_SEQUENCESTEP_MSRC,
04460                                            &msrc_dcc_tcc_timeout_micro_seconds);
04461 
04462         /* Subtract the TCC, MSRC and DSS timeouts if they are
04463          * enabled. */
04464 
04465         if (status != VL53L0X_ERROR_NONE) {
04466             return status;
04467         }
04468 
04469         /* TCC */
04470         if (scheduler_sequence_steps.TccOn) {
04471 
04472             sub_timeout = msrc_dcc_tcc_timeout_micro_seconds
04473                           + tcc_overhead_micro_seconds;
04474 
04475             if (sub_timeout <
04476                     final_range_timing_budget_micro_seconds) {
04477                 final_range_timing_budget_micro_seconds -=
04478                     sub_timeout;
04479             } else {
04480                 /* Requested timeout too big. */
04481                 status = VL53L0X_ERROR_INVALID_PARAMS;
04482             }
04483         }
04484 
04485         if (status != VL53L0X_ERROR_NONE) {
04486             LOG_FUNCTION_END(status);
04487             return status;
04488         }
04489 
04490         /* DSS */
04491         if (scheduler_sequence_steps.DssOn) {
04492 
04493             sub_timeout = 2 * (msrc_dcc_tcc_timeout_micro_seconds +
04494                                dss_overhead_micro_seconds);
04495 
04496             if (sub_timeout < final_range_timing_budget_micro_seconds) {
04497                 final_range_timing_budget_micro_seconds
04498                 -= sub_timeout;
04499             } else {
04500                 /* Requested timeout too big. */
04501                 status = VL53L0X_ERROR_INVALID_PARAMS;
04502             }
04503         } else if (scheduler_sequence_steps.MsrcOn) {
04504             /* MSRC */
04505             sub_timeout = msrc_dcc_tcc_timeout_micro_seconds +
04506                           msrc_overhead_micro_seconds;
04507 
04508             if (sub_timeout < final_range_timing_budget_micro_seconds) {
04509                 final_range_timing_budget_micro_seconds
04510                 -= sub_timeout;
04511             } else {
04512                 /* Requested timeout too big. */
04513                 status = VL53L0X_ERROR_INVALID_PARAMS;
04514             }
04515         }
04516 
04517     }
04518 
04519     if (status != VL53L0X_ERROR_NONE) {
04520         LOG_FUNCTION_END(status);
04521         return status;
04522     }
04523 
04524     if (scheduler_sequence_steps.PreRangeOn) {
04525 
04526         /* Subtract the Pre-range timeout if enabled. */
04527 
04528         status = get_sequence_step_timeout(dev,
04529                                            VL53L0X_SEQUENCESTEP_PRE_RANGE,
04530                                            &pre_range_timeout_micro_seconds);
04531 
04532         sub_timeout = pre_range_timeout_micro_seconds +
04533                       pre_range_overhead_micro_seconds;
04534 
04535         if (sub_timeout < final_range_timing_budget_micro_seconds) {
04536             final_range_timing_budget_micro_seconds -= sub_timeout;
04537         } else {
04538             /* Requested timeout too big. */
04539             status = VL53L0X_ERROR_INVALID_PARAMS;
04540         }
04541     }
04542 
04543 
04544     if (status == VL53L0X_ERROR_NONE &&
04545             scheduler_sequence_steps.FinalRangeOn) {
04546 
04547         final_range_timing_budget_micro_seconds -=
04548             final_range_overhead_micro_seconds;
04549 
04550         /* Final Range Timeout
04551          * Note that the final range timeout is determined by the timing
04552          * budget and the sum of all other timeouts within the sequence.
04553          * If there is no room for the final range timeout, then an error
04554          * will be set. Otherwise the remaining time will be applied to
04555          * the final range.
04556          */
04557         status = set_sequence_step_timeout(dev,
04558                                            VL53L0X_SEQUENCESTEP_FINAL_RANGE,
04559                                            final_range_timing_budget_micro_seconds);
04560 
04561         VL53L0X_SETPARAMETERFIELD(dev,
04562                                   MeasurementTimingBudgetMicroSeconds,
04563                                   measurement_timing_budget_micro_seconds);
04564     }
04565 
04566     LOG_FUNCTION_END(status);
04567 
04568     return status;
04569 }
04570 
04571 VL53L0X_Error VL53L0X::VL53L0X_set_measurement_timing_budget_micro_seconds(VL53L0X_DEV dev,
04572         uint32_t measurement_timing_budget_micro_seconds)
04573 {
04574     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04575     LOG_FUNCTION_START("");
04576 
04577     status = wrapped_VL53L0X_set_measurement_timing_budget_micro_seconds(dev,
04578              measurement_timing_budget_micro_seconds);
04579 
04580     LOG_FUNCTION_END(status);
04581 
04582     return status;
04583 }
04584 
04585 VL53L0X_Error VL53L0X::VL53L0X_set_sequence_step_enable(VL53L0X_DEV dev,
04586         VL53L0X_SequenceStepId sequence_step_id, uint8_t sequence_step_enabled)
04587 {
04588     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04589     uint8_t sequence_config = 0;
04590     uint8_t sequence_config_new = 0;
04591     uint32_t measurement_timing_budget_micro_seconds;
04592     LOG_FUNCTION_START("");
04593 
04594     status = VL53L0X_read_byte(dev, VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG,
04595                                &sequence_config);
04596 
04597     sequence_config_new = sequence_config;
04598 
04599     if (status == VL53L0X_ERROR_NONE) {
04600         if (sequence_step_enabled == 1) {
04601 
04602             /* Enable requested sequence step
04603              */
04604             switch (sequence_step_id) {
04605                 case VL53L0X_SEQUENCESTEP_TCC:
04606                     sequence_config_new |= 0x10;
04607                     break;
04608                 case VL53L0X_SEQUENCESTEP_DSS:
04609                     sequence_config_new |= 0x28;
04610                     break;
04611                 case VL53L0X_SEQUENCESTEP_MSRC:
04612                     sequence_config_new |= 0x04;
04613                     break;
04614                 case VL53L0X_SEQUENCESTEP_PRE_RANGE:
04615                     sequence_config_new |= 0x40;
04616                     break;
04617                 case VL53L0X_SEQUENCESTEP_FINAL_RANGE:
04618                     sequence_config_new |= 0x80;
04619                     break;
04620                 default:
04621                     status = VL53L0X_ERROR_INVALID_PARAMS;
04622             }
04623         } else {
04624             /* Disable requested sequence step
04625              */
04626             switch (sequence_step_id) {
04627                 case VL53L0X_SEQUENCESTEP_TCC:
04628                     sequence_config_new &= 0xef;
04629                     break;
04630                 case VL53L0X_SEQUENCESTEP_DSS:
04631                     sequence_config_new &= 0xd7;
04632                     break;
04633                 case VL53L0X_SEQUENCESTEP_MSRC:
04634                     sequence_config_new &= 0xfb;
04635                     break;
04636                 case VL53L0X_SEQUENCESTEP_PRE_RANGE:
04637                     sequence_config_new &= 0xbf;
04638                     break;
04639                 case VL53L0X_SEQUENCESTEP_FINAL_RANGE:
04640                     sequence_config_new &= 0x7f;
04641                     break;
04642                 default:
04643                     status = VL53L0X_ERROR_INVALID_PARAMS;
04644             }
04645         }
04646     }
04647 
04648     if (sequence_config_new != sequence_config) {
04649         /* Apply New Setting */
04650         if (status == VL53L0X_ERROR_NONE) {
04651             status = VL53L0X_write_byte(dev,
04652                                         VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, sequence_config_new);
04653         }
04654         if (status == VL53L0X_ERROR_NONE) {
04655             PALDevDataSet(dev, SequenceConfig, sequence_config_new);
04656         }
04657 
04658 
04659         /* Recalculate timing budget */
04660         if (status == VL53L0X_ERROR_NONE) {
04661             VL53L0X_GETPARAMETERFIELD(dev,
04662                                       MeasurementTimingBudgetMicroSeconds,
04663                                       measurement_timing_budget_micro_seconds);
04664 
04665             VL53L0X_set_measurement_timing_budget_micro_seconds(dev,
04666                     measurement_timing_budget_micro_seconds);
04667         }
04668     }
04669 
04670     LOG_FUNCTION_END(status);
04671 
04672     return status;
04673 }
04674 
04675 VL53L0X_Error VL53L0X::VL53L0X_set_limit_check_enable(VL53L0X_DEV dev, uint16_t limit_check_id,
04676         uint8_t limit_check_enable)
04677 {
04678     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04679     FixPoint1616_t temp_fix1616 = 0;
04680     uint8_t limit_check_enable_int = 0;
04681     uint8_t limit_check_disable = 0;
04682     uint8_t temp8;
04683 
04684     LOG_FUNCTION_START("");
04685 
04686     if (limit_check_id >= VL53L0X_CHECKENABLE_NUMBER_OF_CHECKS) {
04687         status = VL53L0X_ERROR_INVALID_PARAMS;
04688     } else {
04689         if (limit_check_enable == 0) {
04690             temp_fix1616 = 0;
04691             limit_check_enable_int = 0;
04692             limit_check_disable = 1;
04693 
04694         } else {
04695             VL53L0X_GETARRAYPARAMETERFIELD(dev, LimitChecksValue,
04696                                            limit_check_id, temp_fix1616);
04697             limit_check_disable = 0;
04698             /* this to be sure to have either 0 or 1 */
04699             limit_check_enable_int = 1;
04700         }
04701 
04702         switch (limit_check_id) {
04703 
04704             case VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE:
04705                 /* internal computation: */
04706                 VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksEnable,
04707                                                VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE,
04708                                                limit_check_enable_int);
04709 
04710                 break;
04711 
04712             case VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
04713 
04714                 status = VL53L0X_write_word(dev,
04715                                             VL53L0X_REG_FINAL_RANGE_CONFIG_MIN_COUNT_RATE_RTN_LIMIT,
04716                                             VL53L0X_FIXPOINT1616TOFIXPOINT97(temp_fix1616));
04717 
04718                 break;
04719 
04720             case VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP:
04721 
04722                 /* internal computation: */
04723                 VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksEnable,
04724                                                VL53L0X_CHECKENABLE_SIGNAL_REF_CLIP,
04725                                                limit_check_enable_int);
04726 
04727                 break;
04728 
04729             case VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD:
04730 
04731                 /* internal computation: */
04732                 VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksEnable,
04733                                                VL53L0X_CHECKENABLE_RANGE_IGNORE_THRESHOLD,
04734                                                limit_check_enable_int);
04735 
04736                 break;
04737 
04738             case VL53L0X_CHECKENABLE_SIGNAL_RATE_MSRC:
04739 
04740                 temp8 = (uint8_t)(limit_check_disable << 1);
04741                 status = VL53L0X_update_byte(dev,
04742                                              VL53L0X_REG_MSRC_CONFIG_CONTROL,
04743                                              0xFE, temp8);
04744 
04745                 break;
04746 
04747             case VL53L0X_CHECKENABLE_SIGNAL_RATE_PRE_RANGE:
04748 
04749                 temp8 = (uint8_t)(limit_check_disable << 4);
04750                 status = VL53L0X_update_byte(dev,
04751                                              VL53L0X_REG_MSRC_CONFIG_CONTROL,
04752                                              0xEF, temp8);
04753 
04754                 break;
04755 
04756 
04757             default:
04758                 status = VL53L0X_ERROR_INVALID_PARAMS;
04759 
04760         }
04761 
04762     }
04763 
04764     if (status == VL53L0X_ERROR_NONE) {
04765         if (limit_check_enable == 0) {
04766             VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksEnable,
04767                                            limit_check_id, 0);
04768         } else {
04769             VL53L0X_SETARRAYPARAMETERFIELD(dev, LimitChecksEnable,
04770                                            limit_check_id, 1);
04771         }
04772     }
04773 
04774     LOG_FUNCTION_END(status);
04775     return status;
04776 }
04777 
04778 VL53L0X_Error VL53L0X::VL53L0X_static_init(VL53L0X_DEV dev)
04779 {
04780     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04781     VL53L0X_DeviceParameters_t current_parameters = {0};
04782     uint8_t *p_tuning_setting_buffer;
04783     uint16_t tempword = 0;
04784     uint8_t tempbyte = 0;
04785     uint8_t use_internal_tuning_settings = 0;
04786     uint32_t count = 0;
04787     uint8_t is_aperture_spads = 0;
04788     uint32_t ref_spad_count = 0;
04789     uint8_t aperture_spads = 0;
04790     uint8_t vcsel_pulse_period_pclk;
04791     uint32_t seq_timeout_micro_secs;
04792 
04793     LOG_FUNCTION_START("");
04794 
04795     status = VL53L0X_get_info_from_device(dev, 1);
04796 
04797     /* set the ref spad from NVM */
04798     count   = (uint32_t)VL53L0X_GETDEVICESPECIFICPARAMETER(dev,
04799               ReferenceSpadCount);
04800     aperture_spads = VL53L0X_GETDEVICESPECIFICPARAMETER(dev,
04801                      ReferenceSpadType);
04802 
04803     /* NVM value invalid */
04804     if ((aperture_spads > 1) ||
04805             ((aperture_spads == 1) && (count > 32)) ||
04806             ((aperture_spads == 0) && (count > 12))) {
04807         status = wrapped_VL53L0X_perform_ref_spad_management(dev, &ref_spad_count,
04808                  &is_aperture_spads);
04809     } else {
04810         status = VL53L0X_set_reference_spads(dev, count, aperture_spads);
04811     }
04812 
04813 
04814     /* Initialize tuning settings buffer to prevent compiler warning. */
04815     p_tuning_setting_buffer = DefaultTuningSettings;
04816 
04817     if (status == VL53L0X_ERROR_NONE) {
04818         use_internal_tuning_settings = PALDevDataGet(dev,
04819                                        UseInternalTuningSettings);
04820 
04821         if (use_internal_tuning_settings == 0) {
04822             p_tuning_setting_buffer = PALDevDataGet(dev,
04823                                                     pTuningSettingsPointer);
04824         } else {
04825             p_tuning_setting_buffer = DefaultTuningSettings;
04826         }
04827 
04828     }
04829 
04830     if (status == VL53L0X_ERROR_NONE) {
04831         status = VL53L0X_load_tuning_settings(dev, p_tuning_setting_buffer);
04832     }
04833 
04834 
04835     /* Set interrupt config to new sample ready */
04836     if (status == VL53L0X_ERROR_NONE) {
04837         status = VL53L0X_set_gpio_config(dev, 0, 0,
04838                                          VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY,
04839                                          VL53L0X_INTERRUPTPOLARITY_LOW);
04840     }
04841 
04842     if (status == VL53L0X_ERROR_NONE) {
04843         status = VL53L0X_write_byte(dev, 0xFF, 0x01);
04844         status |= VL53L0X_read_word(dev, 0x84, &tempword);
04845         status |= VL53L0X_write_byte(dev, 0xFF, 0x00);
04846     }
04847 
04848     if (status == VL53L0X_ERROR_NONE) {
04849         VL53L0X_SETDEVICESPECIFICPARAMETER(dev, OscFrequencyMHz,
04850                                            VL53L0X_FIXPOINT412TOFIXPOINT1616(tempword));
04851     }
04852 
04853     /* After static init, some device parameters may be changed,
04854      * so update them */
04855     if (status == VL53L0X_ERROR_NONE) {
04856         status = VL53L0X_get_device_parameters(dev, &current_parameters);
04857     }
04858 
04859 
04860     if (status == VL53L0X_ERROR_NONE) {
04861         status = VL53L0X_get_fraction_enable(dev, &tempbyte);
04862         if (status == VL53L0X_ERROR_NONE) {
04863             PALDevDataSet(dev, RangeFractionalEnable, tempbyte);
04864         }
04865 
04866     }
04867 
04868     if (status == VL53L0X_ERROR_NONE) {
04869         PALDevDataSet(dev, CurrentParameters, current_parameters);
04870     }
04871 
04872 
04873     /* read the sequence config and save it */
04874     if (status == VL53L0X_ERROR_NONE) {
04875         status = VL53L0X_read_byte(dev,
04876                                    VL53L0X_REG_SYSTEM_SEQUENCE_CONFIG, &tempbyte);
04877         if (status == VL53L0X_ERROR_NONE) {
04878             PALDevDataSet(dev, SequenceConfig, tempbyte);
04879         }
04880     }
04881 
04882     /* Disable MSRC and TCC by default */
04883     if (status == VL53L0X_ERROR_NONE) {
04884         status = VL53L0X_set_sequence_step_enable(dev,
04885                  VL53L0X_SEQUENCESTEP_TCC, 0);
04886     }
04887 
04888     if (status == VL53L0X_ERROR_NONE) {
04889         status = VL53L0X_set_sequence_step_enable(dev,
04890                  VL53L0X_SEQUENCESTEP_MSRC, 0);
04891     }
04892 
04893     /* Set PAL State to standby */
04894     if (status == VL53L0X_ERROR_NONE) {
04895         PALDevDataSet(dev, PalState, VL53L0X_STATE_IDLE);
04896     }
04897 
04898     /* Store pre-range vcsel period */
04899     if (status == VL53L0X_ERROR_NONE) {
04900         status = VL53L0X_get_vcsel_pulse_period(
04901                      dev,
04902                      VL53L0X_VCSEL_PERIOD_PRE_RANGE,
04903                      &vcsel_pulse_period_pclk);
04904     }
04905 
04906     if (status == VL53L0X_ERROR_NONE) {
04907         VL53L0X_SETDEVICESPECIFICPARAMETER(
04908             dev,
04909             PreRangeVcselPulsePeriod,
04910             vcsel_pulse_period_pclk);
04911     }
04912 
04913     /* Store final-range vcsel period */
04914     if (status == VL53L0X_ERROR_NONE) {
04915         status = VL53L0X_get_vcsel_pulse_period(
04916                      dev,
04917                      VL53L0X_VCSEL_PERIOD_FINAL_RANGE,
04918                      &vcsel_pulse_period_pclk);
04919     }
04920 
04921     if (status == VL53L0X_ERROR_NONE) {
04922         VL53L0X_SETDEVICESPECIFICPARAMETER(
04923             dev,
04924             FinalRangeVcselPulsePeriod,
04925             vcsel_pulse_period_pclk);
04926     }
04927 
04928     /* Store pre-range timeout */
04929     if (status == VL53L0X_ERROR_NONE) {
04930         status = get_sequence_step_timeout(
04931                      dev,
04932                      VL53L0X_SEQUENCESTEP_PRE_RANGE,
04933                      &seq_timeout_micro_secs);
04934     }
04935 
04936     if (status == VL53L0X_ERROR_NONE) {
04937         VL53L0X_SETDEVICESPECIFICPARAMETER(
04938             dev,
04939             PreRangeTimeoutMicroSecs,
04940             seq_timeout_micro_secs);
04941     }
04942 
04943     /* Store final-range timeout */
04944     if (status == VL53L0X_ERROR_NONE) {
04945         status = get_sequence_step_timeout(
04946                      dev,
04947                      VL53L0X_SEQUENCESTEP_FINAL_RANGE,
04948                      &seq_timeout_micro_secs);
04949     }
04950 
04951     if (status == VL53L0X_ERROR_NONE) {
04952         VL53L0X_SETDEVICESPECIFICPARAMETER(
04953             dev,
04954             FinalRangeTimeoutMicroSecs,
04955             seq_timeout_micro_secs);
04956     }
04957 
04958     LOG_FUNCTION_END(status);
04959     return status;
04960 }
04961 
04962 
04963 VL53L0X_Error VL53L0X::VL53L0X_stop_measurement(VL53L0X_DEV dev)
04964 {
04965     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04966     LOG_FUNCTION_START("");
04967 
04968     status = VL53L0X_write_byte(dev, VL53L0X_REG_SYSRANGE_START,
04969                                 VL53L0X_REG_SYSRANGE_MODE_SINGLESHOT);
04970 
04971     status = VL53L0X_write_byte(dev, 0xFF, 0x01);
04972     status = VL53L0X_write_byte(dev, 0x00, 0x00);
04973     status = VL53L0X_write_byte(dev, 0x91, 0x00);
04974     status = VL53L0X_write_byte(dev, 0x00, 0x01);
04975     status = VL53L0X_write_byte(dev, 0xFF, 0x00);
04976 
04977     if (status == VL53L0X_ERROR_NONE) {
04978         /* Set PAL State to Idle */
04979         PALDevDataSet(dev, PalState, VL53L0X_STATE_IDLE);
04980     }
04981 
04982     /* Check if need to apply interrupt settings */
04983     if (status == VL53L0X_ERROR_NONE) {
04984         status = VL53L0X_check_and_load_interrupt_settings(dev, 0);
04985     }
04986 
04987     LOG_FUNCTION_END(status);
04988     return status;
04989 }
04990 
04991 VL53L0X_Error VL53L0X::VL53L0X_get_stop_completed_status(VL53L0X_DEV dev,
04992         uint32_t *p_stop_status)
04993 {
04994     VL53L0X_Error status = VL53L0X_ERROR_NONE;
04995     uint8_t byte = 0;
04996     LOG_FUNCTION_START("");
04997 
04998     status = VL53L0X_write_byte(dev, 0xFF, 0x01);
04999 
05000     if (status == VL53L0X_ERROR_NONE) {
05001         status = VL53L0X_read_byte(dev, 0x04, &byte);
05002     }
05003 
05004     if (status == VL53L0X_ERROR_NONE) {
05005         status = VL53L0X_write_byte(dev, 0xFF, 0x0);
05006     }
05007 
05008     *p_stop_status = byte;
05009 
05010     if (byte == 0) {
05011         status = VL53L0X_write_byte(dev, 0x80, 0x01);
05012         status = VL53L0X_write_byte(dev, 0xFF, 0x01);
05013         status = VL53L0X_write_byte(dev, 0x00, 0x00);
05014         status = VL53L0X_write_byte(dev, 0x91,
05015                                     PALDevDataGet(dev, StopVariable));
05016         status = VL53L0X_write_byte(dev, 0x00, 0x01);
05017         status = VL53L0X_write_byte(dev, 0xFF, 0x00);
05018         status = VL53L0X_write_byte(dev, 0x80, 0x00);
05019     }
05020 
05021     LOG_FUNCTION_END(status);
05022     return status;
05023 }
05024 
05025 /****************** Write and read functions from I2C *************************/
05026 
05027 VL53L0X_Error VL53L0X::VL53L0X_write_multi(VL53L0X_DEV dev, uint8_t index, uint8_t *p_data, uint32_t count)
05028 {
05029     int  status;
05030 
05031     status = VL53L0X_i2c_write(dev->I2cDevAddr , index, p_data, (uint16_t)count);
05032     return status;
05033 }
05034 
05035 VL53L0X_Error VL53L0X::VL53L0X_read_multi(VL53L0X_DEV dev, uint8_t index, uint8_t *p_data, uint32_t count)
05036 {
05037     int status;
05038 
05039     if (count >= VL53L0X_MAX_I2C_XFER_SIZE) {
05040         status = VL53L0X_ERROR_INVALID_PARAMS;
05041     }
05042 
05043     status = VL53L0X_i2c_read(dev->I2cDevAddr , index, p_data, (uint16_t)count);
05044 
05045     return status;
05046 }
05047 
05048 
05049 VL53L0X_Error VL53L0X::VL53L0X_write_byte(VL53L0X_DEV Dev, uint8_t index, uint8_t data)
05050 {
05051     int  status;
05052 
05053     status = VL53L0X_i2c_write(Dev->I2cDevAddr , index, &data, 1);
05054     return status;
05055 }
05056 
05057 VL53L0X_Error VL53L0X::VL53L0X_write_word(VL53L0X_DEV dev, uint8_t index, uint16_t data)
05058 {
05059     int  status;
05060     uint8_t buffer[2];
05061 
05062     buffer[0] = data >> 8;
05063     buffer[1] = data & 0x00FF;
05064     status = VL53L0X_i2c_write(dev->I2cDevAddr , index, (uint8_t *)buffer, 2);
05065     return status;
05066 }
05067 
05068 VL53L0X_Error VL53L0X::VL53L0X_write_dword(VL53L0X_DEV Dev, uint8_t index, uint32_t data)
05069 {
05070     int  status;
05071     uint8_t buffer[4];
05072 
05073     buffer[0] = (data >> 24) & 0xFF;
05074     buffer[1] = (data >> 16) & 0xFF;
05075     buffer[2] = (data >>  8) & 0xFF;
05076     buffer[3] = (data >>  0) & 0xFF;
05077     status = VL53L0X_i2c_write(Dev->I2cDevAddr , index, (uint8_t *)buffer, 4);
05078     return status;
05079 }
05080 
05081 
05082 VL53L0X_Error VL53L0X::VL53L0X_read_byte(VL53L0X_DEV Dev, uint8_t index, uint8_t *p_data)
05083 {
05084     int  status;
05085 
05086     status = VL53L0X_i2c_read(Dev->I2cDevAddr , index, p_data, 1);
05087 
05088     if (status) {
05089         return -1;
05090     }
05091 
05092     return 0;
05093 }
05094 
05095 VL53L0X_Error VL53L0X::VL53L0X_read_word(VL53L0X_DEV Dev, uint8_t index, uint16_t *p_data)
05096 {
05097     int  status;
05098     uint8_t buffer[2] = {0, 0};
05099 
05100     status = VL53L0X_i2c_read(Dev->I2cDevAddr , index, buffer, 2);
05101     if (!status) {
05102         *p_data = (buffer[0] << 8) + buffer[1];
05103     }
05104     return status;
05105 
05106 }
05107 
05108 VL53L0X_Error VL53L0X::VL53L0X_read_dword(VL53L0X_DEV Dev, uint8_t index, uint32_t *p_data)
05109 {
05110     int status;
05111     uint8_t buffer[4] = {0, 0, 0, 0};
05112 
05113     status = VL53L0X_i2c_read(Dev->I2cDevAddr , index, buffer, 4);
05114     if (!status) {
05115         *p_data = (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
05116     }
05117     return status;
05118 
05119 }
05120 
05121 VL53L0X_Error VL53L0X::VL53L0X_update_byte(VL53L0X_DEV Dev, uint8_t index, uint8_t and_data, uint8_t or_data)
05122 {
05123     int  status;
05124     uint8_t buffer = 0;
05125 
05126     /* read data direct onto buffer */
05127     status = VL53L0X_i2c_read(Dev->I2cDevAddr , index, &buffer, 1);
05128     if (!status) {
05129         buffer = (buffer & and_data) | or_data;
05130         status = VL53L0X_i2c_write(Dev->I2cDevAddr , index, &buffer, (uint8_t)1);
05131     }
05132     return status;
05133 }
05134 
05135 VL53L0X_Error VL53L0X::VL53L0X_i2c_write(uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t *p_data,
05136         uint16_t NumByteToWrite)
05137 {
05138     int ret;
05139 
05140     ret = _dev_i2c->i2c_write(p_data, DeviceAddr, RegisterAddr, NumByteToWrite);
05141 
05142     if (ret) {
05143         return -1;
05144     }
05145     return 0;
05146 }
05147 
05148 VL53L0X_Error VL53L0X::VL53L0X_i2c_read(uint8_t DeviceAddr, uint8_t RegisterAddr, uint8_t *p_data,
05149                                         uint16_t NumByteToRead)
05150 {
05151     int ret;
05152 
05153     ret = _dev_i2c->i2c_read(p_data, DeviceAddr, RegisterAddr, NumByteToRead);
05154 
05155     if (ret) {
05156         return -1;
05157     }
05158     return 0;
05159 }
05160 
05161 int VL53L0X::read_id(uint8_t *id)
05162 {
05163     int status = 0;
05164     uint16_t rl_id = 0;
05165 
05166     status = VL53L0X_read_word(_device, VL53L0X_REG_IDENTIFICATION_MODEL_ID, &rl_id);
05167     if (rl_id == 0xEEAA) {
05168         return status;
05169     }
05170 
05171     return -1;
05172 }
05173 
05174 
05175 VL53L0X_Error VL53L0X::wait_measurement_data_ready(VL53L0X_DEV dev)
05176 {
05177     VL53L0X_Error status = VL53L0X_ERROR_NONE;
05178     uint8_t new_dat_ready = 0;
05179     uint32_t loop_nb;
05180 
05181     // Wait until it finished
05182     // use timeout to avoid deadlock
05183     if (status == VL53L0X_ERROR_NONE) {
05184         loop_nb = 0;
05185         do {
05186             status = VL53L0X_get_measurement_data_ready(dev, &new_dat_ready);
05187             if ((new_dat_ready == 0x01) || status != VL53L0X_ERROR_NONE) {
05188                 break;
05189             }
05190             loop_nb = loop_nb + 1;
05191             VL53L0X_polling_delay(dev);
05192         } while (loop_nb < VL53L0X_DEFAULT_MAX_LOOP);
05193 
05194         if (loop_nb >= VL53L0X_DEFAULT_MAX_LOOP) {
05195             status = VL53L0X_ERROR_TIME_OUT;
05196         }
05197     }
05198 
05199     return status;
05200 }
05201 
05202 VL53L0X_Error VL53L0X::wait_stop_completed(VL53L0X_DEV dev)
05203 {
05204     VL53L0X_Error status = VL53L0X_ERROR_NONE;
05205     uint32_t stop_completed = 0;
05206     uint32_t loop_nb;
05207 
05208     // Wait until it finished
05209     // use timeout to avoid deadlock
05210     if (status == VL53L0X_ERROR_NONE) {
05211         loop_nb = 0;
05212         do {
05213             status = VL53L0X_get_stop_completed_status(dev, &stop_completed);
05214             if ((stop_completed == 0x00) || status != VL53L0X_ERROR_NONE) {
05215                 break;
05216             }
05217             loop_nb = loop_nb + 1;
05218             VL53L0X_polling_delay(dev);
05219         } while (loop_nb < VL53L0X_DEFAULT_MAX_LOOP);
05220 
05221         if (loop_nb >= VL53L0X_DEFAULT_MAX_LOOP) {
05222             status = VL53L0X_ERROR_TIME_OUT;
05223         }
05224 
05225     }
05226 
05227     return status;
05228 }
05229 
05230 
05231 int VL53L0X::init_sensor(uint8_t new_addr)
05232 {
05233     int status;
05234 
05235     VL53L0X_off();
05236     VL53L0X_on();
05237 
05238 //   status=VL53L0X_WaitDeviceBooted(Device);
05239 //   if(status)
05240 //      printf("WaitDeviceBooted fail\n\r");
05241     status = is_present();
05242     if (!status) {
05243         status = init(&_my_device);
05244         if (status != VL53L0X_ERROR_NONE) {
05245             printf("Failed to init VL53L0X sensor!\n\r");
05246             return status;
05247         }
05248 
05249         // deduce silicon version
05250         status = VL53L0X_get_device_info(&_my_device, &_device_info);
05251 
05252         status = prepare();
05253         if (status != VL53L0X_ERROR_NONE) {
05254             printf("Failed to prepare VL53L0X!\n\r");
05255             return status;
05256         }
05257 
05258         if (new_addr != VL53L0X_DEFAULT_ADDRESS) {
05259             status = set_device_address(new_addr);
05260             if (status) {
05261                 printf("Failed to change I2C address!\n\r");
05262                 return status;
05263             }
05264         } else {
05265             printf("Invalid new address!\n\r");
05266             return VL53L0X_ERROR_INVALID_PARAMS;
05267         }
05268     }
05269     return status;
05270 }
05271 
05272 int VL53L0X::range_meas_int_continuous_mode(void (*fptr)(void))
05273 {
05274     int status, clr_status;
05275 
05276     status = VL53L0X_stop_measurement(_device); // it is safer to do this while sensor is stopped
05277 
05278 //   status = VL53L0X_SetInterruptThresholds(Device, VL53L0X_DEVICEMODE_CONTINUOUS_RANGING, 0, 300);
05279 
05280     status = VL53L0X_set_gpio_config(_device, 0, VL53L0X_DEVICEMODE_CONTINUOUS_RANGING,
05281                                      VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY,
05282                                      VL53L0X_INTERRUPTPOLARITY_HIGH);
05283 
05284     if (!status) {
05285         attach_interrupt_measure_detection_irq(fptr);
05286         enable_interrupt_measure_detection_irq();
05287     }
05288 
05289     clr_status = clear_interrupt(VL53L0X_REG_RESULT_INTERRUPT_STATUS | VL53L0X_REG_RESULT_RANGE_STATUS);
05290     if (clr_status) {
05291         VL53L0X_ErrLog("VL53L0X_ClearErrorInterrupt fail\r\n");
05292     }
05293 
05294     if (!status) {
05295         status = range_start_continuous_mode();
05296     }
05297     return status;
05298 }
05299 
05300 
05301 int VL53L0X::start_measurement(OperatingMode operating_mode, void (*fptr)(void))
05302 {
05303     int Status = VL53L0X_ERROR_NONE;
05304     int ClrStatus;
05305 
05306     uint8_t VhvSettings;
05307     uint8_t PhaseCal;
05308     // *** from mass market cube expansion v1.1, ranging with satellites.
05309     // default settings, for normal range.
05310     FixPoint1616_t signalLimit = (FixPoint1616_t)(0.25 * 65536);
05311     FixPoint1616_t sigmaLimit = (FixPoint1616_t)(18 * 65536);
05312     uint32_t timingBudget = 33000;
05313     uint8_t preRangeVcselPeriod = 14;
05314     uint8_t finalRangeVcselPeriod = 10;
05315 
05316     if (operating_mode == range_continuous_interrupt) {
05317         if (_gpio1Int == NULL) {
05318             printf("GPIO1 Error\r\n");
05319             return 1;
05320         }
05321 
05322         Status = VL53L0X_stop_measurement(_device); // it is safer to do this while sensor is stopped
05323 
05324 //        Status = VL53L0X_SetInterruptThresholds(Device, VL53L0X_DEVICEMODE_CONTINUOUS_RANGING, 0, 300);
05325 
05326         Status = VL53L0X_set_gpio_config(_device, 0, VL53L0X_DEVICEMODE_CONTINUOUS_RANGING,
05327                                          VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY,
05328                                          VL53L0X_INTERRUPTPOLARITY_HIGH);
05329 
05330         if (Status == VL53L0X_ERROR_NONE) {
05331             attach_interrupt_measure_detection_irq(fptr);
05332             enable_interrupt_measure_detection_irq();
05333         }
05334 
05335         ClrStatus = clear_interrupt(VL53L0X_REG_RESULT_INTERRUPT_STATUS | VL53L0X_REG_RESULT_RANGE_STATUS);
05336         if (ClrStatus) {
05337             VL53L0X_ErrLog("VL53L0X_ClearErrorInterrupt fail\r\n");
05338         }
05339 
05340         if (Status == VL53L0X_ERROR_NONE) {
05341             Status = VL53L0X_set_device_mode(_device, VL53L0X_DEVICEMODE_CONTINUOUS_RANGING); // Setup in continuous ranging mode
05342         }
05343 
05344         if (Status == VL53L0X_ERROR_NONE) {
05345             Status = VL53L0X_start_measurement(_device);
05346         }
05347     }
05348 
05349     if (operating_mode == range_single_shot_polling) {
05350         // singelshot, polled ranging
05351         if (Status == VL53L0X_ERROR_NONE) {
05352             // no need to do this when we use VL53L0X_PerformSingleRangingMeasurement
05353             Status = VL53L0X_set_device_mode(_device, VL53L0X_DEVICEMODE_SINGLE_RANGING); // Setup in single ranging mode
05354         }
05355 
05356         // Enable/Disable Sigma and Signal check
05357         if (Status == VL53L0X_ERROR_NONE) {
05358             Status = VL53L0X_set_limit_check_enable(_device,
05359                                                     VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, 1);
05360         }
05361         if (Status == VL53L0X_ERROR_NONE) {
05362             Status = VL53L0X_set_limit_check_enable(_device,
05363                                                     VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, 1);
05364         }
05365 
05366 // *** from mass market cube expansion v1.1, ranging with satellites.
05367         /* Ranging configuration */
05368 //*
05369 //        switch(rangingConfig) {
05370 //        case LONG_RANGE:
05371         signalLimit = (FixPoint1616_t)(0.1 * 65536);
05372         sigmaLimit = (FixPoint1616_t)(60 * 65536);
05373         timingBudget = 33000;
05374         preRangeVcselPeriod = 18;
05375         finalRangeVcselPeriod = 14;
05376         /*          break;
05377                 case HIGH_ACCURACY:
05378                     signalLimit = (FixPoint1616_t)(0.25*65536);
05379                     sigmaLimit = (FixPoint1616_t)(18*65536);
05380                     timingBudget = 200000;
05381                     preRangeVcselPeriod = 14;
05382                     finalRangeVcselPeriod = 10;
05383                     break;
05384                 case HIGH_SPEED:
05385                     signalLimit = (FixPoint1616_t)(0.25*65536);
05386                     sigmaLimit = (FixPoint1616_t)(32*65536);
05387                     timingBudget = 20000;
05388                     preRangeVcselPeriod = 14;
05389                     finalRangeVcselPeriod = 10;
05390                     break;
05391                 default:
05392                     debug_printf("Not Supported");
05393                 }
05394         */
05395 
05396         if (Status == VL53L0X_ERROR_NONE) {
05397             Status = VL53L0X_set_limit_check_value(_device,
05398                                                    VL53L0X_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE, signalLimit);
05399         }
05400 
05401         if (Status == VL53L0X_ERROR_NONE) {
05402             Status = VL53L0X_set_limit_check_value(_device,
05403                                                    VL53L0X_CHECKENABLE_SIGMA_FINAL_RANGE, sigmaLimit);
05404         }
05405 
05406         if (Status == VL53L0X_ERROR_NONE) {
05407             Status = VL53L0X_set_measurement_timing_budget_micro_seconds(_device, timingBudget);
05408         }
05409 
05410         if (Status == VL53L0X_ERROR_NONE) {
05411             Status = VL53L0X_set_vcsel_pulse_period(_device,
05412                                                     VL53L0X_VCSEL_PERIOD_PRE_RANGE, preRangeVcselPeriod);
05413         }
05414 
05415         if (Status == VL53L0X_ERROR_NONE) {
05416             Status = VL53L0X_set_vcsel_pulse_period(_device,
05417                                                     VL53L0X_VCSEL_PERIOD_FINAL_RANGE, finalRangeVcselPeriod);
05418         }
05419 
05420         if (Status == VL53L0X_ERROR_NONE) {
05421             Status = VL53L0X_perform_ref_calibration(_device, &VhvSettings, &PhaseCal);
05422         }
05423 
05424     }
05425 
05426     if (operating_mode == range_continuous_polling) {
05427         if (Status == VL53L0X_ERROR_NONE) {
05428             //printf("Call of VL53L0X_SetDeviceMode\n");
05429             Status = VL53L0X_set_device_mode(_device, VL53L0X_DEVICEMODE_CONTINUOUS_RANGING); // Setup in continuous ranging mode
05430         }
05431 
05432         if (Status == VL53L0X_ERROR_NONE) {
05433             //printf("Call of VL53L0X_StartMeasurement\n");
05434             Status = VL53L0X_start_measurement(_device);
05435         }
05436     }
05437 
05438     return Status;
05439 }
05440 
05441 
05442 int VL53L0X::get_measurement(OperatingMode operating_mode, VL53L0X_RangingMeasurementData_t *p_data)
05443 {
05444     int Status = VL53L0X_ERROR_NONE;
05445 
05446     if (operating_mode == range_single_shot_polling) {
05447         Status = VL53L0X_perform_single_ranging_measurement(_device, p_data);
05448     }
05449 
05450     if (operating_mode == range_continuous_polling) {
05451         if (Status == VL53L0X_ERROR_NONE) {
05452             Status = VL53L0X_measurement_poll_for_completion(_device);
05453         }
05454 
05455         if (Status == VL53L0X_ERROR_NONE) {
05456             Status = VL53L0X_get_ranging_measurement_data(_device, p_data);
05457 
05458             // Clear the interrupt
05459             VL53L0X_clear_interrupt_mask(_device, VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY);
05460             VL53L0X_polling_delay(_device);
05461         }
05462     }
05463 
05464     if (operating_mode == range_continuous_interrupt) {
05465         Status = VL53L0X_get_ranging_measurement_data(_device, p_data);
05466         VL53L0X_clear_interrupt_mask(_device, VL53L0X_REG_SYSTEM_INTERRUPT_CLEAR | VL53L0X_REG_RESULT_INTERRUPT_STATUS);
05467     }
05468 
05469     return Status;
05470 }
05471 
05472 
05473 int VL53L0X::stop_measurement(OperatingMode operating_mode)
05474 {
05475     int status = VL53L0X_ERROR_NONE;
05476 
05477 
05478     // don't need to stop for a singleshot range!
05479     if (operating_mode == range_single_shot_polling) {
05480     }
05481 
05482     if (operating_mode == range_continuous_interrupt || operating_mode == range_continuous_polling) {
05483         // continuous mode
05484         if (status == VL53L0X_ERROR_NONE) {
05485             //printf("Call of VL53L0X_StopMeasurement\n");
05486             status = VL53L0X_stop_measurement(_device);
05487         }
05488 
05489         if (status == VL53L0X_ERROR_NONE) {
05490             //printf("Wait Stop to be competed\n");
05491             status = wait_stop_completed(_device);
05492         }
05493 
05494         if (status == VL53L0X_ERROR_NONE)
05495             status = VL53L0X_clear_interrupt_mask(_device,
05496                                                   VL53L0X_REG_SYSTEM_INTERRUPT_GPIO_NEW_SAMPLE_READY);
05497     }
05498 
05499     return status;
05500 }
05501 
05502 
05503 int VL53L0X::handle_irq(OperatingMode operating_mode, VL53L0X_RangingMeasurementData_t *data)
05504 {
05505     int status;
05506     status = get_measurement(operating_mode, data);
05507     enable_interrupt_measure_detection_irq();
05508     return status;
05509 }
05510 
05511 
05512 /******************************************************************************/