This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

We are trying to interface the VL53L1X with nrf52832. but "slave address = 0x52" is not getting reflected in the address register of TWI0.

1. Slave address is not reflected in the address register of TWI0.

2. other information is reflected in registers like operating frequency, SDA, SCL as well as enable.

3. due to the problem of the slave address is not getting reflected, I2C communication isn't established with the sensor.

4. please give me all possible suggestion for solving this logical error regarding it.

Parents
  • Hello Karl,

    1. When we are going to interfacing the TOF sensor(VL53L1X) with ESP32. It is working absolutely fine with the ESP32 platform with Arduino  IDE. I am attaching the library of the TOF sensor which is working on ESP32.

    VL53L1X.hVL53L1X.cpp

    2. It's giving the problem with the nRF52832 platform here I am attaching the library file of the TOF sensor given by the manufacturer (STMicroelectronics).

    vl53l1_api.cvl53l1_api.h

    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file  vl53l1_api_core.c
     *
     * @brief EwokPlus25 low level API function definition
     */
    
    
    #include "vl53l1_ll_def.h"
    #include "vl53l1_ll_device.h"
    #include "vl53l1_platform.h"
    #include "vl53l1_register_map.h"
    #include "vl53l1_register_funcs.h"
    #include "vl53l1_register_settings.h"
    #include "vl53l1_core.h"
    #include "vl53l1_wait.h"
    #include "vl53l1_api_preset_modes.h"
    #include "vl53l1_silicon_core.h"
    #include "vl53l1_api_core.h"
    #include "vl53l1_api_calibration.h"
    
    #ifdef VL53L1_LOG_ENABLE
      #include "vl53l1_api_debug.h"
    #endif
    #ifdef VL53L1_LOGGING
      #include "vl53l1_debug.h"
    #endif
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \
    		fmt, ##__VA_ARGS__)
    
    #define trace_print(level, ...) \
    	_LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \
    	level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__)
    
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_run_ref_spad_char(
    	VL53L1_DEV        Dev,
    	VL53L1_Error     *pcal_status)
    {
    	/*
    	 *  Runs Reference SPAD Characterisation
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t comms_buffer[6];
    
    	VL53L1_refspadchar_config_t *prefspadchar  = &(pdev->refspadchar);
    
    	LOG_FUNCTION_START("");
    
    	/*
    	 * Ensure power force is enabled
    	 */
    
    	if (status == VL53L1_ERROR_NONE) /*lint !e774 always true*/
    		status = VL53L1_enable_powerforce(Dev);
    
    	/*
    	 * Configure device
    	 */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_set_ref_spad_char_config(
    				Dev,
    				prefspadchar->vcsel_period,
    				prefspadchar->timeout_us,
    				prefspadchar->target_count_rate_mcps,
    				prefspadchar->max_count_rate_limit_mcps,
    				prefspadchar->min_count_rate_limit_mcps,
    				pdev->stat_nvm.osc_measured__fast_osc__frequency);
    
    	/*
    	 * Run device test
    	 */
    
    	if (status == VL53L1_ERROR_NONE)
    		status = VL53L1_run_device_test(
    					Dev,
    					prefspadchar->device_test_mode);
    
    	/*
    	 * Read results
    	 */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_ReadMulti(
    				Dev,
    				VL53L1_REF_SPAD_CHAR_RESULT__NUM_ACTUAL_REF_SPADS,
    				comms_buffer,
    				2);
    
    	if (status == VL53L1_ERROR_NONE) {
    		pdev->dbg_results.ref_spad_char_result__num_actual_ref_spads =
    				comms_buffer[0];
    		pdev->dbg_results.ref_spad_char_result__ref_location =
    				comms_buffer[1];
    	}
    
    	/*
    	 * copy results to customer nvm managed G02 registers
    	 */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WriteMulti(
    				Dev,
    				VL53L1_REF_SPAD_MAN__NUM_REQUESTED_REF_SPADS,
    				comms_buffer,
    				2);
    
    	if (status == VL53L1_ERROR_NONE) {
    		pdev->customer.ref_spad_man__num_requested_ref_spads =
    				comms_buffer[0];
    		pdev->customer.ref_spad_man__ref_location =
    				comms_buffer[1];
    	}
    
    	/* After Ref Spad Char the final set of good SPAD enables
    	 * are stored in the NCY results registers below
    	 *
    	 *  - RESULT__SPARE_0_SD_1
    	 *  - RESULT__SPARE_1_SD_1
    	 *  - RESULT__SPARE_2_SD_1
    	 */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_ReadMulti(
    				Dev,
    				VL53L1_RESULT__SPARE_0_SD1,
    				comms_buffer,
    				6);
    
    	/*
    	 * copy reference SPAD enables to customer nvm managed
    	 * G02 registers
    	 */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WriteMulti(
    				Dev,
    				VL53L1_GLOBAL_CONFIG__SPAD_ENABLES_REF_0,
    				comms_buffer,
    				6);
    
    	if (status == VL53L1_ERROR_NONE) {
    		pdev->customer.global_config__spad_enables_ref_0 =
    				comms_buffer[0];
    		pdev->customer.global_config__spad_enables_ref_1 =
    				comms_buffer[1];
    		pdev->customer.global_config__spad_enables_ref_2 =
    				comms_buffer[2];
    		pdev->customer.global_config__spad_enables_ref_3 =
    				comms_buffer[3];
    		pdev->customer.global_config__spad_enables_ref_4 =
    				comms_buffer[4];
    		pdev->customer.global_config__spad_enables_ref_5 =
    				comms_buffer[5];
    	}
    
    #ifdef VL53L1_LOG_ENABLE
    	/* Print customer nvm managed data */
    	if (status == VL53L1_ERROR_NONE)
    		VL53L1_print_customer_nvm_managed(
    			&(pdev->customer),
    			"run_ref_spad_char():pdev->lldata.customer.",
    			VL53L1_TRACE_MODULE_REF_SPAD_CHAR);
    #endif
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		switch (pdev->sys_results.result__range_status) {
    
    		case VL53L1_DEVICEERROR_REFSPADCHARNOTENOUGHDPADS:
    			status = VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS;
    			break;
    
    		case VL53L1_DEVICEERROR_REFSPADCHARMORETHANTARGET:
    			status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH;
    			break;
    
    		case VL53L1_DEVICEERROR_REFSPADCHARLESSTHANTARGET:
    			status = VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW;
    			break;
    		}
    	}
    
    	/*
    	 * Save unfiltered status
    	 */
    
    	*pcal_status = status;
    
    	/* Status exception code */
    
    	IGNORE_STATUS(
    		IGNORE_REF_SPAD_CHAR_NOT_ENOUGH_SPADS,
    		VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS,
    		status);
    
    	IGNORE_STATUS(
    		IGNORE_REF_SPAD_CHAR_RATE_TOO_HIGH,
    		VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH,
    		status);
    
    	IGNORE_STATUS(
    		IGNORE_REF_SPAD_CHAR_RATE_TOO_LOW,
    		VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW,
    		status);
    
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_run_offset_calibration(
    	VL53L1_DEV	                  Dev,
    	int16_t                       cal_distance_mm,
    	VL53L1_Error                 *pcal_status)
    {
    	/*
    	 * Runs offset calibration
    	 *
    	 * Recommended tuning parm settings:
    	 *
    	 *  - pre_num_of_samples    =    32
    	 *  - mm1_num_of_samples    =   100
    	 *  - mm2_num_of_samples    =    64
    	 *  - target_distance_mm    =   140mm
    	 *  - target reflectance    =     5%
    	 *
    	 * Standard Ranging (sigma delta mode):
    	 *  - dss_config__target_total_rate_mcps = 20.0 -40.0 Mcps
    	 *  - phasecal_config_timeout_us        =  1000
    	 *  - range_config_timeout_us           = 13000
    	 *  - mm_config_timeout_us              = 13000
    	 *
    	 *
    	 * Note: function parms simplified as part of
    	 * Patch_CalFunctionSimplification_11791
    	 *
    	 */
    
    	VL53L1_Error status        = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev =
    		VL53L1DevStructGetLLDriverHandle(Dev);
    
    	VL53L1_DevicePresetModes device_preset_modes[VL53L1_MAX_OFFSET_RANGE_RESULTS];
    
    	VL53L1_range_results_t      range_results;
    	VL53L1_range_results_t     *prange_results = &range_results;
    	VL53L1_range_data_t        *prange_data = NULL;
    	VL53L1_offset_range_data_t *poffset     = NULL;
    
    	uint8_t  i                      = 0;
    	uint8_t  m                      = 0;
    	uint8_t  measurement_mode       =
    		VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK;
    	uint16_t manual_effective_spads =
    		pdev->gen_cfg.dss_config__manual_effective_spads_select;
    
    	uint8_t num_of_samples[VL53L1_MAX_OFFSET_RANGE_RESULTS];
    
    	LOG_FUNCTION_START("");
    
    	/* select requested offset calibration mode */
    
    	switch (pdev->offset_calibration_mode) {
    
    	default:
    		device_preset_modes[0] =
    			VL53L1_DEVICEPRESETMODE_STANDARD_RANGING;
    		device_preset_modes[1] =
    			VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL;
    		device_preset_modes[2] =
    			VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL;
    	break;
    	}
    
    	/* initialise num_of_samples */
    	/* Start Patch_CalFunctionSimplification_11791 */
    	num_of_samples[0] = pdev->offsetcal_cfg.pre_num_of_samples;
    	num_of_samples[1] = pdev->offsetcal_cfg.mm1_num_of_samples;
    	num_of_samples[2] = pdev->offsetcal_cfg.mm2_num_of_samples;
    	/* End Patch_CalFunctionSimplification_11791 */
    
    	/* force all offsets to zero */
    
    	switch (pdev->offset_calibration_mode) {
    
    	case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY:
    		/* only run pre range */
    		pdev->offset_results.active_results  = 1;
    
    	break;
    
    	default:
    
    		pdev->customer.mm_config__inner_offset_mm  = 0;
    		pdev->customer.mm_config__outer_offset_mm  = 0;
    		pdev->offset_results.active_results  =
    			VL53L1_MAX_OFFSET_RANGE_RESULTS;
    
    	break;
    	}
    
    	pdev->customer.algo__part_to_part_range_offset_mm = 0;
    
    	/* initialise offset range results */
    
    	pdev->offset_results.max_results           = VL53L1_MAX_OFFSET_RANGE_RESULTS;
    	pdev->offset_results.cal_distance_mm       = cal_distance_mm;
    
    	for (m = 0 ; m <  VL53L1_MAX_OFFSET_RANGE_RESULTS; m++) {
    
    		poffset = &(pdev->offset_results.data[m]);
    		poffset->preset_mode         = 0;
    		poffset->no_of_samples       = 0;
    		poffset->effective_spads     = 0;
    		poffset->peak_rate_mcps      = 0;
    		poffset->sigma_mm            = 0;
    		poffset->median_range_mm     = 0;
    	}
    
    	for (m = 0 ; m < pdev->offset_results.active_results ; m++) {
    
    		poffset = &(pdev->offset_results.data[m]);
    
    		poffset->preset_mode         = device_preset_modes[m];
    
    		/* Apply preset mode */
    
    		if (status == VL53L1_ERROR_NONE)
    			status =
    				VL53L1_set_preset_mode(
    					Dev,
    					device_preset_modes[m],
    					/* Start Patch_CalFunctionSimplification_11791 */
    					pdev->offsetcal_cfg.dss_config__target_total_rate_mcps,
    					pdev->offsetcal_cfg.phasecal_config_timeout_us,
    					pdev->offsetcal_cfg.mm_config_timeout_us,
    					pdev->offsetcal_cfg.range_config_timeout_us,
    					/* End Patch_CalFunctionSimplification_11791 */
    					100);
    
    		pdev->gen_cfg.dss_config__manual_effective_spads_select =
    				manual_effective_spads;
    
    		/* Initialise device and start range */
    
    		if (status == VL53L1_ERROR_NONE)
    			status =
    				VL53L1_init_and_start_range(
    					Dev,
    					measurement_mode,
    					VL53L1_DEVICECONFIGLEVEL_CUSTOMER_ONWARDS);
    
    		for (i = 0 ; i <= (num_of_samples[m]+2) ; i++) {
    
    			/* Wait for range completion */
    
    			if (status == VL53L1_ERROR_NONE)
    				status =
    					VL53L1_wait_for_range_completion(Dev);
    
    			/*
    			 *  Get Device Results
    			 *  - Checks the stream count is the expected one
    			 *  - Read device system results
    			 */
    
    			if (status == VL53L1_ERROR_NONE)
    				status =
    					VL53L1_get_device_results(
    						Dev,
    						VL53L1_DEVICERESULTSLEVEL_FULL,
    						prange_results);
    
    			/*
    			 * Ignore 1st two ranges to give the sigma delta initial
    			 * phase time to settle
    			 *
    			 * accummulate range results if range is successful
    			 */
    
    			prange_data  = &(prange_results->data[0]);
    
    			if (prange_results->stream_count   > 1) {
    
    				if (prange_data->range_status ==
    						VL53L1_DEVICEERROR_RANGECOMPLETE) {
    
    					poffset->no_of_samples++;
    					poffset->effective_spads +=
    						(uint32_t)prange_data->actual_effective_spads;
    					poffset->peak_rate_mcps  +=
    						(uint32_t)prange_data->peak_signal_count_rate_mcps;
    					poffset->sigma_mm        +=
    						(uint32_t)prange_data->sigma_mm;
    					poffset->median_range_mm +=
    						(int32_t)prange_data->median_range_mm;
    
    					poffset->dss_config__roi_mode_control =
    						pdev->gen_cfg.dss_config__roi_mode_control;
    					poffset->dss_config__manual_effective_spads_select =
    						pdev->gen_cfg.dss_config__manual_effective_spads_select;
    				}
    			}
    
    			/*
    			 * Conditional wait for firmware ready. Only waits for timed
    			 * and single shot modes. Mode check is performed inside the
    			 * wait function
    			 */
    
    			if (status == VL53L1_ERROR_NONE)
    				status =
    					VL53L1_wait_for_firmware_ready(Dev);
    
    			/*
    			 * Send ranging handshake
    			 *
    			 *  - Update Zone management
    			 *  - Update GPH registers
    			 *  - Clear current interrupt
    			 *  - Initialise SYSTEM__MODE_START for next range (if there is one!)
    			 */
    
    			if (status == VL53L1_ERROR_NONE)
    				status =
    					VL53L1_clear_interrupt_and_enable_next_range(
    						Dev,
    						measurement_mode);
    		}
    
    		/* Stop range */
    
    		if (status == VL53L1_ERROR_NONE)
    			status = VL53L1_stop_range(Dev);
    
    		/* Wait for Stop (abort) range to complete */
    
    		if (status == VL53L1_ERROR_NONE)
    			status = VL53L1_WaitUs(Dev, 1000);
    
    		/* generate average values */
    		if (poffset->no_of_samples > 0) {
    
    			poffset->effective_spads += (poffset->no_of_samples/2);
    			poffset->effective_spads /= poffset->no_of_samples;
    
    			poffset->peak_rate_mcps  += (poffset->no_of_samples/2);
    			poffset->peak_rate_mcps  /= poffset->no_of_samples;
    
    			poffset->sigma_mm        += (poffset->no_of_samples/2);
    			poffset->sigma_mm        /= poffset->no_of_samples;
    
    			poffset->median_range_mm += (poffset->no_of_samples/2);
    			poffset->median_range_mm /= poffset->no_of_samples;
    
    			poffset->range_mm_offset  =  (int32_t)cal_distance_mm;
    			poffset->range_mm_offset -= poffset->median_range_mm;
    
    			/* remember the number of SPADs for standard ranging */
    			if (poffset->preset_mode ==
    				VL53L1_DEVICEPRESETMODE_STANDARD_RANGING)
    				manual_effective_spads =
    					(uint16_t)poffset->effective_spads;
    		}
    	}
    
    	/* Calculate offsets */
    
    	switch (pdev->offset_calibration_mode) {
    
    	case VL53L1_OFFSETCALIBRATIONMODE__MM1_MM2__STANDARD_PRE_RANGE_ONLY:
    
    		/* copy offsets to customer data structure */
    		pdev->customer.mm_config__inner_offset_mm +=
    			(int16_t)pdev->offset_results.data[0].range_mm_offset;
    		pdev->customer.mm_config__outer_offset_mm +=
    			(int16_t)pdev->offset_results.data[0].range_mm_offset;
    	break;
    
    	default:
    		/* copy offsets to customer data structure */
    		pdev->customer.mm_config__inner_offset_mm =
    			(int16_t)pdev->offset_results.data[1].range_mm_offset;
    		pdev->customer.mm_config__outer_offset_mm =
    			(int16_t)pdev->offset_results.data[2].range_mm_offset;
    		pdev->customer.algo__part_to_part_range_offset_mm = 0;
    
    		/* copy average rate and effective SPAD count to
    		   additional offset calibration data structure */
    
    		pdev->add_off_cal_data.result__mm_inner_actual_effective_spads =
    			(uint16_t)pdev->offset_results.data[1].effective_spads;
    		pdev->add_off_cal_data.result__mm_outer_actual_effective_spads =
    			(uint16_t)pdev->offset_results.data[2].effective_spads;
    
    		pdev->add_off_cal_data.result__mm_inner_peak_signal_count_rtn_mcps =
    			(uint16_t)pdev->offset_results.data[1].peak_rate_mcps;
    		pdev->add_off_cal_data.result__mm_outer_peak_signal_count_rtn_mcps =
    			(uint16_t)pdev->offset_results.data[2].peak_rate_mcps;
    
    		break;
    	}
    
    
    	/* apply to device */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_set_customer_nvm_managed(
    				Dev,
    				&(pdev->customer));
    
    	/*
    	 *  Check the peak rates, sigma, min spads for each stage
    	 */
    
    	for (m = 0 ; m < pdev->offset_results.active_results ; m++) {
    
    		poffset = &(pdev->offset_results.data[m]);
    
    		if (status == VL53L1_ERROR_NONE) {
    
    			pdev->offset_results.cal_report = m;
    
    			if (poffset->no_of_samples < num_of_samples[m])
    				status = VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES;
    
    			/* only check sigma for the pre-range as
    			 * the it is not calculated by the device
    			 * for the MM1 and MM2 stages
    			 */
    			if (m == 0 && poffset->sigma_mm >
    				((uint32_t)VL53L1_OFFSET_CAL_MAX_SIGMA_MM<<5))
    				status = VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH;
    
    			if (poffset->peak_rate_mcps >
    				VL53L1_OFFSET_CAL_MAX_PRE_PEAK_RATE_MCPS)
    				status = VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH;
    
    			if (poffset->dss_config__manual_effective_spads_select <
    				VL53L1_OFFSET_CAL_MIN_EFFECTIVE_SPADS)
    				status = VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW;
    
    			if (poffset->dss_config__manual_effective_spads_select == 0)
    				status = VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL;
    
    			if (poffset->no_of_samples == 0)
    				status = VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL;
    		}
    	}
    
    	/*
    	 * Save unfiltered status
    	 */
    
    	pdev->offset_results.cal_status = status;
    	*pcal_status = pdev->offset_results.cal_status;
    
    	/* Status exception codes */
    
    	IGNORE_STATUS(
    		IGNORE_OFFSET_CAL_MISSING_SAMPLES,
    		VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES,
    		status);
    
    	IGNORE_STATUS(
    		IGNORE_OFFSET_CAL_SIGMA_TOO_HIGH,
    		VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH,
    		status);
    
    	IGNORE_STATUS(
    		IGNORE_OFFSET_CAL_RATE_TOO_HIGH,
    		VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH,
    		status);
    
    	IGNORE_STATUS(
    		IGNORE_OFFSET_CAL_SPAD_COUNT_TOO_LOW,
    		VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW,
    		status);
    
    #ifdef VL53L1_LOG_ENABLE
    
    	/* Prints out the offset calibration data for debug */
    
    	VL53L1_print_customer_nvm_managed(
    		&(pdev->customer),
    		"run_offset_calibration():pdev->lldata.customer.",
    		VL53L1_TRACE_MODULE_OFFSET_DATA);
    
    	VL53L1_print_additional_offset_cal_data(
    		&(pdev->add_off_cal_data),
    		"run_offset_calibration():pdev->lldata.add_off_cal_data.",
    		VL53L1_TRACE_MODULE_OFFSET_DATA);
    
    	VL53L1_print_offset_range_results(
    		&(pdev->offset_results),
    		"run_offset_calibration():pdev->lldata.offset_results.",
    		VL53L1_TRACE_MODULE_OFFSET_DATA);
    #endif
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_run_spad_rate_map(
    	VL53L1_DEV                 Dev,
    	VL53L1_DeviceTestMode      device_test_mode,
    	VL53L1_DeviceSscArray      array_select,
    	uint32_t                   ssc_config_timeout_us,
        VL53L1_spad_rate_data_t   *pspad_rate_data)
    {
    
        /**
         *  Runs SPAD Rate Map
         */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    
    	VL53L1_LLDriverData_t *pdev =
    		VL53L1DevStructGetLLDriverHandle(Dev);
    
    	LOG_FUNCTION_START("");
    
    	/*
    	 * Ensure power force is enabled
    	 */
    	if (status == VL53L1_ERROR_NONE)
    		status = VL53L1_enable_powerforce(Dev);
    
    	/*
    	 * Configure the test
    	 */
    
    	if (status == VL53L1_ERROR_NONE) {
    		pdev->ssc_cfg.array_select = array_select;
    		pdev->ssc_cfg.timeout_us   = ssc_config_timeout_us;
    		status =
    			VL53L1_set_ssc_config(
    				Dev,
    				&(pdev->ssc_cfg),
    				pdev->stat_nvm.osc_measured__fast_osc__frequency);
    	}
    
    	/*
    	 * Run device test
    	 */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_run_device_test(
    				Dev,
    				device_test_mode);
    
    	/*
    	 * Read Rate Data from Patch Ram
    	 */
    
        if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_get_spad_rate_data(
    				Dev,
    				pspad_rate_data);
    
    	if (device_test_mode == VL53L1_DEVICETESTMODE_LCR_VCSEL_ON)
    		pspad_rate_data->fractional_bits =  7;
    	else
    		pspad_rate_data->fractional_bits = 15;
    
    	/* Ensure power force is disabled */
    
    	if (status == VL53L1_ERROR_NONE)
    		status = VL53L1_disable_powerforce(Dev);
    
    #ifdef VL53L1_LOG_ENABLE
        /* Print return rate data and map */
    
        if (status == VL53L1_ERROR_NONE) {
    		VL53L1_print_spad_rate_data(
    			pspad_rate_data,
    			"run_spad_rate_map():",
    			VL53L1_TRACE_MODULE_SPAD_RATE_MAP);
    		VL53L1_print_spad_rate_map(
    			pspad_rate_data,
    			"run_spad_rate_map():",
    			VL53L1_TRACE_MODULE_SPAD_RATE_MAP);
        }
    #endif
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_run_device_test(
    	VL53L1_DEV             Dev,
    	VL53L1_DeviceTestMode  device_test_mode)
    {
    	/*
    	 *  Runs the selected Device Test Mode
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t      comms_buffer[2];
    	uint8_t      gpio_hv_mux__ctrl = 0;
    
    	LOG_FUNCTION_START("");
    
    	/*
    	 * Get current interrupt config
    	 */
    
    	if (status == VL53L1_ERROR_NONE) /*lint !e774 always true*/
    		status =
    			VL53L1_RdByte(
    				Dev,
    				VL53L1_GPIO_HV_MUX__CTRL,
    				&gpio_hv_mux__ctrl);
    
    	if (status == VL53L1_ERROR_NONE)
    		pdev->stat_cfg.gpio_hv_mux__ctrl = gpio_hv_mux__ctrl;
    
    	/*
    	 * Trigger the test
    	 */
    	if (status == VL53L1_ERROR_NONE)
    		status = VL53L1_start_test(
    					Dev,
    					device_test_mode);
    
    	/*
    	 * Wait for test completion
    	 */
    	if (status == VL53L1_ERROR_NONE)
    		status = VL53L1_wait_for_test_completion(Dev);
    
    	/*
    	 * Read range and report status
    	 */
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_ReadMulti(
    				Dev,
    				VL53L1_RESULT__RANGE_STATUS,
    				comms_buffer,
    				2);
    
    	if (status == VL53L1_ERROR_NONE) {
    		pdev->sys_results.result__range_status  = comms_buffer[0];
    		pdev->sys_results.result__report_status = comms_buffer[1];
    	}
    
    	/* mask range status bits */
    
    	pdev->sys_results.result__range_status &=
    		VL53L1_RANGE_STATUS__RANGE_STATUS_MASK;
    
    	if (status == VL53L1_ERROR_NONE) {
    		trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    			"    Device Test Complete:\n\t%-32s = %3u\n\t%-32s = %3u\n",
    			"result__range_status",
    			pdev->sys_results.result__range_status,
    			"result__report_status",
    			pdev->sys_results.result__report_status);
    
    		/*
    		 * Clear interrupt
    		 */
    		if (status == VL53L1_ERROR_NONE)
    			status = VL53L1_clear_interrupt(Dev);
    	}
    
    	/*
    	 * Clear test mode register
    	 *  - required so that next test command will trigger
    	 *    internal MCU interrupt
    	 */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_start_test(
    				Dev,
    				0x00);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    vl53l1_api_calibration.hvl53l1_api_core.cvl53l1_api_core.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file  vl53l1_api_debug.c
     * @brief EwokPlus25 low level Driver debug function definition
     */
    
    #include "vl53l1_ll_def.h"
    #include "vl53l1_ll_device.h"
    #include "vl53l1_register_structs.h"
    #include "vl53l1_core.h"
    #include "vl53l1_api_debug.h"
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \
    	fmt, ##__VA_ARGS__)
    
    #define trace_print(level, ...) \
    	_LOG_TRACE_PRINT(trace_flags, \
    	level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__)
    
    
    /* Start Patch_AdditionalDebugData_11823 */
    
    VL53L1_Error VL53L1_get_additional_data(
    	VL53L1_DEV                       Dev,
    	VL53L1_additional_data_t        *pdata)
    {
    	/*
    	 * Gets the addition debug data
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	LOG_FUNCTION_START("");
    
    	/* get LL Driver configuration parameters */
    
    	pdata->preset_mode             = pdev->preset_mode;
    	pdata->measurement_mode        = pdev->measurement_mode;
    
    	pdata->phasecal_config_timeout_us  = pdev->phasecal_config_timeout_us;
    	pdata->mm_config_timeout_us        = pdev->mm_config_timeout_us;
    	pdata->range_config_timeout_us     = pdev->range_config_timeout_us;
    	pdata->inter_measurement_period_ms = pdev->inter_measurement_period_ms;
    	pdata->dss_config__target_total_rate_mcps =
    			pdev->dss_config__target_total_rate_mcps;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    /* End Patch_AdditionalDebugData_11823 */
    
    #ifdef VL53L1_LOG_ENABLE
    
    void  VL53L1_signed_fixed_point_sprintf(
    	int32_t    signed_fp_value,
    	uint8_t    frac_bits,
    	uint16_t   buf_size,
    	char      *pbuffer)
    {
    	/*
    	 * Converts input signed fixed point number into a string
    	 */
    
    	uint32_t  fp_value      = 0;
    	uint32_t  unity_fp_value = 0;
    	uint32_t  sign_bit       = 0;
    	uint32_t  int_part       = 0;
    	uint32_t  frac_part      = 0;
    	uint32_t  dec_points     = 0;
    	uint32_t  dec_scaler     = 0;
    	uint32_t  dec_part       = 0;
    
    	uint64_t  tmp_long_int   = 0;
    
    	char  fmt[VL53L1_MAX_STRING_LENGTH];
    
    	SUPPRESS_UNUSED_WARNING(buf_size);
    
    	/* split into integer and fractional values */
    
    	sign_bit       =  signed_fp_value >> 31;
    
    	if (sign_bit > 0) {
    		fp_value = 0x80000000 -
    			(0x7FFFFFFF & (uint32_t)signed_fp_value);
    	} else
    		fp_value = (uint32_t)signed_fp_value;
    
    	int_part       =  fp_value >> frac_bits;
    	unity_fp_value =  0x01 << frac_bits;
    	frac_part      =  fp_value & (unity_fp_value-1);
    
    	/* Calculate decimal scale factor and required decimal points
    	 * min number of displayed places is 2
    	 */
    	dec_points =   2;
    	dec_scaler = 100;
    
    	while (dec_scaler < unity_fp_value) {
    		dec_points++;
    		dec_scaler *= 10;
    	}
    
    	/* Build format string */
    	if (sign_bit > 0)
    		sprintf(fmt, "-%%u.%%0%uu", dec_points);
    	else
    		sprintf(fmt,  "%%u.%%0%uu", dec_points);
    
    	/* Convert fractional part into a decimal
    	 * need 64-bit head room at this point
    	 */
    	tmp_long_int  = (uint64_t)frac_part * (uint64_t)dec_scaler;
    	tmp_long_int += (uint64_t)unity_fp_value/2;
    
    	tmp_long_int = do_division_u(tmp_long_int, (uint64_t)unity_fp_value);
    
    	dec_part = (uint32_t)tmp_long_int;
    
    	/* Generate string for fixed point number */
    	sprintf(
    		pbuffer,
    		fmt,
    		int_part,
    		dec_part);
    }
    
    
    void VL53L1_print_static_nvm_managed(
    	VL53L1_static_nvm_managed_t   *pdata,
    	char                          *pprefix,
    	uint32_t                       trace_flags)
    {
    	/**
    	 * Prints out VL53L1_static_nvm_managed_t for debug
    	*/
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = 0x%02X\n",
    		pprefix,
    		"i2c_slave__device_address",
    		pdata->i2c_slave__device_address);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__vhv_ref_sel_vddpix",
    		pdata->ana_config__vhv_ref_sel_vddpix);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__vhv_ref_sel_vquench",
    		pdata->ana_config__vhv_ref_sel_vquench);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__reg_avdd1v2_sel",
    		pdata->ana_config__reg_avdd1v2_sel);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__fast_osc__trim",
    		pdata->ana_config__fast_osc__trim);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->osc_measured__fast_osc__frequency,
    		12,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"osc_measured__fast_osc__frequency",
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"vhv_config__timeout_macrop_loop_bound",
    		pdata->vhv_config__timeout_macrop_loop_bound);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"vhv_config__count_thresh",
    		pdata->vhv_config__count_thresh);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"vhv_config__offset",
    		pdata->vhv_config__offset);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"vhv_config__init",
    		pdata->vhv_config__init);
    }
    
    
    void VL53L1_print_customer_nvm_managed(
    	VL53L1_customer_nvm_managed_t *pdata,
    	char                          *pprefix,
    	uint32_t                       trace_flags)
    {
    	/*
    	 * Prints out VL53L1_customer_nvm_managed_t for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_ref_0",
    		pdata->global_config__spad_enables_ref_0);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_ref_1",
    		pdata->global_config__spad_enables_ref_1);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_ref_2",
    		pdata->global_config__spad_enables_ref_2);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_ref_3",
    		pdata->global_config__spad_enables_ref_3);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_ref_4",
    		pdata->global_config__spad_enables_ref_4);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_ref_5",
    		pdata->global_config__spad_enables_ref_5);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__ref_en_start_select",
    		pdata->global_config__ref_en_start_select);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ref_spad_man__num_requested_ref_spads",
    		pdata->ref_spad_man__num_requested_ref_spads);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ref_spad_man__ref_location",
    		pdata->ref_spad_man__ref_location);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps,
    		9,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"algo__crosstalk_compensation_plane_offset_kcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->algo__crosstalk_compensation_x_plane_gradient_kcps,
    		11,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"algo__crosstalk_compensation_x_plane_gradient_kcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->algo__crosstalk_compensation_y_plane_gradient_kcps,
    		11,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"algo__crosstalk_compensation_y_plane_gradient_kcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->ref_spad_char__total_rate_target_mcps,
    		7,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"ref_spad_char__total_rate_target_mcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->algo__part_to_part_range_offset_mm,
    		2,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"algo__part_to_part_range_offset_mm",
    		fp_text);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %d\n",
    		pprefix,
    		"mm_config__inner_offset_mm",
    		pdata->mm_config__inner_offset_mm);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %d\n",
    		pprefix,
    		"mm_config__outer_offset_mm",
    		pdata->mm_config__outer_offset_mm);
    }
    
    
    void VL53L1_print_nvm_copy_data(
    	VL53L1_nvm_copy_data_t      *pdata,
    	char                        *pprefix,
    	uint32_t                     trace_flags)
    {
    	/**
    	 * Prints out VL53L1_nvm_copy_data_t for debug
    	 */
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"identification__model_id",
    		pdata->identification__model_id);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"identification__module_type",
    		pdata->identification__module_type);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"identification__revision_id",
    		pdata->identification__revision_id);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"identification__module_id",
    		pdata->identification__module_id);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__fast_osc__trim_max",
    		pdata->ana_config__fast_osc__trim_max);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__fast_osc__freq_set",
    		pdata->ana_config__fast_osc__freq_set);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__vcsel_trim",
    		pdata->ana_config__vcsel_trim);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__vcsel_selion",
    		pdata->ana_config__vcsel_selion);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"ana_config__vcsel_selion_max",
    		pdata->ana_config__vcsel_selion_max);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"protected_laser_safety__lock_bit",
    		pdata->protected_laser_safety__lock_bit);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"laser_safety__key",
    		pdata->laser_safety__key);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"laser_safety__key_ro",
    		pdata->laser_safety__key_ro);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"laser_safety__clip",
    		pdata->laser_safety__clip);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"laser_safety__mult",
    		pdata->laser_safety__mult);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_0",
    		pdata->global_config__spad_enables_rtn_0);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_1",
    		pdata->global_config__spad_enables_rtn_1);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_2",
    		pdata->global_config__spad_enables_rtn_2);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_3",
    		pdata->global_config__spad_enables_rtn_3);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_4",
    		pdata->global_config__spad_enables_rtn_4);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_5",
    		pdata->global_config__spad_enables_rtn_5);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_6",
    		pdata->global_config__spad_enables_rtn_6);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_7",
    		pdata->global_config__spad_enables_rtn_7);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_8",
    		pdata->global_config__spad_enables_rtn_8);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_9",
    		pdata->global_config__spad_enables_rtn_9);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_10",
    		pdata->global_config__spad_enables_rtn_10);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_11",
    		pdata->global_config__spad_enables_rtn_11);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_12",
    		pdata->global_config__spad_enables_rtn_12);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_13",
    		pdata->global_config__spad_enables_rtn_13);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_14",
    		pdata->global_config__spad_enables_rtn_14);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_15",
    		pdata->global_config__spad_enables_rtn_15);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_16",
    		pdata->global_config__spad_enables_rtn_16);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_17",
    		pdata->global_config__spad_enables_rtn_17);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_18",
    		pdata->global_config__spad_enables_rtn_18);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_19",
    		pdata->global_config__spad_enables_rtn_19);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_20",
    		pdata->global_config__spad_enables_rtn_20);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_21",
    		pdata->global_config__spad_enables_rtn_21);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_22",
    		pdata->global_config__spad_enables_rtn_22);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_23",
    		pdata->global_config__spad_enables_rtn_23);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_24",
    		pdata->global_config__spad_enables_rtn_24);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_25",
    		pdata->global_config__spad_enables_rtn_25);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_26",
    		pdata->global_config__spad_enables_rtn_26);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_27",
    		pdata->global_config__spad_enables_rtn_27);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_28",
    		pdata->global_config__spad_enables_rtn_28);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_29",
    		pdata->global_config__spad_enables_rtn_29);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_30",
    		pdata->global_config__spad_enables_rtn_30);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_config__spad_enables_rtn_31",
    		pdata->global_config__spad_enables_rtn_31);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"roi_config__mode_roi_centre_spad",
    		pdata->roi_config__mode_roi_centre_spad);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = 0x%02X\n",
    		pprefix,
    		"roi_config__mode_roi_xy_size",
    		pdata->roi_config__mode_roi_xy_size);
    }
    
    
    void VL53L1_print_range_data(
    	VL53L1_range_data_t *pdata,
    	char                *pprefix,
    	uint32_t             trace_flags)
    {
    	/*
    	 * Prints out the range data structure for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"range_id",
    		pdata->range_id);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"time_stamp",
    		pdata->time_stamp);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->width,
    		 4,	VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"width",
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"woi",
    		pdata->woi);
    
    	/* Fast Oscillator Frequency */
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->fast_osc_frequency,
    		12,	VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"fast_osc_frequency",
    		fp_text);
    
    	/* Zero Distance Phase */
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->zero_distance_phase,
    		11, VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"zero_distance_phase",
    		fp_text);
    
    	/* Actual effective SPAD count */
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->actual_effective_spads,
    		8, VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"actual_effective_spad",
    		fp_text);
    
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"total_periods_elapsed",
    		pdata->total_periods_elapsed);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"peak_duration_us",
    		pdata->peak_duration_us);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"woi_duration_us",
    		pdata->woi_duration_us);
    
    	trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %d\n",
    		pprefix,
    			"ambient_window_events",
    			pdata->ambient_window_events);
    
    	trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %d\n",
    		pprefix,
    			"ranging_total_events",
    			pdata->ranging_total_events);
    
    	trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %d\n",
    		pprefix,
    			"signal_total_events",
    			pdata->signal_total_events);
    
    	/* Rates */
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->peak_signal_count_rate_mcps,
    		7, VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"peak_signal_count_rate_mcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->avg_signal_count_rate_mcps,
    		7, VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"avg_signal_count_rate_mcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->ambient_count_rate_mcps,
    		7, VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"ambient_count_rate_mcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->total_rate_per_spad_mcps,
    		13, VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"total_rate_per_spad_mcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->peak_rate_per_spad_kcps,
    		11, VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"peak_rate_per_spad_kcps",
    		fp_text);
    
    	/* Sigma */
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->sigma_mm,
    		 2,	VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"sigma_mm",
    		fp_text);
    
    	/* Phase */
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->median_phase,
    		11,	VL53L1_MAX_STRING_LENGTH, fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"median_phase",
    		fp_text);
    
    	/* Offset Corrected Range */
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %d\n",
    		pprefix,
    		"median_range_mm",
    		pdata->median_range_mm);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"range_status",
    		pdata->range_status);
    }
    
    
    void VL53L1_print_range_results(
    	VL53L1_range_results_t *pdata,
    	char                   *pprefix,
    	uint32_t                trace_flags)
    {
    	/*
    	 * Prints out the range results data structure for debug
    	 */
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"cfg_device_state",
    		pdata->cfg_device_state);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"rd_device_state",
    		pdata->rd_device_state);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"stream_count",
    		pdata->stream_count);
    
    	trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    			"%s%s = %u\n",
    			pprefix,
    			"device_status",
    			pdata->device_status);
    
    }
    
    void VL53L1_print_offset_range_results(
    	VL53L1_offset_range_results_t *pdata,
    	char                          *pprefix,
    	uint32_t                       trace_flags)
    {
    	/*
    	 * Prints out the offset range results data structure for debug
    	 */
    
    	char  pre_text[VL53L1_MAX_STRING_LENGTH];
    	char *ppre_text = &(pre_text[0]);
    
    	uint8_t  i = 0;
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"cal_distance_mm",
    		pdata->cal_distance_mm);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"cal_status",
    		pdata->cal_status);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"cal_report",
    		pdata->cal_report);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"max_results",
    		pdata->max_results);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"active_results",
    		pdata->active_results);
    
    	for (i = 0 ; i < pdata->active_results ; i++) {
    		sprintf(ppre_text, "%sdata[%u].", pprefix, i);
    		VL53L1_print_offset_range_data(
    			&(pdata->data[i]),
    			ppre_text, trace_flags);
    	}
    }
    
    void VL53L1_print_offset_range_data(
    	VL53L1_offset_range_data_t *pdata,
    	char                       *pprefix,
    	uint32_t                    trace_flags)
    {
    	/*
    	 * Prints out the xtalk range (ROI) data structure for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"preset_mode",
    		pdata->preset_mode);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"dss_config__roi_mode_control",
    		pdata->dss_config__roi_mode_control);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->dss_config__manual_effective_spads_select,
    		8,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"dss_config__manual_effective_spads_select",
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"no_of_samples",
    		pdata->no_of_samples);
    
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->effective_spads,
    		8,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"effective_spads",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->peak_rate_mcps,
    		7,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"peak_rate_mcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->sigma_mm,
    		2,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"sigma_mm",
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %d\n",
    		pprefix,
    		"median_range_mm",
    		pdata->median_range_mm);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %d\n",
    		pprefix,
    		"range_mm_offset",
    		pdata->range_mm_offset);
    }
    
    void VL53L1_print_additional_offset_cal_data(
    	VL53L1_additional_offset_cal_data_t *pdata,
    	char                                *pprefix,
    	uint32_t                             trace_flags)
    {
    	/*
    	 * Prints out the xtalk range (ROI) data structure for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->result__mm_inner_actual_effective_spads,
    		8,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"result__mm_inner_actual_effective_spads",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->result__mm_outer_actual_effective_spads,
    		8,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"result__mm_outer_actual_effective_spads",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->result__mm_inner_peak_signal_count_rtn_mcps,
    		7,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"result__mm_inner_peak_signal_count_rtn_mcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->result__mm_outer_peak_signal_count_rtn_mcps,
    		7,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"result__mm_outer_peak_signal_count_rtn_mcps",
    		fp_text);
    }
    
    
    void VL53L1_print_cal_peak_rate_map(
    	VL53L1_cal_peak_rate_map_t *pdata,
    	char                       *pprefix,
    	uint32_t                    trace_flags)
    {
    	/*
    	 * Prints out peak rate map structure for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    	char  pre_text[VL53L1_MAX_STRING_LENGTH];
    	char *ppre_text = &(pre_text[0]);
    
    	uint8_t   i = 0;
    	uint8_t   x = 0;
    	uint8_t   y = 0;
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->cal_distance_mm,
    		2,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"cal_distance_mm",
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"max_samples",
    		pdata->max_samples);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"width",
    		pdata->width);
    
    	trace_print(
    	VL53L1_TRACE_LEVEL_INFO,
    	"%s%s = %u\n",
    	pprefix,
    	"height",
    	pdata->height);
    
    	i = 0;
    	for (y = 0 ; y < pdata->height ; y++) {
    		for (x = 0 ; x < pdata->width ; x++) {
    
    			sprintf(ppre_text, "%speak_rate_mcps[%u]", pprefix, i);
    
    			VL53L1_signed_fixed_point_sprintf(
    				(int32_t)pdata->peak_rate_mcps[i],
    				7,
    				VL53L1_MAX_STRING_LENGTH,
    				fp_text);
    
    			trace_print(
    				VL53L1_TRACE_LEVEL_INFO,
    				"%s = %s\n",
    				ppre_text,
    				fp_text);
    
    			i++;
    		}
    	}
    }
    
    void VL53L1_print_additional_data(
    	VL53L1_additional_data_t *pdata,
    	char                     *pprefix,
    	uint32_t                 trace_flags)
    {
    
    	/*
    	 * Prints out the Additional data structure for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"preset_mode",
    		pdata->preset_mode);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"measurement_mode",
    		pdata->measurement_mode);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"phasecal_config_timeout_us",
    		pdata->phasecal_config_timeout_us);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"mm_config_timeout_us",
    		pdata->mm_config_timeout_us);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"range_config_timeout_us",
    		pdata->range_config_timeout_us);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"inter_measurement_period_ms",
    		pdata->inter_measurement_period_ms);
    
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->dss_config__target_total_rate_mcps,
    		7,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"dss_config__target_total_rate_mcps",
    		fp_text);
    
    }
    
    
    void VL53L1_print_gain_calibration_data(
    	VL53L1_gain_calibration_data_t *pdata,
    	char                           *pprefix,
    	uint32_t                        trace_flags)
    {
    	/*
    	 * Prints out the LL Driver state data for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->standard_ranging_gain_factor,
    		11,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"standard_ranging_gain_factor",
    		fp_text);
    
    }
    
    
    void VL53L1_print_xtalk_config(
    	VL53L1_xtalk_config_t *pdata,
    	char                  *pprefix,
    	uint32_t               trace_flags)
    {
    	/*
    	 * Prints out the xtalk config data structure for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->algo__crosstalk_compensation_plane_offset_kcps,
    		9,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"algo__crosstalk_compensation_plane_offset_kcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->algo__crosstalk_compensation_x_plane_gradient_kcps,
    		11,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"algo__crosstalk_compensation_x_plane_gradient_kcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->algo__crosstalk_compensation_y_plane_gradient_kcps,
    		11,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"algo__crosstalk_compensation_y_plane_gradient_kcps",
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"global_crosstalk_compensation_enable",
    		pdata->global_crosstalk_compensation_enable);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->lite_mode_crosstalk_margin_kcps,
    		9,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"lite_mode_crosstalk_margin_kcps",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->crosstalk_range_ignore_threshold_mult,
    		5,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"crosstalk_range_ignore_threshold_mult",
    		fp_text);
    
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->crosstalk_range_ignore_threshold_rate_mcps,
    		13,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"crosstalk_range_ignore_threshold_rate_mcps",
    		fp_text);
    
    }
    
    
    
    void VL53L1_print_optical_centre(
    	VL53L1_optical_centre_t  *pdata,
    	char                     *pprefix,
    	uint32_t                  trace_flags)
    {
    
    	/* Prints out the optical centre data structure for debug
    	 */
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->x_centre,
    		4,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"x_centre",
    		fp_text);
    
    	VL53L1_signed_fixed_point_sprintf(
    		(int32_t)pdata->y_centre,
    		4,
    		VL53L1_MAX_STRING_LENGTH,
    		fp_text);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %s\n",
    		pprefix,
    		"y_centre",
    		fp_text);
    }
    
    
    void VL53L1_print_user_zone(
    	VL53L1_user_zone_t   *pdata,
    	char                 *pprefix,
    	uint32_t              trace_flags)
    {
    
    	/* Prints out the zone (ROI) data structure for debug
    	 */
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"x_centre",
    		pdata->x_centre);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"y_centre",
    		pdata->y_centre);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"width",
    		pdata->width);
    
    	trace_print(VL53L1_TRACE_LEVEL_INFO,
    		"%s%s = %u\n",
    		pprefix,
    		"height",
    		pdata->height);
    }
    
    
    void VL53L1_print_spad_rate_data(
    	VL53L1_spad_rate_data_t  *pspad_rates,
    	char                     *pprefix,
    	uint32_t                  trace_flags)
    {
    
        /**
         *  Print per SPAD rates generated by SSC
         */
    
    	uint16_t spad_no = 0;
    	uint8_t  row     = 0;
    	uint8_t  col     = 0;
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
        trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%8s,%4s,%4s, %s\n",
    		pprefix,
    		"spad_no",
    		"row",
    		"col",
    		"peak_rate_mcps");
    
        for (spad_no = 0 ; spad_no < pspad_rates->no_of_values ; spad_no++) {
    
    		/* generate row / col location from SPAD number  */
    		VL53L1_decode_row_col(
    			(uint8_t)spad_no,
    			&row,
    			&col);
    
    		/* Convert fixed point rate value to string */
    
    		VL53L1_signed_fixed_point_sprintf(
    			(int32_t)pspad_rates->rate_data[spad_no],
    			pspad_rates->fractional_bits,
    			VL53L1_MAX_STRING_LENGTH,
    			fp_text);
    
    		/* Print data */
    
    		trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    			"%s%8u,%4u,%4u, %s\n",
    			pprefix,
    			spad_no,
    			row,
    			col,
    			fp_text);
        }
    }
    
    
    void VL53L1_print_spad_rate_map(
    	VL53L1_spad_rate_data_t  *pspad_rates,
    	char                     *pprefix,
    	uint32_t                  trace_flags)
    {
    
        /**
         *  Print per SPAD rates generated by SSC as a map
         */
    
    	uint8_t  spad_no = 0;
    	uint8_t  row     = 0;
    	uint8_t  col     = 0;
    
    	char  fp_text[VL53L1_MAX_STRING_LENGTH];
    
    	/* Print column headers  */
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"%s%4s",
    		pprefix,
    		" ");
    
        for (col = 0 ;  col < VL53L1_SPAD_ARRAY_WIDTH ; col++)
    		trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    			",%8u",
    			col);
    
    	trace_print(
    		VL53L1_TRACE_LEVEL_INFO,
    		"\n");
    
        /* Print rate data  */
    
        for (row = 0 ;  row < VL53L1_SPAD_ARRAY_HEIGHT ; row++) {
    
    		trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    			"%s%4u",
    			pprefix,
    			row);
    
    		for (col = 0 ;  col < VL53L1_SPAD_ARRAY_HEIGHT ; col++) {
    
    			/* generate SPAD number from (row, col) location */
    
    			VL53L1_encode_row_col(
    				row,
    				col,
    				&spad_no);
    
    			/* Convert fixed point rate value to string */
    
    			VL53L1_signed_fixed_point_sprintf(
    				(int32_t)pspad_rates->rate_data[spad_no],
    				pspad_rates->fractional_bits,
    				VL53L1_MAX_STRING_LENGTH,
    				fp_text);
    
    			/* Print data */
    
    			trace_print(
    				VL53L1_TRACE_LEVEL_INFO,
    				",%8s",
    				fp_text);
    		}
    
    		trace_print(
    			VL53L1_TRACE_LEVEL_INFO,
    			"\n");
        }
    }
    
    
    #endif /* VL53L1_LOG_ENABLE */
    
    
    vl53l1_api_debug.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file  vl53l1_api_preset_modes.c
     *
     * @brief EwokPlus25 API Preset Modes definitions
     */
    
    #include "vl53l1_ll_def.h"
    #include "vl53l1_platform_log.h"
    #include "vl53l1_register_structs.h"
    #include "vl53l1_register_settings.h"
    #include "vl53l1_core.h"
    #include "vl53l1_api_preset_modes.h"
    #include "vl53l1_tuning_parm_defaults.h"
    
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, fmt, ##__VA_ARGS__)
    
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_init_refspadchar_config_struct(
    	VL53L1_refspadchar_config_t   *pdata)
    {
    	/*
    	 * Initializes Ref SPAD Char data structures preset mode
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Reference SPAD Char Configuration
    	 *
    	 * vcsel_period              = 0x0B   - 24 clock VCSEL period
    	 * timeout_us                = 1000   - Set 1000us phase cal timeout
    	 * target_count_rate_mcps    = 0x0A00 - 9.7 -> 20.0 Mcps
    	 * min_count_rate_limit_mcps = 0x0500 - 9.7 -> 10.0 Mcps
    	 * max_count_rate_limit_mcps = 0x1400 - 9.7 -> 40.0 Mcps
    	 */
    
    	pdata->device_test_mode =
    			VL53L1_TUNINGPARM_REFSPADCHAR_DEVICE_TEST_MODE_DEFAULT;
    	pdata->vcsel_period              =
    			VL53L1_TUNINGPARM_REFSPADCHAR_VCSEL_PERIOD_DEFAULT;
    	pdata->timeout_us                =
    			VL53L1_TUNINGPARM_REFSPADCHAR_PHASECAL_TIMEOUT_US_DEFAULT;
    	pdata->target_count_rate_mcps    =
    			VL53L1_TUNINGPARM_REFSPADCHAR_TARGET_COUNT_RATE_MCPS_DEFAULT;
    	pdata->min_count_rate_limit_mcps =
    			VL53L1_TUNINGPARM_REFSPADCHAR_MIN_COUNTRATE_LIMIT_MCPS_DEFAULT;
    	pdata->max_count_rate_limit_mcps =
    			VL53L1_TUNINGPARM_REFSPADCHAR_MAX_COUNTRATE_LIMIT_MCPS_DEFAULT;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_init_ssc_config_struct(
    	VL53L1_ssc_config_t   *pdata)
    {
    	/*
    	 * Initializes SPAD Self Check (SSC) data structure
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* SPAD Select Check Configuration */
    
    	/* 0 - store RTN count rates
    	 * 1 - store REF count rates
    	 */
    	pdata->array_select = VL53L1_DEVICESSCARRAY_RTN;
    
    	/* VCSEL period register value  0x12 (18) -> 38 VCSEL clocks */
    	pdata->vcsel_period =
    			VL53L1_TUNINGPARM_SPADMAP_VCSEL_PERIOD_DEFAULT;
    
    	/* VCSEL pulse start */
    	pdata->vcsel_start  =
    			VL53L1_TUNINGPARM_SPADMAP_VCSEL_START_DEFAULT;
    
    	/* VCSEL pulse width */
    	pdata->vcsel_width  = 0x02;
    
    	/* SSC timeout [us] */
    	pdata->timeout_us   = 36000;
    
    	/* SSC rate limit [Mcps]
    	 * - 9.7 for VCSEL ON
    	 * - 1.15 for VCSEL OFF
    	 */
    	pdata->rate_limit_mcps =
    			VL53L1_TUNINGPARM_SPADMAP_RATE_LIMIT_MCPS_DEFAULT;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    
    VL53L1_Error VL53L1_init_xtalk_config_struct(
    	VL53L1_customer_nvm_managed_t *pnvm,
    	VL53L1_xtalk_config_t   *pdata)
    {
    	/*
    	 * Initializes Xtalk Config structure
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Xtalk default configuration
    	 *
    	 * algo__crosstalk_compensation_plane_offset_kcps
    	 *  = pdev->customer.algo__crosstalk_compensation_plane_offset_kcps
    	 * algo__crosstalk_compensation_x_plane_gradient_kcps
    	 *  = pdev->customer.algo__crosstalk_compensation_x_plane_gradient_kcps
    	 * algo__crosstalk_compensation_y_plane_gradient_kcps
    	 *  = pdev->customer.algo__crosstalk_compensation_y_plane_gradient_kcps
    	 *
    	 */
    
    	/* Store xtalk data into golden copy */
    
    	pdata->algo__crosstalk_compensation_plane_offset_kcps      =
    		pnvm->algo__crosstalk_compensation_plane_offset_kcps;
    	pdata->algo__crosstalk_compensation_x_plane_gradient_kcps  =
    		pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps;
    	pdata->algo__crosstalk_compensation_y_plane_gradient_kcps  =
    		pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps;
    
    	/* Store NVM defaults for later use */
    
    	pdata->nvm_default__crosstalk_compensation_plane_offset_kcps      =
    		(uint32_t)pnvm->algo__crosstalk_compensation_plane_offset_kcps;
    	pdata->nvm_default__crosstalk_compensation_x_plane_gradient_kcps  =
    		pnvm->algo__crosstalk_compensation_x_plane_gradient_kcps;
    	pdata->nvm_default__crosstalk_compensation_y_plane_gradient_kcps  =
    		pnvm->algo__crosstalk_compensation_y_plane_gradient_kcps;
    
    	pdata->lite_mode_crosstalk_margin_kcps                     =
    			VL53L1_TUNINGPARM_LITE_XTALK_MARGIN_KCPS_DEFAULT;
    
    	/* Default for Range Ignore Threshold Mult = 2.0 */
    
    	pdata->crosstalk_range_ignore_threshold_mult =
    			VL53L1_TUNINGPARM_LITE_RIT_MULT_DEFAULT;
    
    	if ((pdata->algo__crosstalk_compensation_plane_offset_kcps == 0x00)
    		&& (pdata->algo__crosstalk_compensation_x_plane_gradient_kcps == 0x00)
    		&& (pdata->algo__crosstalk_compensation_y_plane_gradient_kcps == 0x00))
    		pdata->global_crosstalk_compensation_enable = 0x00;
    	else
    		pdata->global_crosstalk_compensation_enable = 0x01;
    
    
    	if ((status == VL53L1_ERROR_NONE) &&
    		(pdata->global_crosstalk_compensation_enable == 0x01)) {
    		pdata->crosstalk_range_ignore_threshold_rate_mcps =
    			VL53L1_calc_range_ignore_threshold(
    				pdata->algo__crosstalk_compensation_plane_offset_kcps,
    				pdata->algo__crosstalk_compensation_x_plane_gradient_kcps,
    				pdata->algo__crosstalk_compensation_y_plane_gradient_kcps,
    				pdata->crosstalk_range_ignore_threshold_mult);
    	} else {
    		pdata->crosstalk_range_ignore_threshold_rate_mcps = 0;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_init_offset_cal_config_struct(
    	VL53L1_offsetcal_config_t   *pdata)
    {
    	/*
    	 * Initializes Offset Calibration Config structure
    	 * - for use with VL53L1_run_offset_calibration()
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Preset Timeout and DSS defaults */
    
    	pdata->dss_config__target_total_rate_mcps          =
    			VL53L1_TUNINGPARM_OFFSET_CAL_DSS_RATE_MCPS_DEFAULT;
    	/* 20.0 Mcps */
    	pdata->phasecal_config_timeout_us                  =
    			VL53L1_TUNINGPARM_OFFSET_CAL_PHASECAL_TIMEOUT_US_DEFAULT;
    	/* 1000 us */
    	pdata->range_config_timeout_us                     =
    			VL53L1_TUNINGPARM_OFFSET_CAL_RANGE_TIMEOUT_US_DEFAULT;
    	/* 13000 us */
    	pdata->mm_config_timeout_us                        =
    			VL53L1_TUNINGPARM_OFFSET_CAL_MM_TIMEOUT_US_DEFAULT;
    	/* 13000 us - Added as part of Patch_AddedOffsetCalMMTuningParm_11791 */
    
    	/* Init number of averaged samples */
    
    	pdata->pre_num_of_samples                          =
    			VL53L1_TUNINGPARM_OFFSET_CAL_PRE_SAMPLES_DEFAULT;
    	pdata->mm1_num_of_samples                          =
    			VL53L1_TUNINGPARM_OFFSET_CAL_MM1_SAMPLES_DEFAULT;
    	pdata->mm2_num_of_samples                          =
    			VL53L1_TUNINGPARM_OFFSET_CAL_MM2_SAMPLES_DEFAULT;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    VL53L1_Error VL53L1_init_tuning_parm_storage_struct(
    	VL53L1_tuning_parm_storage_t   *pdata)
    {
    	/*
    	 * Initializes  Tuning Param storage structure
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Default configuration
    	 *
    	 * - Custom overwrite possible from vl53l1_set_tuning_parms()
    	 * - via tuning file input
    	 */
    
    	pdata->tp_tuning_parm_version              =
    			VL53L1_TUNINGPARM_VERSION_DEFAULT;
    	pdata->tp_tuning_parm_key_table_version    =
    			VL53L1_TUNINGPARM_KEY_TABLE_VERSION_DEFAULT;
    	pdata->tp_tuning_parm_lld_version          =
    			VL53L1_TUNINGPARM_LLD_VERSION_DEFAULT;
    	pdata->tp_init_phase_rtn_lite_long         =
    			VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_LONG_RANGE_DEFAULT;
    	pdata->tp_init_phase_rtn_lite_med          =
    			VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_MED_RANGE_DEFAULT;
    	pdata->tp_init_phase_rtn_lite_short        =
    			VL53L1_TUNINGPARM_INITIAL_PHASE_RTN_LITE_SHORT_RANGE_DEFAULT;
    	pdata->tp_init_phase_ref_lite_long         =
    			VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_LONG_RANGE_DEFAULT;
    	pdata->tp_init_phase_ref_lite_med          =
    			VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_MED_RANGE_DEFAULT;
    	pdata->tp_init_phase_ref_lite_short        =
    			VL53L1_TUNINGPARM_INITIAL_PHASE_REF_LITE_SHORT_RANGE_DEFAULT;
    	pdata->tp_consistency_lite_phase_tolerance =
    			VL53L1_TUNINGPARM_CONSISTENCY_LITE_PHASE_TOLERANCE_DEFAULT;
    	pdata->tp_phasecal_target                  =
    			VL53L1_TUNINGPARM_PHASECAL_TARGET_DEFAULT;
    	pdata->tp_cal_repeat_rate                  =
    			VL53L1_TUNINGPARM_LITE_CAL_REPEAT_RATE_DEFAULT;
    	pdata->tp_lite_min_clip                    =
    			VL53L1_TUNINGPARM_LITE_MIN_CLIP_MM_DEFAULT;
    	pdata->tp_lite_long_sigma_thresh_mm        =
    			VL53L1_TUNINGPARM_LITE_LONG_SIGMA_THRESH_MM_DEFAULT;
    	pdata->tp_lite_med_sigma_thresh_mm         =
    			VL53L1_TUNINGPARM_LITE_MED_SIGMA_THRESH_MM_DEFAULT;
    	pdata->tp_lite_short_sigma_thresh_mm       =
    			VL53L1_TUNINGPARM_LITE_SHORT_SIGMA_THRESH_MM_DEFAULT;
    	pdata->tp_lite_long_min_count_rate_rtn_mcps  =
    			VL53L1_TUNINGPARM_LITE_LONG_MIN_COUNT_RATE_RTN_MCPS_DEFAULT;
    	pdata->tp_lite_med_min_count_rate_rtn_mcps   =
    			VL53L1_TUNINGPARM_LITE_MED_MIN_COUNT_RATE_RTN_MCPS_DEFAULT;
    	pdata->tp_lite_short_min_count_rate_rtn_mcps =
    			VL53L1_TUNINGPARM_LITE_SHORT_MIN_COUNT_RATE_RTN_MCPS_DEFAULT;
    	pdata->tp_lite_sigma_est_pulse_width_ns      =
    			VL53L1_TUNINGPARM_LITE_SIGMA_EST_PULSE_WIDTH_DEFAULT;
    	pdata->tp_lite_sigma_est_amb_width_ns        =
    			VL53L1_TUNINGPARM_LITE_SIGMA_EST_AMB_WIDTH_NS_DEFAULT;
    	pdata->tp_lite_sigma_ref_mm                  =
    			VL53L1_TUNINGPARM_LITE_SIGMA_REF_MM_DEFAULT;
    	pdata->tp_lite_seed_cfg                      =
    			VL53L1_TUNINGPARM_LITE_SEED_CONFIG_DEFAULT;
    	pdata->tp_timed_seed_cfg                     =
    			VL53L1_TUNINGPARM_TIMED_SEED_CONFIG_DEFAULT;
    	pdata->tp_lite_quantifier                    =
    			VL53L1_TUNINGPARM_LITE_QUANTIFIER_DEFAULT;
    	pdata->tp_lite_first_order_select            =
    			VL53L1_TUNINGPARM_LITE_FIRST_ORDER_SELECT_DEFAULT;
    
    	/* Preset Mode Configurations */
    	/* - New parms added as part of Patch_TuningParmPresetModeAddition_11839 */
    
    	pdata->tp_dss_target_lite_mcps               =
    			VL53L1_TUNINGPARM_LITE_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT;
    	pdata->tp_dss_target_timed_mcps              =
    			VL53L1_TUNINGPARM_TIMED_DSS_CONFIG_TARGET_TOTAL_RATE_MCPS_DEFAULT;
    	pdata->tp_phasecal_timeout_lite_us           =
    			VL53L1_TUNINGPARM_LITE_PHASECAL_CONFIG_TIMEOUT_US;
    	pdata->tp_phasecal_timeout_timed_us          =
    			VL53L1_TUNINGPARM_TIMED_PHASECAL_CONFIG_TIMEOUT_US_DEFAULT;
    	pdata->tp_mm_timeout_lite_us                 =
    			VL53L1_TUNINGPARM_LITE_MM_CONFIG_TIMEOUT_US_DEFAULT;
    	pdata->tp_mm_timeout_timed_us                =
    			VL53L1_TUNINGPARM_TIMED_MM_CONFIG_TIMEOUT_US_DEFAULT;
    	pdata->tp_range_timeout_lite_us              =
    			VL53L1_TUNINGPARM_LITE_RANGE_CONFIG_TIMEOUT_US_DEFAULT;
    	pdata->tp_range_timeout_timed_us             =
    			VL53L1_TUNINGPARM_TIMED_RANGE_CONFIG_TIMEOUT_US_DEFAULT;
    
    	/* Added for Patch_LowPowerAutoMode */
    
    	pdata->tp_mm_timeout_lpa_us =
    			VL53L1_TUNINGPARM_LOWPOWERAUTO_MM_CONFIG_TIMEOUT_US_DEFAULT;
    	pdata->tp_range_timeout_lpa_us =
    			VL53L1_TUNINGPARM_LOWPOWERAUTO_RANGE_CONFIG_TIMEOUT_US_DEFAULT;
    
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_preset_mode_standard_ranging(
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	 * Initializes static and dynamic data structures fordevice preset mode
    	 * VL53L1_DEVICEPRESETMODE_STANDARD_RANGING
    	 *
    	 *  - streaming
    	 *  - single sigma delta
    	 *  - back to back
    	 *
    	 *  PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Static Configuration */
    
    	/* dss_config__target_total_rate_mcps = 20.0 Mcps 9.7 fp */
    	pstatic->dss_config__target_total_rate_mcps               = 0x0A00;
    	pstatic->debug__ctrl                                      = 0x00;
    	pstatic->test_mode__ctrl                                  = 0x00;
    	pstatic->clk_gating__ctrl                                 = 0x00;
    	pstatic->nvm_bist__ctrl                                   = 0x00;
    	pstatic->nvm_bist__num_nvm_words                          = 0x00;
    	pstatic->nvm_bist__start_address                          = 0x00;
    	pstatic->host_if__status                                  = 0x00;
    	pstatic->pad_i2c_hv__config                               = 0x00;
    	pstatic->pad_i2c_hv__extsup_config                        = 0x00;
    
    	/*
    	 *  0 - gpio__extsup_hv
    	 *  1 - gpio__vmodeint_hv
    	 */
    	pstatic->gpio_hv_pad__ctrl                                = 0x00;
    
    	/*
    	 * Set interrupt active low
    	 *
    	 *  3:0 - gpio__mux_select_hv
    	 *    4 - gpio__mux_active_high_hv
    	 */
    	pstatic->gpio_hv_mux__ctrl  = \
    			VL53L1_DEVICEINTERRUPTPOLARITY_ACTIVE_LOW | \
    			VL53L1_DEVICEGPIOMODE_OUTPUT_RANGE_AND_ERROR_INTERRUPTS;
    
    	pstatic->gpio__tio_hv_status                              = 0x02;
    	pstatic->gpio__fio_hv_status                              = 0x00;
    	pstatic->ana_config__spad_sel_pswidth                     = 0x02;
    	pstatic->ana_config__vcsel_pulse_width_offset             = 0x08;
    	pstatic->ana_config__fast_osc__config_ctrl                = 0x00;
    
    	pstatic->sigma_estimator__effective_pulse_width_ns        =
    			ptuning_parms->tp_lite_sigma_est_pulse_width_ns;
    	pstatic->sigma_estimator__effective_ambient_width_ns      =
    			ptuning_parms->tp_lite_sigma_est_amb_width_ns;
    	pstatic->sigma_estimator__sigma_ref_mm                    =
    			ptuning_parms->tp_lite_sigma_ref_mm;
    	/* Minimum allowable value of 1 - 0 disables the feature */
    	pstatic->algo__crosstalk_compensation_valid_height_mm     = 0x01;
    	pstatic->spare_host_config__static_config_spare_0         = 0x00;
    	pstatic->spare_host_config__static_config_spare_1         = 0x00;
    
    	pstatic->algo__range_ignore_threshold_mcps                = 0x0000;
    
    	/* set RIT distance to 20 mm */
    	pstatic->algo__range_ignore_valid_height_mm               = 0xff;
    	pstatic->algo__range_min_clip                             =
    			ptuning_parms->tp_lite_min_clip;
    	/*
    	 * Phase consistency check limit - format 1.3 fp
    	 * 0x02 -> 0.25
    	 * 0x08 -> 1.00
    	 */
    	pstatic->algo__consistency_check__tolerance               =
    			ptuning_parms->tp_consistency_lite_phase_tolerance;
    	pstatic->spare_host_config__static_config_spare_2         = 0x00;
    	pstatic->sd_config__reset_stages_msb                      = 0x00;
    	pstatic->sd_config__reset_stages_lsb                      = 0x00;
    
    	pgeneral->gph_config__stream_count_update_value           = 0x00;
    	pgeneral->global_config__stream_divider                   = 0x00;
    	pgeneral->system__interrupt_config_gpio =
    			VL53L1_INTERRUPT_CONFIG_NEW_SAMPLE_READY;
    	pgeneral->cal_config__vcsel_start                         = 0x0B;
    
    	/*
    	 * Set VHV / Phase Cal repeat rate to 1 every
    	 * 60 * 60 ranges (once every minute @ 60Hz)
    	 * 0 - disables
    	 * 12-bit value -> 4095 max
    	 */
    	pgeneral->cal_config__repeat_rate                         =
    			ptuning_parms->tp_cal_repeat_rate;
    	pgeneral->global_config__vcsel_width                      = 0x02;
    	/* 13 macro periods gives a timeout of 1ms */
    	pgeneral->phasecal_config__timeout_macrop                 = 0x0D;
    	/* Phase cal target phase 2.0625 - 4.4 fp -> 0x21*/
    	pgeneral->phasecal_config__target                         =
    			ptuning_parms->tp_phasecal_target;
    	pgeneral->phasecal_config__override                       = 0x00;
    	pgeneral->dss_config__roi_mode_control =
    			VL53L1_DEVICEDSSMODE__TARGET_RATE;
    	/* format for threshold high and low is 9.7 fp */
    	pgeneral->system__thresh_rate_high                        = 0x0000;
    	pgeneral->system__thresh_rate_low                         = 0x0000;
    	/* The format for manual effective spads is 8.8 -> 0x8C00 = 140.00 */
    	pgeneral->dss_config__manual_effective_spads_select       = 0x8C00;
    	pgeneral->dss_config__manual_block_select                 = 0x00;
    
    	/*
    	 * Aperture attenuation value - format 0.8
    	 *
    	 * Nominal:  5x   -> 0.200000 * 256 = 51 = 0x33
    	 * Measured: 4.6x -> 0.217391 * 256 = 56 = 0x38
    	 */
    	pgeneral->dss_config__aperture_attenuation                = 0x38;
    	pgeneral->dss_config__max_spads_limit                     = 0xFF;
    	pgeneral->dss_config__min_spads_limit                     = 0x01;
    
    	/* Timing Configuration */
    
    	/* Default timing of 2ms */
    	ptiming->mm_config__timeout_macrop_a_hi                   = 0x00;
    	ptiming->mm_config__timeout_macrop_a_lo                   = 0x1a;
    	ptiming->mm_config__timeout_macrop_b_hi                   = 0x00;
    	ptiming->mm_config__timeout_macrop_b_lo                   = 0x20;
    	/* Setup for 30ms default */
    	ptiming->range_config__timeout_macrop_a_hi                = 0x01;
    	ptiming->range_config__timeout_macrop_a_lo                = 0xCC;
    	/* register value 11 gives a 24 VCSEL period */
    	ptiming->range_config__vcsel_period_a                     = 0x0B;
    	/* Setup for 30ms default */
    	ptiming->range_config__timeout_macrop_b_hi                = 0x01;
    	ptiming->range_config__timeout_macrop_b_lo                = 0xF5;
    	/* register value  09 gives a 20 VCSEL period */
    	ptiming->range_config__vcsel_period_b                     = 0x09;
    	/*
    	 * Sigma thresh register - format 14.2
    	 *
    	 * 0x003C -> 15.0 mm
    	 * 0x0050 -> 20.0 mm
    	 */
    	ptiming->range_config__sigma_thresh                       =
    			ptuning_parms->tp_lite_med_sigma_thresh_mm;
    	/*
    	 *  Rate Limit - format 9.7fp
    	 *  0x0020 -> 0.250 Mcps
    	 *  0x0080 -> 1.000 Mcps
    	 */
    	ptiming->range_config__min_count_rate_rtn_limit_mcps      =
    			ptuning_parms->tp_lite_med_min_count_rate_rtn_mcps;
    
    	/* Phase limit register formats = 5.3
    	 * low   = 0x08 ->  1.0
    	 * high  = 0x78 -> 15.0 -> 3.0m
    	 */
    	ptiming->range_config__valid_phase_low                    = 0x08;
    	ptiming->range_config__valid_phase_high                   = 0x78;
    	ptiming->system__intermeasurement_period                  = 0x00000000;
    	ptiming->system__fractional_enable                        = 0x00;
    
    	/* Dynamic Configuration */
    
    	pdynamic->system__grouped_parameter_hold_0                 = 0x01;
    
    	pdynamic->system__thresh_high                              = 0x0000;
    	pdynamic->system__thresh_low                               = 0x0000;
    	pdynamic->system__enable_xtalk_per_quadrant                = 0x00;
    	pdynamic->system__seed_config =
    			ptuning_parms->tp_lite_seed_cfg;
    
    	/* Timing A */
    	pdynamic->sd_config__woi_sd0                               = 0x0B;
    	/* Timing B */
    	pdynamic->sd_config__woi_sd1                               = 0x09;
    
    	pdynamic->sd_config__initial_phase_sd0                     =
    			ptuning_parms->tp_init_phase_rtn_lite_med;
    	pdynamic->sd_config__initial_phase_sd1                     =
    			ptuning_parms->tp_init_phase_ref_lite_med;;
    
    	pdynamic->system__grouped_parameter_hold_1                 = 0x01;
    
    	/*
    	 *  Quantifier settings
    	 *
    	 *  sd_config__first_order_select
    	 *     bit 0 - return sigma delta
    	 *     bit 1 - reference sigma delta
    	 *
    	 *  sd_config__first_order_select = 0x03 (1st order)
    	 *
    	 *      sd_config__quantifier options
    	 *        0
    	 *        1 ->   64
    	 *        2 ->  128
    	 *        3 ->  256
    	 *
    	 *  sd_config__first_order_select = 0x00 (2nd order)
    	 *
    	 *      sd_config__quantifier options
    	 *        0
    	 *        1  ->  256
    	 *        2  -> 1024
    	 *        3  -> 4095
    	 *
    	 *  Setting below 2nd order, Quantifier = 1024
    	 */
    
    	pdynamic->sd_config__first_order_select =
    			ptuning_parms->tp_lite_first_order_select;
    	pdynamic->sd_config__quantifier         =
    			ptuning_parms->tp_lite_quantifier;
    
    	/* Below defaults will be overwritten by zone_cfg
    	 * Spad no = 199 (0xC7)
    	 * Spad no =  63 (0x3F)
    	 */
    	pdynamic->roi_config__user_roi_centre_spad              = 0xC7;
    	/* 16x16 ROI */
    	pdynamic->roi_config__user_roi_requested_global_xy_size = 0xFF;
    
    
    	pdynamic->system__sequence_config                          = \
    			VL53L1_SEQUENCE_VHV_EN | \
    			VL53L1_SEQUENCE_PHASECAL_EN | \
    			VL53L1_SEQUENCE_DSS1_EN | \
    			VL53L1_SEQUENCE_DSS2_EN | \
    			VL53L1_SEQUENCE_MM2_EN | \
    			VL53L1_SEQUENCE_RANGE_EN;
    
    	pdynamic->system__grouped_parameter_hold                   = 0x02;
    
    	/* System control */
    
    
    	psystem->system__stream_count_ctrl                         = 0x00;
    	psystem->firmware__enable                                  = 0x01;
    	psystem->system__interrupt_clear                           = \
    			VL53L1_CLEAR_RANGE_INT;
    
    	psystem->system__mode_start                                = \
    			VL53L1_DEVICESCHEDULERMODE_STREAMING | \
    			VL53L1_DEVICEREADOUTMODE_SINGLE_SD | \
    			VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_preset_mode_standard_ranging_short_range(
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	 * Initializes static and dynamic data structures for
    	 * device preset mode
    	 *
    	 * VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_SHORT_RANGE
    	 * (up to 1.4 metres)
    	 *
    	 * PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration followed by
    	 * overrides for the  short range configuration
    	 */
    
    	status = VL53L1_preset_mode_standard_ranging(
    		pstatic,
    		pgeneral,
    		ptiming,
    		pdynamic,
    		psystem,
    		ptuning_parms);
    
    	/* now override standard ranging specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		/* Timing Configuration
    		 *
    		 * vcsel_period_a    = 7 -> 16 period
    		 * vcsel_period_b    = 5 -> 12 period
    		 * sigma_thresh                  = 0x003C -> 14.2fp -> 15.0 mm
    		 * min_count_rate_rtn_limit_mcps = 0x0080 ->  9.7fp ->  1.0 Mcps
    		 * valid_phase_low               = 0x08 -> 5.3fp -> 1.0
    		 * valid_phase_high              = 0x38 -> 5.3fp -> 7.0 -> 1.4m
    		 */
    
    		ptiming->range_config__vcsel_period_a                = 0x07;
    		ptiming->range_config__vcsel_period_b                = 0x05;
    		ptiming->range_config__sigma_thresh                  =
    				ptuning_parms->tp_lite_short_sigma_thresh_mm;
    		ptiming->range_config__min_count_rate_rtn_limit_mcps =
    				ptuning_parms->tp_lite_short_min_count_rate_rtn_mcps;
    		ptiming->range_config__valid_phase_low               = 0x08;
    		ptiming->range_config__valid_phase_high              = 0x38;
    
    		/* Dynamic Configuration
    		 * SD0 -> Timing A
    		 * SD1 -> Timing B
    		 */
    
    		pdynamic->sd_config__woi_sd0                         = 0x07;
    		pdynamic->sd_config__woi_sd1                         = 0x05;
    		pdynamic->sd_config__initial_phase_sd0               =
    				ptuning_parms->tp_init_phase_rtn_lite_short;
    		pdynamic->sd_config__initial_phase_sd1               =
    				ptuning_parms->tp_init_phase_ref_lite_short;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_preset_mode_standard_ranging_long_range(
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	 * Initializes static and dynamic data structures for
    	 * device preset mode
    	 *
    	 * VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_LONG_RANGE
    	 * (up to 4.8 metres)
    	 *
    	 *  PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration with
    	 * overrides for long range configuration
    	 */
    
    	status = VL53L1_preset_mode_standard_ranging(
    		pstatic,
    		pgeneral,
    		ptiming,
    		pdynamic,
    		psystem,
    		ptuning_parms);
    
    	/* now override standard ranging specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		/* Timing Configuration
    		 *
    		 * vcsel_period_a    = 15 -> 32 period
    		 * vcsel_period_b    = 13 -> 28 period
    		 * sigma_thresh                  = 0x003C -> 14.2fp -> 15.0 mm
    		 * min_count_rate_rtn_limit_mcps = 0x0080 ->  9.7fp ->  1.0 Mcps
    		 * valid_phase_low               = 0x08 -> 5.3fp ->  1.0
    		 * valid_phase_high              = 0xB8 -> 5.3fp -> 23.0 -> 4.6m
    		 */
    
    		ptiming->range_config__vcsel_period_a                = 0x0F;
    		ptiming->range_config__vcsel_period_b                = 0x0D;
    		ptiming->range_config__sigma_thresh                  =
    				ptuning_parms->tp_lite_long_sigma_thresh_mm;
    		ptiming->range_config__min_count_rate_rtn_limit_mcps =
    				ptuning_parms->tp_lite_long_min_count_rate_rtn_mcps;
    		ptiming->range_config__valid_phase_low               = 0x08;
    		ptiming->range_config__valid_phase_high              = 0xB8;
    
    		/* Dynamic Configuration
    		 * SD0 -> Timing A
    		 * SD1 -> Timing B
    		 */
    
    		pdynamic->sd_config__woi_sd0                         = 0x0F;
    		pdynamic->sd_config__woi_sd1                         = 0x0D;
    		pdynamic->sd_config__initial_phase_sd0               =
    				ptuning_parms->tp_init_phase_rtn_lite_long;
    		pdynamic->sd_config__initial_phase_sd1               =
    				ptuning_parms->tp_init_phase_ref_lite_long;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_preset_mode_standard_ranging_mm1_cal(
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	 * Initializes static and dynamic data structures for
    	 * device preset mode
    	 *
    	 * VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM1_CAL
    	 *
    	 * PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration with
    	 * overrides for long range configuration
    	 */
    
    	status = VL53L1_preset_mode_standard_ranging(
    		pstatic,
    		pgeneral,
    		ptiming,
    		pdynamic,
    		psystem,
    		ptuning_parms);
    
    	/* now override standard ranging specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		pgeneral->dss_config__roi_mode_control =
    				VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS;
    
    		pdynamic->system__sequence_config  = \
    				VL53L1_SEQUENCE_VHV_EN | \
    				VL53L1_SEQUENCE_PHASECAL_EN | \
    				VL53L1_SEQUENCE_DSS1_EN | \
    				VL53L1_SEQUENCE_DSS2_EN | \
    				VL53L1_SEQUENCE_MM1_EN;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_preset_mode_standard_ranging_mm2_cal(
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	 * Initializes static and dynamic data structures for
    	 * device preset mode
    	 *
    	 * VL53L1_DEVICEPRESETMODE_STANDARD_RANGING_MM2_CAL
    	 *
    	 * PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration with
    	 * overrides for long range configuration
    	 */
    
    	status = VL53L1_preset_mode_standard_ranging(
    		pstatic,
    		pgeneral,
    		ptiming,
    		pdynamic,
    		psystem,
    		ptuning_parms);
    
    	/* now override standard ranging specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		pgeneral->dss_config__roi_mode_control =
    				VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS;
    
    		pdynamic->system__sequence_config  = \
    				VL53L1_SEQUENCE_VHV_EN | \
    				VL53L1_SEQUENCE_PHASECAL_EN | \
    				VL53L1_SEQUENCE_DSS1_EN | \
    				VL53L1_SEQUENCE_DSS2_EN | \
    				VL53L1_SEQUENCE_MM2_EN;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    
    VL53L1_Error VL53L1_preset_mode_timed_ranging(
    
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	* Initializes static and dynamic data structures for
    	* device preset mode
    	*
    	* VL53L1_DEVICEPRESETMODE_TIMED_RANGING
    	*
    	*  - pseudo-solo
    	*  - single sigma delta
    	*  - timed
    	*
    	*  PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	*/
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration */
    
    	status = VL53L1_preset_mode_standard_ranging(
    					pstatic,
    					pgeneral,
    					ptiming,
    					pdynamic,
    					psystem,
    					ptuning_parms);
    
    	/* now override standard ranging specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		/* Dynamic Configuration */
    
    		/* Disable GPH  */
    		pdynamic->system__grouped_parameter_hold = 0x00;
    
    		/* Re-Configure timing budget default for 13ms */
    		ptiming->range_config__timeout_macrop_a_hi                = 0x00;
    		ptiming->range_config__timeout_macrop_a_lo                = 0xB1;
    		/* Setup for 13ms default */
    		ptiming->range_config__timeout_macrop_b_hi                = 0x00;
    		ptiming->range_config__timeout_macrop_b_lo                = 0xD4;
    
    		/* Timing Configuration */
    
    		ptiming->system__intermeasurement_period = 0x00000600;
    		pdynamic->system__seed_config =
    				ptuning_parms->tp_timed_seed_cfg;
    
    		/* System control */
    
    		/* Configure Timed/Psuedo-solo mode */
    		psystem->system__mode_start =
    				VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | \
    				VL53L1_DEVICEREADOUTMODE_SINGLE_SD     | \
    				VL53L1_DEVICEMEASUREMENTMODE_TIMED;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_preset_mode_timed_ranging_short_range(
    
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	* Initializes static and dynamic data structures for
    	* device preset mode
    	*
    	* VL53L1_DEVICEPRESETMODE_TIMED_RANGING_SHORT_RANGE
    	*
    	*  - pseudo-solo
    	*  - single sigma delta
    	*  - timed
    	*
    	*  PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	*/
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration */
    
    	status = VL53L1_preset_mode_standard_ranging_short_range(
    					pstatic,
    					pgeneral,
    					ptiming,
    					pdynamic,
    					psystem,
    					ptuning_parms);
    
    	/* now override standard ranging specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		/* Dynamic Configuration */
    
    		/* Disable GPH  */
    		pdynamic->system__grouped_parameter_hold = 0x00;
    
    
    		/* Timing Configuration */
    
    		/* Re-Configure timing budget default for 13ms */
    		ptiming->range_config__timeout_macrop_a_hi                = 0x01;
    		ptiming->range_config__timeout_macrop_a_lo                = 0x84;
    		/* Setup for 13ms default */
    		ptiming->range_config__timeout_macrop_b_hi                = 0x01;
    		ptiming->range_config__timeout_macrop_b_lo                = 0xB1;
    
    		ptiming->system__intermeasurement_period = 0x00000600;
    		pdynamic->system__seed_config =
    				ptuning_parms->tp_timed_seed_cfg;
    
    		/* System control */
    
    		/* Configure Timed/Psuedo-solo mode */
    		psystem->system__mode_start =
    				VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | \
    				VL53L1_DEVICEREADOUTMODE_SINGLE_SD     | \
    				VL53L1_DEVICEMEASUREMENTMODE_TIMED;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_preset_mode_timed_ranging_long_range(
    
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	* Initializes static and dynamic data structures for
    	* device preset mode
    	*
    	* VL53L1_DEVICEPRESETMODE_TIMED_RANGING_LONG_RANGE
    	*
    	*  - pseudo-solo
    	*  - single sigma delta
    	*  - timed
    	*
    	*  PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	*/
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration */
    
    	status = VL53L1_preset_mode_standard_ranging_long_range(
    					pstatic,
    					pgeneral,
    					ptiming,
    					pdynamic,
    					psystem,
    					ptuning_parms);
    
    	/* now override standard ranging specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		/* Dynamic Configuration */
    
    		/* Disable GPH  */
    		pdynamic->system__grouped_parameter_hold = 0x00;
    
    
    		/* Timing Configuration */
    
    		/* Re-Configure timing budget default for 13ms */
    		ptiming->range_config__timeout_macrop_a_hi                = 0x00;
    		ptiming->range_config__timeout_macrop_a_lo                = 0x97;
    		/* Setup for 13ms default */
    		ptiming->range_config__timeout_macrop_b_hi                = 0x00;
    		ptiming->range_config__timeout_macrop_b_lo                = 0xB1;
    
    		ptiming->system__intermeasurement_period = 0x00000600;
    		pdynamic->system__seed_config =
    				ptuning_parms->tp_timed_seed_cfg;
    
    		/* System control */
    
    		/* Configure Timed/Psuedo-solo mode */
    		psystem->system__mode_start =
    				VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | \
    				VL53L1_DEVICEREADOUTMODE_SINGLE_SD     | \
    				VL53L1_DEVICEMEASUREMENTMODE_TIMED;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    /* Start Patch_LowPowerAutoMode */
    VL53L1_Error VL53L1_preset_mode_low_power_auto_ranging(
    
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms,
    	VL53L1_low_power_auto_data_t *plpadata)
    {
    	/*
    	* Initializes static and dynamic data structures for
    	* device preset mode
    	*
    	* VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_MEDIUM_RANGE
    	*
    	*  - pseudo-solo
    	*  - single sigma delta
    	*  - timed
    	*  - special low power auto mode for Presence application
    	*
    	*  PLEASE NOTE THE SETTINGS BELOW ARE PROVISIONAL AND WILL CHANGE!
    	*/
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration */
    
    	status = VL53L1_preset_mode_timed_ranging(
    					pstatic,
    					pgeneral,
    					ptiming,
    					pdynamic,
    					psystem,
    					ptuning_parms);
    
    	/* now setup the low power auto mode */
    
    	if (status == VL53L1_ERROR_NONE) {
    		status = VL53L1_config_low_power_auto_mode(
    				pgeneral,
    				pdynamic,
    				plpadata
    				);
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_preset_mode_low_power_auto_short_ranging(
    
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms,
    	VL53L1_low_power_auto_data_t *plpadata)
    {
    	/*
    	* Initializes static and dynamic data structures for
    	* device preset mode
    	*
    	* VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_SHORT_RANGE
    	*
    	*  - pseudo-solo
    	*  - single sigma delta
    	*  - timed
    	*  - special low power auto mode for Presence application
    	*
    	*  PLEASE NOTE THE SETTINGS BELOW ARE PROVISIONAL AND WILL CHANGE!
    	*/
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration */
    
    	status = VL53L1_preset_mode_timed_ranging_short_range(
    					pstatic,
    					pgeneral,
    					ptiming,
    					pdynamic,
    					psystem,
    					ptuning_parms);
    
    	/* now setup the low power auto mode */
    
    	if (status == VL53L1_ERROR_NONE) {
    		status = VL53L1_config_low_power_auto_mode(
    				pgeneral,
    				pdynamic,
    				plpadata
    				);
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_preset_mode_low_power_auto_long_ranging(
    
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms,
    	VL53L1_low_power_auto_data_t *plpadata)
    {
    	/*
    	* Initializes static and dynamic data structures for
    	* device preset mode
    	*
    	* VL53L1_DEVICEPRESETMODE_LOWPOWERAUTO_LONG_RANGE
    	*
    	*  - pseudo-solo
    	*  - single sigma delta
    	*  - timed
    	*  - special low power auto mode for Presence application
    	*
    	*  PLEASE NOTE THE SETTINGS BELOW ARE PROVISIONAL AND WILL CHANGE!
    	*/
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration */
    
    	status = VL53L1_preset_mode_timed_ranging_long_range(
    					pstatic,
    					pgeneral,
    					ptiming,
    					pdynamic,
    					psystem,
    					ptuning_parms);
    
    	/* now setup the low power auto mode */
    
    	if (status == VL53L1_ERROR_NONE) {
    		status = VL53L1_config_low_power_auto_mode(
    				pgeneral,
    				pdynamic,
    				plpadata
    				);
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    /* End Patch_LowPowerAutoMode */
    
    VL53L1_Error VL53L1_preset_mode_singleshot_ranging(
    
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/*
    	* Initializes static and dynamic data structures for device preset mode
    	* VL53L1_DEVICEPRESETMODE_TIMED_RANGING
    	*
    	*  - pseudo-solo
    	*  - single sigma delta
    	*  - timed
    	*
    	*  PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	*/
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration */
    
    	status = VL53L1_preset_mode_standard_ranging(
    		pstatic,
    		pgeneral,
    		ptiming,
    		pdynamic,
    		psystem,
    		ptuning_parms);
    
    	/* now override standard ranging specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		/* Dynamic Configuration */
    
    		/* Disable GPH  */
    		pdynamic->system__grouped_parameter_hold = 0x00;
    
    		/* Timing Configuration */
    
    		/* Re-Configure timing budget default for 13ms */
    		ptiming->range_config__timeout_macrop_a_hi                = 0x00;
    		ptiming->range_config__timeout_macrop_a_lo                = 0xB1;
    		/* Setup for 13ms default */
    		ptiming->range_config__timeout_macrop_b_hi                = 0x00;
    		ptiming->range_config__timeout_macrop_b_lo                = 0xD4;
    
    		pdynamic->system__seed_config =
    				ptuning_parms->tp_timed_seed_cfg;
    
    		/* System control */
    
    		/* Configure Timed/Psuedo-solo mode */
    		psystem->system__mode_start = \
    				VL53L1_DEVICESCHEDULERMODE_PSEUDO_SOLO | \
    				VL53L1_DEVICEREADOUTMODE_SINGLE_SD     | \
    				VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_preset_mode_olt(
    	VL53L1_static_config_t    *pstatic,
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_timing_config_t    *ptiming,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_system_control_t   *psystem,
    	VL53L1_tuning_parm_storage_t *ptuning_parms)
    {
    	/**
    	 * Initializes static and dynamic data structures for device preset mode
    	 * VL53L1_DEVICEPRESETMODE_OLT
    	 *
    	 *  PLEASE NOTE THE SETTINGS BELOW AT PROVISIONAL AND WILL CHANGE!
    	 */
    
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* Call standard ranging configuration */
    
    	status = VL53L1_preset_mode_standard_ranging(
    					pstatic,
    					pgeneral,
    					ptiming,
    					pdynamic,
    					psystem,
    					ptuning_parms);
    
    	/* now override OLT specific registers */
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		/* Disables requirement for host handshake */
    		psystem->system__stream_count_ctrl  = 0x01;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    vl53l1_api_preset_modes.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file   vl53l1_api_strings.c
     * @brief  VL53L1 API functions for decoding error codes to a text string
     */
    
    #include "vl53l1_api_core.h"
    #include "vl53l1_api_strings.h"
    #include "vl53l1_error_codes.h"
    #include "vl53l1_error_strings.h"
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, status, fmt, \
    			##__VA_ARGS__)
    
    
    VL53L1_Error VL53L1_get_range_status_string(
    	uint8_t   RangeStatus,
    	char    *pRangeStatusString)
    {
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    #ifdef VL53L1_USE_EMPTY_STRING
    	VL53L1_COPYSTRING(pRangeStatusString, "");
    #else
    	switch (RangeStatus) {
    	case 0:
    		VL53L1_COPYSTRING(pRangeStatusString,
    			VL53L1_STRING_RANGESTATUS_RANGEVALID);
    	break;
    	case 1:
    		VL53L1_COPYSTRING(pRangeStatusString,
    			VL53L1_STRING_RANGESTATUS_SIGMA);
    	break;
    	case 2:
    		VL53L1_COPYSTRING(pRangeStatusString,
    			VL53L1_STRING_RANGESTATUS_SIGNAL);
    	break;
    	case 3:
    		VL53L1_COPYSTRING(pRangeStatusString,
    			VL53L1_STRING_RANGESTATUS_MINRANGE);
    	break;
    	case 4:
    		VL53L1_COPYSTRING(pRangeStatusString,
    			VL53L1_STRING_RANGESTATUS_PHASE);
    	break;
    	case 5:
    		VL53L1_COPYSTRING(pRangeStatusString,
    			VL53L1_STRING_RANGESTATUS_HW);
    	break;
    
    	default: /**/
    		VL53L1_COPYSTRING(pRangeStatusString,
    			VL53L1_STRING_RANGESTATUS_NONE);
    	}
    #endif
    
    	LOG_FUNCTION_END(status);
    	return status;
    }
    
    
    VL53L1_Error VL53L1_get_pal_state_string(
    	VL53L1_State PalStateCode,
    	char *pPalStateString)
    {
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    #ifdef VL53L1_USE_EMPTY_STRING
    	VL53L1_COPYSTRING(pPalStateString, "");
    #else
    	switch (PalStateCode) {
    	case VL53L1_STATE_POWERDOWN:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_POWERDOWN);
    	break;
    	case VL53L1_STATE_WAIT_STATICINIT:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_WAIT_STATICINIT);
    	break;
    	case VL53L1_STATE_STANDBY:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_STANDBY);
    	break;
    	case VL53L1_STATE_IDLE:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_IDLE);
    	break;
    	case VL53L1_STATE_RUNNING:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_RUNNING);
    	break;
    	case VL53L1_STATE_RESET:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_RESET);
    	break;
    	case VL53L1_STATE_UNKNOWN:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_UNKNOWN);
    	break;
    	case VL53L1_STATE_ERROR:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_ERROR);
    	break;
    
    	default:
    		VL53L1_COPYSTRING(pPalStateString,
    			VL53L1_STRING_STATE_UNKNOWN);
    	}
    #endif
    
    	LOG_FUNCTION_END(status);
    	return status;
    }
    
    VL53L1_Error VL53L1_get_sequence_steps_info(
    		VL53L1_SequenceStepId SequenceStepId,
    		char *pSequenceStepsString)
    {
    	VL53L1_Error Status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    #ifdef VL53L1_USE_EMPTY_STRING
    	VL53L1_COPYSTRING(pSequenceStepsString, "");
    #else
    	switch (SequenceStepId) {
    	case VL53L1_SEQUENCESTEP_VHV:
    		VL53L1_COPYSTRING(pSequenceStepsString,
    				VL53L1_STRING_SEQUENCESTEP_VHV);
    	break;
    	case VL53L1_SEQUENCESTEP_PHASECAL:
    		VL53L1_COPYSTRING(pSequenceStepsString,
    				VL53L1_STRING_SEQUENCESTEP_PHASECAL);
    	break;
    	case VL53L1_SEQUENCESTEP_REFPHASE:
    		VL53L1_COPYSTRING(pSequenceStepsString,
    				VL53L1_STRING_SEQUENCESTEP_DSS1);
    	break;
    	case VL53L1_SEQUENCESTEP_DSS1:
    		VL53L1_COPYSTRING(pSequenceStepsString,
    				VL53L1_STRING_SEQUENCESTEP_DSS1);
    	break;
    	case VL53L1_SEQUENCESTEP_DSS2:
    		VL53L1_COPYSTRING(pSequenceStepsString,
    				VL53L1_STRING_SEQUENCESTEP_DSS2);
    	break;
    	case VL53L1_SEQUENCESTEP_MM1:
    		VL53L1_COPYSTRING(pSequenceStepsString,
    				VL53L1_STRING_SEQUENCESTEP_MM1);
    	break;
    	case VL53L1_SEQUENCESTEP_MM2:
    		VL53L1_COPYSTRING(pSequenceStepsString,
    				VL53L1_STRING_SEQUENCESTEP_MM2);
    	break;
    	case VL53L1_SEQUENCESTEP_RANGE:
    		VL53L1_COPYSTRING(pSequenceStepsString,
    				VL53L1_STRING_SEQUENCESTEP_RANGE);
    	break;
    	default:
    		Status = VL53L1_ERROR_INVALID_PARAMS;
    	}
    #endif
    
    	LOG_FUNCTION_END(Status);
    
    	return Status;
    }
    
    VL53L1_Error VL53L1_get_limit_check_info(uint16_t LimitCheckId,
    	char *pLimitCheckString)
    {
    	VL53L1_Error Status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    #ifdef VL53L1_USE_EMPTY_STRING
    	VL53L1_COPYSTRING(pLimitCheckString, "");
    #else
    	switch (LimitCheckId) {
    	case VL53L1_CHECKENABLE_SIGMA_FINAL_RANGE:
    		VL53L1_COPYSTRING(pLimitCheckString,
    			VL53L1_STRING_CHECKENABLE_SIGMA_FINAL_RANGE);
    	break;
    	case VL53L1_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE:
    		VL53L1_COPYSTRING(pLimitCheckString,
    			VL53L1_STRING_CHECKENABLE_SIGNAL_RATE_FINAL_RANGE);
    	break;
    	default:
    		VL53L1_COPYSTRING(pLimitCheckString,
    			VL53L1_STRING_UNKNOW_ERROR_CODE);
    	}
    #endif
    
    	LOG_FUNCTION_END(Status);
    	return Status;
    }
    
    
    vl53l1_api_strings.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file  vl53l1_core.c
     *
     * @brief EwokPlus25 core function definition
     */
    
    #include "vl53l1_ll_def.h"
    #include "vl53l1_ll_device.h"
    #include "vl53l1_platform.h"
    #include "vl53l1_register_map.h"
    #include "vl53l1_register_funcs.h"
    #include "vl53l1_register_settings.h"
    #include "vl53l1_api_preset_modes.h"
    #include "vl53l1_core.h"
    #include "vl53l1_tuning_parm_defaults.h"
    
    #ifdef VL53L1_LOGGING
    #include "vl53l1_api_debug.h"
    #include "vl53l1_debug.h"
    #include "vl53l1_register_debug.h"
    #endif
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \
    		status, fmt, ##__VA_ARGS__)
    
    #define trace_print(level, ...) \
    	_LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \
    	level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__)
    
    
    void  VL53L1_init_version(
    	VL53L1_DEV        Dev)
    {
    	/**
    	 * Initialise version structure
    	 */
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	pdev->version.ll_major    = VL53L1_LL_API_IMPLEMENTATION_VER_MAJOR;
    	pdev->version.ll_minor    = VL53L1_LL_API_IMPLEMENTATION_VER_MINOR;
    	pdev->version.ll_build    = VL53L1_LL_API_IMPLEMENTATION_VER_SUB;
    	pdev->version.ll_revision = VL53L1_LL_API_IMPLEMENTATION_VER_REVISION;
    }
    
    
    void  VL53L1_init_ll_driver_state(
    	VL53L1_DEV         Dev,
    	VL53L1_DeviceState device_state)
    {
    	/**
    	 * Initialise LL Driver state variables
    	 */
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    	VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state);
    
    	pstate->cfg_device_state  = device_state;
    	pstate->cfg_stream_count  = 0;
    	pstate->cfg_gph_id        = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK;
    	pstate->cfg_timing_status = 0;
    
    	pstate->rd_device_state   = device_state;
    	pstate->rd_stream_count   = 0;
    	pstate->rd_gph_id         = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK;
    	pstate->rd_timing_status  = 0;
    
    }
    
    
    VL53L1_Error  VL53L1_update_ll_driver_rd_state(
    	VL53L1_DEV         Dev)
    {
    	/**
    	 * State machine for read device state
    	 *
    	 * VL53L1_DEVICESTATE_SW_STANDBY
    	 * VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC
    	 * VL53L1_DEVICESTATE_RANGING_GATHER_DATA
    	 * VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA
    	 */
    
    	VL53L1_Error        status  = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    	VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state);
    
    	/* if top bits of mode start reset are zero then in standby state */
    
    	LOG_FUNCTION_START("");
    
    #ifdef VL53L1_LOGGING
    	VL53L1_print_ll_driver_state(pstate);
    #endif
    
    	if ((pdev->sys_ctrl.system__mode_start &
    		VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) {
    
    		pstate->rd_device_state  = VL53L1_DEVICESTATE_SW_STANDBY;
    		pstate->rd_stream_count  = 0;
    		pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK;
    		pstate->rd_timing_status = 0;
    
    	} else {
    
    		/*
    		 * implement read stream count
    		 */
    
    		if (pstate->rd_stream_count == 0xFF) {
    			pstate->rd_stream_count = 0x80;
    		} else {
    			pstate->rd_stream_count++;
    		}
    
    
    		/*
    		 * Toggle grouped parameter hold ID
    		 */
    
    		pstate->rd_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK;
    
    		/* Ok now ranging  */
    
    		switch (pstate->rd_device_state) {
    
    		case VL53L1_DEVICESTATE_SW_STANDBY:
    
    			if ((pdev->dyn_cfg.system__grouped_parameter_hold &
    				VL53L1_GROUPEDPARAMETERHOLD_ID_MASK) > 0) {
    				pstate->rd_device_state =
    					VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC;
    			} else {
    				pstate->rd_device_state =
    					VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA;
    			}
    
    			pstate->rd_stream_count  = 0;
    			pstate->rd_timing_status = 0;
    
    		break;
    
    		case VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC:
    
    			pstate->rd_stream_count = 0;
    			pstate->rd_device_state =
    				VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA;
    
    		break;
    
    		case VL53L1_DEVICESTATE_RANGING_GATHER_DATA:
    
    			pstate->rd_device_state =
    				VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA;
    
    		break;
    
    		case VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA:
    
    			pstate->rd_timing_status ^= 0x01;
    
    			pstate->rd_device_state =
    				VL53L1_DEVICESTATE_RANGING_OUTPUT_DATA;
    
    		break;
    
    		default:
    
    			pstate->rd_device_state  =
    				VL53L1_DEVICESTATE_SW_STANDBY;
    			pstate->rd_stream_count  = 0;
    			pstate->rd_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK;
    			pstate->rd_timing_status = 0;
    
    		break;
    		}
    	}
    
    #ifdef VL53L1_LOGGING
    	VL53L1_print_ll_driver_state(pstate);
    #endif
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_check_ll_driver_rd_state(
    	VL53L1_DEV         Dev)
    {
    	/*
    	 * Checks if the LL Driver Read state and expected stream count
    	 * matches the state and stream count received from the device
    	 *
    	 * Check is only use in back to back mode
    	 */
    
    	VL53L1_Error         status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t  *pdev =
    			VL53L1DevStructGetLLDriverHandle(Dev);
    
    	VL53L1_ll_driver_state_t  *pstate       = &(pdev->ll_state);
    	VL53L1_system_results_t   *psys_results = &(pdev->sys_results);
    
    	uint8_t   device_range_status   = 0;
    	uint8_t   device_stream_count   = 0;
    	uint8_t   device_gph_id         = 0;
    
    	LOG_FUNCTION_START("");
    
    #ifdef VL53L1_LOGGING
    	VL53L1_print_ll_driver_state(pstate);
    #endif
    
    	device_range_status =
    			psys_results->result__range_status &
    			VL53L1_RANGE_STATUS__RANGE_STATUS_MASK;
    
    	device_stream_count = psys_results->result__stream_count;
    
    	/* load the correct GPH ID */
    	device_gph_id = (psys_results->result__interrupt_status &
    		VL53L1_INTERRUPT_STATUS__GPH_ID_INT_STATUS_MASK) >> 4;
    
    	/* only apply checks in back to back mode */
    
    	if ((pdev->sys_ctrl.system__mode_start &
    		VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) ==
    		VL53L1_DEVICEMEASUREMENTMODE_BACKTOBACK) {
    
    		/* if read state is wait for GPH sync interrupt then check the
    		 * device returns a GPH range status value otherwise check that
    		 * the stream count matches
    		 *
    		 * In theory the stream count should zero for the GPH interrupt
    		 * but that is not the case after at abort ....
    		 */
    
    		if (pstate->rd_device_state ==
    			VL53L1_DEVICESTATE_RANGING_WAIT_GPH_SYNC) {
    
    			if (device_range_status !=
    				VL53L1_DEVICEERROR_GPHSTREAMCOUNT0READY) {
    				status = VL53L1_ERROR_GPH_SYNC_CHECK_FAIL;
    			}
    		} else {
    			if (pstate->rd_stream_count != device_stream_count) {
    				status = VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL;
    			}
    
    		/*
    		 * Check Read state GPH ID
    		 */
    
    		if (pstate->rd_gph_id != device_gph_id) {
    			status = VL53L1_ERROR_GPH_ID_CHECK_FAIL;
    #ifdef VL53L1_LOGGING
    				trace_print(VL53L1_TRACE_LEVEL_ALL,
    					"    RDSTATECHECK: Check failed: rd_gph_id: %d, device_gph_id: %d\n",
    					pstate->rd_gph_id,
    					device_gph_id);
    #endif
    			} else {
    #ifdef VL53L1_LOGGING
    				trace_print(VL53L1_TRACE_LEVEL_ALL,
    					"    RDSTATECHECK: Check passed: rd_gph_id: %d, device_gph_id: %d\n",
    					pstate->rd_gph_id,
    					device_gph_id);
    #endif
    			}
    
    		} /* else (not in WAIT_GPH_SYNC) */
    
    	} /* if back to back */
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error  VL53L1_update_ll_driver_cfg_state(
    	VL53L1_DEV         Dev)
    {
    	/**
    	 * State machine for configuration device state
    	 */
    
    	VL53L1_Error         status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t  *pdev =
    			VL53L1DevStructGetLLDriverHandle(Dev);
    
    	VL53L1_ll_driver_state_t *pstate = &(pdev->ll_state);
    
    	LOG_FUNCTION_START("");
    
    #ifdef VL53L1_LOGGING
    	VL53L1_print_ll_driver_state(pstate);
    #endif
    
    	/* if top bits of mode start reset are zero then in standby state */
    
    	if ((pdev->sys_ctrl.system__mode_start &
    		VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK) == 0x00) {
    
    		pstate->cfg_device_state  = VL53L1_DEVICESTATE_SW_STANDBY;
    		pstate->cfg_stream_count  = 0;
    		pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK;
    		pstate->cfg_timing_status = 0;
    
    	} else {
    
    		/*
    		 * implement configuration stream count
    		 */
    
    		if (pstate->cfg_stream_count == 0xFF) {
    			pstate->cfg_stream_count = 0x80;
    		} else {
    			pstate->cfg_stream_count++;
    		}
    
    		/*
    		 * Toggle grouped parameter hold ID
    		 */
    
    		pstate->cfg_gph_id ^= VL53L1_GROUPEDPARAMETERHOLD_ID_MASK;
    
    		/*
    		 * Implement configuration state machine
    		 */
    
    		switch (pstate->cfg_device_state) {
    
    		case VL53L1_DEVICESTATE_SW_STANDBY:
    
    			pstate->cfg_timing_status ^= 0x01;
    			pstate->cfg_stream_count = 1;
    
    			pstate->cfg_device_state = VL53L1_DEVICESTATE_RANGING_DSS_AUTO;
    		break;
    
    		case VL53L1_DEVICESTATE_RANGING_DSS_AUTO:
    
    			pstate->cfg_timing_status ^= 0x01;
    
    		break;
    
    		default:
    
    			pstate->cfg_device_state = VL53L1_DEVICESTATE_SW_STANDBY;
    			pstate->cfg_stream_count = 0;
    			pstate->cfg_gph_id = VL53L1_GROUPEDPARAMETERHOLD_ID_MASK;
    			pstate->cfg_timing_status = 0;
    
    		break;
    		}
    	}
    
    #ifdef VL53L1_LOGGING
    	VL53L1_print_ll_driver_state(pstate);
    #endif
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    void VL53L1_copy_rtn_good_spads_to_buffer(
    	VL53L1_nvm_copy_data_t  *pdata,
    	uint8_t                 *pbuffer)
    {
    	/*
    	 * Convenience function to copy return SPAD enables to buffer
    	 */
    
    	*(pbuffer +  0) = pdata->global_config__spad_enables_rtn_0;
    	*(pbuffer +  1) = pdata->global_config__spad_enables_rtn_1;
    	*(pbuffer +  2) = pdata->global_config__spad_enables_rtn_2;
    	*(pbuffer +  3) = pdata->global_config__spad_enables_rtn_3;
    	*(pbuffer +  4) = pdata->global_config__spad_enables_rtn_4;
    	*(pbuffer +  5) = pdata->global_config__spad_enables_rtn_5;
    	*(pbuffer +  6) = pdata->global_config__spad_enables_rtn_6;
    	*(pbuffer +  7) = pdata->global_config__spad_enables_rtn_7;
    	*(pbuffer +  8) = pdata->global_config__spad_enables_rtn_8;
    	*(pbuffer +  9) = pdata->global_config__spad_enables_rtn_9;
    	*(pbuffer + 10) = pdata->global_config__spad_enables_rtn_10;
    	*(pbuffer + 11) = pdata->global_config__spad_enables_rtn_11;
    	*(pbuffer + 12) = pdata->global_config__spad_enables_rtn_12;
    	*(pbuffer + 13) = pdata->global_config__spad_enables_rtn_13;
    	*(pbuffer + 14) = pdata->global_config__spad_enables_rtn_14;
    	*(pbuffer + 15) = pdata->global_config__spad_enables_rtn_15;
    	*(pbuffer + 16) = pdata->global_config__spad_enables_rtn_16;
    	*(pbuffer + 17) = pdata->global_config__spad_enables_rtn_17;
    	*(pbuffer + 18) = pdata->global_config__spad_enables_rtn_18;
    	*(pbuffer + 19) = pdata->global_config__spad_enables_rtn_19;
    	*(pbuffer + 20) = pdata->global_config__spad_enables_rtn_20;
    	*(pbuffer + 21) = pdata->global_config__spad_enables_rtn_21;
    	*(pbuffer + 22) = pdata->global_config__spad_enables_rtn_22;
    	*(pbuffer + 23) = pdata->global_config__spad_enables_rtn_23;
    	*(pbuffer + 24) = pdata->global_config__spad_enables_rtn_24;
    	*(pbuffer + 25) = pdata->global_config__spad_enables_rtn_25;
    	*(pbuffer + 26) = pdata->global_config__spad_enables_rtn_26;
    	*(pbuffer + 27) = pdata->global_config__spad_enables_rtn_27;
    	*(pbuffer + 28) = pdata->global_config__spad_enables_rtn_28;
    	*(pbuffer + 29) = pdata->global_config__spad_enables_rtn_29;
    	*(pbuffer + 30) = pdata->global_config__spad_enables_rtn_30;
    	*(pbuffer + 31) = pdata->global_config__spad_enables_rtn_31;
    }
    
    
    void VL53L1_init_system_results(
    		VL53L1_system_results_t  *pdata)
    {
    	/*
    	 * Initialises the system results to all 0xFF just like the
    	 * device firmware does a the start of a range
    	 */
    
    	pdata->result__interrupt_status                       = 0xFF;
    	pdata->result__range_status                           = 0xFF;
    	pdata->result__report_status                          = 0xFF;
    	pdata->result__stream_count                           = 0xFF;
    
    	pdata->result__dss_actual_effective_spads_sd0         = 0xFFFF;
    	pdata->result__peak_signal_count_rate_mcps_sd0        = 0xFFFF;
    	pdata->result__ambient_count_rate_mcps_sd0            = 0xFFFF;
    	pdata->result__sigma_sd0                              = 0xFFFF;
    	pdata->result__phase_sd0                              = 0xFFFF;
    	pdata->result__final_crosstalk_corrected_range_mm_sd0 = 0xFFFF;
    	pdata->result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 =
    			0xFFFF;
    	pdata->result__mm_inner_actual_effective_spads_sd0    = 0xFFFF;
    	pdata->result__mm_outer_actual_effective_spads_sd0    = 0xFFFF;
    	pdata->result__avg_signal_count_rate_mcps_sd0         = 0xFFFF;
    
    	pdata->result__dss_actual_effective_spads_sd1         = 0xFFFF;
    	pdata->result__peak_signal_count_rate_mcps_sd1        = 0xFFFF;
    	pdata->result__ambient_count_rate_mcps_sd1            = 0xFFFF;
    	pdata->result__sigma_sd1                              = 0xFFFF;
    	pdata->result__phase_sd1                              = 0xFFFF;
    	pdata->result__final_crosstalk_corrected_range_mm_sd1 = 0xFFFF;
    	pdata->result__spare_0_sd1                            = 0xFFFF;
    	pdata->result__spare_1_sd1                            = 0xFFFF;
    	pdata->result__spare_2_sd1                            = 0xFFFF;
    	pdata->result__spare_3_sd1                            = 0xFF;
    
    }
    
    
    void VL53L1_i2c_encode_uint16_t(
    	uint16_t    ip_value,
    	uint16_t    count,
    	uint8_t    *pbuffer)
    {
    	/*
    	 * Encodes a uint16_t register value into an I2C write buffer
    	 * MS byte first order (as per I2C register map.
    	 */
    
    	uint16_t   i    = 0;
    	uint16_t   data = 0;
    
    	data =  ip_value;
    
    	for (i = 0; i < count ; i++) {
    		pbuffer[count-i-1] = (uint8_t)(data & 0x00FF);
    		data = data >> 8;
    	}
    }
    
    uint16_t VL53L1_i2c_decode_uint16_t(
    	uint16_t    count,
    	uint8_t    *pbuffer)
    {
    	/*
    	 * Decodes a uint16_t from the input I2C read buffer
    	 * (MS byte first order)
    	 */
    
    	uint16_t   value = 0x00;
    
    	while (count-- > 0) {
    		value = (value << 8) | (uint16_t)*pbuffer++;
    	}
    
    	return value;
    }
    
    
    void VL53L1_i2c_encode_int16_t(
    	int16_t     ip_value,
    	uint16_t    count,
    	uint8_t    *pbuffer)
    {
    	/*
    	 * Encodes a int16_t register value into an I2C write buffer
    	 * MS byte first order (as per I2C register map.
    	 */
    
    	uint16_t   i    = 0;
    	int16_t    data = 0;
    
    	data =  ip_value;
    
    	for (i = 0; i < count ; i++) {
    		pbuffer[count-i-1] = (uint8_t)(data & 0x00FF);
    		data = data >> 8;
    	}
    }
    
    int16_t VL53L1_i2c_decode_int16_t(
    	uint16_t    count,
    	uint8_t    *pbuffer)
    {
    	/*
    	 * Decodes a int16_t from the input I2C read buffer
    	 * (MS byte first order)
    	 */
    
    	int16_t    value = 0x00;
    
    	/* implement sign extension */
    	if (*pbuffer >= 0x80) {
    		value = 0xFFFF;
    	}
    
    	while (count-- > 0) {
    		value = (value << 8) | (int16_t)*pbuffer++;
    	}
    
    	return value;
    }
    
    void VL53L1_i2c_encode_uint32_t(
    	uint32_t    ip_value,
    	uint16_t    count,
    	uint8_t    *pbuffer)
    {
    	/*
    	 * Encodes a uint32_t register value into an I2C write buffer
    	 * MS byte first order (as per I2C register map.
    	 */
    
    	uint16_t   i    = 0;
    	uint32_t   data = 0;
    
    	data =  ip_value;
    
    	for (i = 0; i < count ; i++) {
    		pbuffer[count-i-1] = (uint8_t)(data & 0x00FF);
    		data = data >> 8;
    	}
    }
    
    uint32_t VL53L1_i2c_decode_uint32_t(
    	uint16_t    count,
    	uint8_t    *pbuffer)
    {
    	/*
    	 * Decodes a uint32_t from the input I2C read buffer
    	 * (MS byte first order)
    	 */
    
    	uint32_t   value = 0x00;
    
    	while (count-- > 0) {
    		value = (value << 8) | (uint32_t)*pbuffer++;
    	}
    
    	return value;
    }
    
    
    uint32_t VL53L1_i2c_decode_with_mask(
    	uint16_t    count,
    	uint8_t    *pbuffer,
    	uint32_t    bit_mask,
    	uint32_t    down_shift,
    	uint32_t    offset)
    {
    	/*
    	 * Decodes an integer from the input I2C read buffer
    	 * (MS byte first order)
    	 */
    
    	uint32_t   value = 0x00;
    
    	/* extract from buffer */
    	while (count-- > 0) {
    		value = (value << 8) | (uint32_t)*pbuffer++;
    	}
    
    	/* Apply bit mask and down shift */
    	value =  value & bit_mask;
    	if (down_shift > 0) {
    		value = value >> down_shift;
    	}
    
    	/* add offset */
    	value = value + offset;
    
    	return value;
    }
    
    
    void VL53L1_i2c_encode_int32_t(
    	int32_t     ip_value,
    	uint16_t    count,
    	uint8_t    *pbuffer)
    {
    	/*
    	 * Encodes a int32_t register value into an I2C write buffer
    	 * MS byte first order (as per I2C register map.
    	 */
    
    	uint16_t   i    = 0;
    	int32_t    data = 0;
    
    	data =  ip_value;
    
    	for (i = 0; i < count ; i++) {
    		pbuffer[count-i-1] = (uint8_t)(data & 0x00FF);
    		data = data >> 8;
    	}
    }
    
    int32_t VL53L1_i2c_decode_int32_t(
    	uint16_t    count,
    	uint8_t    *pbuffer)
    {
    	/*
    	 * Decodes a int32_t from the input I2C read buffer
    	 * (MS byte first order)
    	 */
    
    	int32_t    value = 0x00;
    
    	/* implement sign extension */
    	if (*pbuffer >= 0x80) {
    		value = 0xFFFFFFFF;
    	}
    
    	while (count-- > 0) {
    		value = (value << 8) | (int32_t)*pbuffer++;
    	}
    
    	return value;
    }
    
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_start_test(
    	VL53L1_DEV    Dev,
    	uint8_t       test_mode__ctrl)
    {
    	/*
    	 * Triggers the start of a test mode
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	if (status == VL53L1_ERROR_NONE) { /*lint !e774 always true*/
    		status = VL53L1_WrByte(
    					Dev,
    					VL53L1_TEST_MODE__CTRL,
    					test_mode__ctrl);
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    
    VL53L1_Error VL53L1_set_firmware_enable_register(
    	VL53L1_DEV    Dev,
    	uint8_t       value)
    {
    	/*
    	 * Set FIRMWARE__ENABLE register
    	 */
    
    	VL53L1_Error status         = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	pdev->sys_ctrl.firmware__enable = value;
    
    	status = VL53L1_WrByte(
    				Dev,
    				VL53L1_FIRMWARE__ENABLE,
    				pdev->sys_ctrl.firmware__enable);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_enable_firmware(
    	VL53L1_DEV    Dev)
    {
    	/*
    	 * Enable firmware
    	 */
    
    	VL53L1_Error status       = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	status = VL53L1_set_firmware_enable_register(Dev, 0x01);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_disable_firmware(
    	VL53L1_DEV    Dev)
    {
    	/*
    	 * Disable firmware
    	 */
    
    	VL53L1_Error status       = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	status = VL53L1_set_firmware_enable_register(Dev, 0x00);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_set_powerforce_register(
    	VL53L1_DEV    Dev,
    	uint8_t       value)
    {
    	/*
    	 * Set power force register
    	 */
    
    	VL53L1_Error status       = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	pdev->sys_ctrl.power_management__go1_power_force = value;
    
    	status = VL53L1_WrByte(
    			Dev,
    			VL53L1_POWER_MANAGEMENT__GO1_POWER_FORCE,
    			pdev->sys_ctrl.power_management__go1_power_force);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_enable_powerforce(
    	VL53L1_DEV    Dev)
    {
    	/*
    	 * Enable power force
    	 */
    
    	VL53L1_Error status       = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	status = VL53L1_set_powerforce_register(Dev, 0x01);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_disable_powerforce(
    	VL53L1_DEV    Dev)
    {
    	/*
    	 * Disable power force
    	 */
    
    	VL53L1_Error status       = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	status = VL53L1_set_powerforce_register(Dev, 0x00);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_clear_interrupt(
    	VL53L1_DEV    Dev)
    {
    	/*
    	 * Clear Ranging interrupt by writing to
    	 */
    
    	VL53L1_Error status       = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	LOG_FUNCTION_START("");
    
    	pdev->sys_ctrl.system__interrupt_clear = VL53L1_CLEAR_RANGE_INT;
    
    	status = VL53L1_WrByte(
    					Dev,
    					VL53L1_SYSTEM__INTERRUPT_CLEAR,
    					pdev->sys_ctrl.system__interrupt_clear);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    #ifdef VL53L1_DEBUG
    VL53L1_Error VL53L1_force_shadow_stream_count_to_zero(
    	VL53L1_DEV    Dev)
    {
    	/*
    	 * Forces shadow stream count to zero
    	 */
    
    	VL53L1_Error status       = VL53L1_ERROR_NONE;
    
    	if (status == VL53L1_ERROR_NONE) { /*lint !e774 always true*/
    		status = VL53L1_disable_firmware(Dev);
    	}
    
    	if (status == VL53L1_ERROR_NONE) {
    		status = VL53L1_WrByte(
    				Dev,
    				VL53L1_SHADOW_RESULT__STREAM_COUNT,
    				0x00);
    	}
    
    	if (status == VL53L1_ERROR_NONE) {
    		status = VL53L1_enable_firmware(Dev);
    	}
    
    	return status;
    }
    #endif
    
    uint32_t VL53L1_calc_macro_period_us(
    	uint16_t  fast_osc_frequency,
    	uint8_t   vcsel_period)
    {
    	/* Calculates macro period in [us] from the input fast oscillator
    	 * frequency and VCSEL period
    	 *
    	 * Macro period fixed point format = unsigned 12.12
    	 * Maximum supported macro period  = 4095.9999 us
    	 */
    
    	uint32_t  pll_period_us        = 0;
    	uint8_t   vcsel_period_pclks   = 0;
    	uint32_t  macro_period_us      = 0;
    
    	LOG_FUNCTION_START("");
    
    	/*  Calculate PLL period in [us] from the  fast_osc_frequency
    	 *  Fast osc frequency fixed point format = unsigned 4.12
    	 */
    
    	pll_period_us = VL53L1_calc_pll_period_us(fast_osc_frequency);
    
    	/*  VCSEL period
    	 *  - the real VCSEL period in PLL clocks = 2*(VCSEL_PERIOD+1)
    	 */
    
    	vcsel_period_pclks = VL53L1_decode_vcsel_period(vcsel_period);
    
    	/*  Macro period
    	 *  - PLL period [us]      = 0.24 format
    	 *      - for 1.0 MHz fast oscillator freq
    	 *      - max PLL period = 1/64 (6-bits)
    	 *      - i.e only the lower 18-bits of PLL Period value are used
    	 *  - Macro period [vclks] = 2304 (12-bits)
    	 *
    	 *  Max bits (24 - 6) + 12 = 30-bits usage
    	 *
    	 *  Downshift by 6 before multiplying by the VCSEL Period
    	 */
    
    	macro_period_us =
    			(uint32_t)VL53L1_MACRO_PERIOD_VCSEL_PERIODS *
    			pll_period_us;
    	macro_period_us = macro_period_us >> 6;
    
    	macro_period_us = macro_period_us * (uint32_t)vcsel_period_pclks;
    	macro_period_us = macro_period_us >> 6;
    
    #ifdef VL53L1_LOGGING
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u\n", "pll_period_us",
    			pll_period_us);
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u\n", "vcsel_period_pclks",
    			vcsel_period_pclks);
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u\n", "macro_period_us",
    			macro_period_us);
    #endif
    
    	LOG_FUNCTION_END(0);
    
    	return macro_period_us;
    }
    
    
    uint16_t VL53L1_calc_range_ignore_threshold(
    	uint32_t central_rate,
    	int16_t  x_gradient,
    	int16_t  y_gradient,
    	uint8_t  rate_mult)
    {
    	/* Calculates Range Ignore Threshold rate per spad
    	 * in Mcps - 3.13 format
    	 *
    	 * Calculates worst case xtalk rate per spad in array corner
    	 * based on input central xtalk and x and y gradients
    	 *
    	 * Worst case rate = central rate + (8*(magnitude(xgrad)) +
    	 * (8*(magnitude(ygrad)))
    	 *
    	 * Range ignore threshold rate is then multiplied by user input
    	 * rate_mult (in 3.5 fractional format)
    	 *
    	 */
    
    	int32_t    range_ignore_thresh_int  = 0;
    	uint16_t   range_ignore_thresh_kcps = 0;
    	int32_t    central_rate_int         = 0;
    	int16_t    x_gradient_int           = 0;
    	int16_t    y_gradient_int           = 0;
    
    	LOG_FUNCTION_START("");
    
    	/* Shift central_rate to .13 fractional for simple addition */
    
    	central_rate_int = ((int32_t)central_rate * (1 << 4)) / (1000);
    
    	if (x_gradient < 0) {
    		x_gradient_int = x_gradient * -1;
    	}
    
    	if (y_gradient < 0) {
    		y_gradient_int = y_gradient * -1;
    	}
    
    	/* Calculate full rate per spad - worst case from measured xtalk */
    	/* Generated here from .11 fractional kcps */
    	/* Additional factor of 4 applied to bring fractional precision to .13 */
    
    	range_ignore_thresh_int = (8 * x_gradient_int * 4) + (8 * y_gradient_int * 4);
    
    	/* Convert Kcps to Mcps */
    
    	range_ignore_thresh_int = range_ignore_thresh_int / 1000;
    
    	/* Combine with Central Rate - Mcps .13 format*/
    
    	range_ignore_thresh_int = range_ignore_thresh_int + central_rate_int;
    
    	/* Mult by user input */
    
    	range_ignore_thresh_int = (int32_t)rate_mult * range_ignore_thresh_int;
    
    	range_ignore_thresh_int = (range_ignore_thresh_int + (1<<4)) / (1<<5);
    
    	/* Finally clip and output in correct format */
    
    	if (range_ignore_thresh_int > 0xFFFF) {
    		range_ignore_thresh_kcps = 0xFFFF;
    	} else {
    		range_ignore_thresh_kcps = (uint16_t)range_ignore_thresh_int;
    	}
    
    #ifdef VL53L1_LOGGING
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u\n", "range_ignore_thresh_kcps",
    			range_ignore_thresh_kcps);
    #endif
    
    	LOG_FUNCTION_END(0);
    
    	return range_ignore_thresh_kcps;
    }
    
    
    uint32_t VL53L1_calc_timeout_mclks(
    	uint32_t timeout_us,
    	uint32_t macro_period_us)
    {
    	/*  Calculates the timeout value in macro periods based on the input
    	 *  timeout period in milliseconds and the macro period in [us]
    	 *
    	 *  Max timeout supported is 1000000 us (1 sec) -> 20-bits
    	 *  Max timeout in 20.12 format = 32-bits
    	 *
    	 *  Macro period [us] = 12.12 format
    	 */
    
    	uint32_t timeout_mclks   = 0;
    
    	LOG_FUNCTION_START("");
    
    	timeout_mclks   =
    			((timeout_us << 12) + (macro_period_us>>1)) /
    			macro_period_us;
    
    	LOG_FUNCTION_END(0);
    
    	return timeout_mclks;
    }
    
    
    uint16_t VL53L1_calc_encoded_timeout(
    	uint32_t timeout_us,
    	uint32_t macro_period_us)
    {
    	/*  Calculates the encoded timeout register value based on the input
    	 *  timeout period in milliseconds and the macro period in [us]
    	 *
    	 *  Max timeout supported is 1000000 us (1 sec) -> 20-bits
    	 *  Max timeout in 20.12 format = 32-bits
    	 *
    	 *  Macro period [us] = 12.12 format
    	 */
    
    	uint32_t timeout_mclks   = 0;
    	uint16_t timeout_encoded = 0;
    
    	LOG_FUNCTION_START("");
    
    	timeout_mclks   =
    		VL53L1_calc_timeout_mclks(timeout_us, macro_period_us);
    
    	timeout_encoded =
    		VL53L1_encode_timeout(timeout_mclks);
    
    #ifdef VL53L1_LOGGING
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u  (0x%04X)\n", "timeout_mclks",
    			timeout_mclks, timeout_mclks);
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u  (0x%04X)\n", "timeout_encoded",
    			timeout_encoded, timeout_encoded);
    #endif
    
    	LOG_FUNCTION_END(0);
    
    	return timeout_encoded;
    }
    
    
    uint32_t VL53L1_calc_timeout_us(
    	uint32_t timeout_mclks,
    	uint32_t macro_period_us)
    {
    	/*  Calculates the  timeout in [us] based on the input
    	 *  encoded timeout and the macro period in [us]
    	 *
    	 *  Max timeout supported is 1000000 us (1 sec) -> 20-bits
    	 *  Max timeout in 20.12 format = 32-bits
    	 *
    	 *  Macro period [us] = 12.12 format
    	 */
    
    	uint32_t timeout_us     = 0;
    	uint64_t tmp            = 0;
    
    	LOG_FUNCTION_START("");
    
    	tmp  = (uint64_t)timeout_mclks * (uint64_t)macro_period_us;
    	tmp += 0x00800;
    	tmp  = tmp >> 12;
    
    	timeout_us = (uint32_t)tmp;
    
    #ifdef VL53L1_LOGGING
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u  (0x%04X)\n", "timeout_mclks",
    			timeout_mclks, timeout_mclks);
    
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u us\n", "timeout_us",
    			timeout_us, timeout_us);
    #endif
    
    	LOG_FUNCTION_END(0);
    
    	return timeout_us;
    }
    
    uint32_t VL53L1_calc_crosstalk_plane_offset_with_margin(
    		uint32_t     plane_offset_kcps,
    		int16_t      margin_offset_kcps)
    {
    	uint32_t plane_offset_with_margin = 0;
    	int32_t  plane_offset_kcps_temp   = 0;
    
    	LOG_FUNCTION_START("");
    
    	plane_offset_kcps_temp =
    		(int32_t)plane_offset_kcps +
    		(int32_t)margin_offset_kcps;
    
    	if (plane_offset_kcps_temp < 0) {
    		plane_offset_kcps_temp = 0;
    	} else {
    		if (plane_offset_kcps_temp > 0x3FFFF) {
    			plane_offset_kcps_temp = 0x3FFFF;
    		}
    	}
    
    	plane_offset_with_margin = (uint32_t) plane_offset_kcps_temp;
    
    	LOG_FUNCTION_END(0);
    
    	return plane_offset_with_margin;
    
    }
    
    uint32_t VL53L1_calc_decoded_timeout_us(
    	uint16_t timeout_encoded,
    	uint32_t macro_period_us)
    {
    	/*  Calculates the  timeout in [us] based on the input
    	 *  encoded timeout and the macro period in [us]
    	 *
    	 *  Max timeout supported is 1000000 us (1 sec) -> 20-bits
    	 *  Max timeout in 20.12 format = 32-bits
    	 *
    	 *  Macro period [us] = 12.12 format
    	 */
    
    	uint32_t timeout_mclks  = 0;
    	uint32_t timeout_us     = 0;
    
    	LOG_FUNCTION_START("");
    
    	timeout_mclks =
    		VL53L1_decode_timeout(timeout_encoded);
    
    	timeout_us    =
    		VL53L1_calc_timeout_us(timeout_mclks, macro_period_us);
    
    	LOG_FUNCTION_END(0);
    
    	return timeout_us;
    }
    
    
    uint16_t VL53L1_encode_timeout(uint32_t timeout_mclks)
    {
    	/*
    	 * Encode timeout in macro periods in (LSByte * 2^MSByte) + 1 format
    	 */
    
    	uint16_t encoded_timeout = 0;
    	uint32_t ls_byte = 0;
    	uint16_t ms_byte = 0;
    
    	if (timeout_mclks > 0) {
    		ls_byte = timeout_mclks - 1;
    
    		while ((ls_byte & 0xFFFFFF00) > 0) {
    			ls_byte = ls_byte >> 1;
    			ms_byte++;
    		}
    
    		encoded_timeout = (ms_byte << 8)
    				+ (uint16_t) (ls_byte & 0x000000FF);
    	}
    
    	return encoded_timeout;
    }
    
    
    uint32_t VL53L1_decode_timeout(uint16_t encoded_timeout)
    {
    	/*
    	 * Decode 16-bit timeout register value
    	 * format (LSByte * 2^MSByte) + 1
    	 */
    
    	uint32_t timeout_macro_clks = 0;
    
    	timeout_macro_clks = ((uint32_t) (encoded_timeout & 0x00FF)
    			<< (uint32_t) ((encoded_timeout & 0xFF00) >> 8)) + 1;
    
    	return timeout_macro_clks;
    }
    
    
    VL53L1_Error VL53L1_calc_timeout_register_values(
    	uint32_t                 phasecal_config_timeout_us,
    	uint32_t                 mm_config_timeout_us,
    	uint32_t                 range_config_timeout_us,
    	uint16_t                 fast_osc_frequency,
    	VL53L1_general_config_t *pgeneral,
    	VL53L1_timing_config_t  *ptiming)
    {
    	/*
    	 * Converts the input MM and range timeouts in [us]
    	 * into the appropriate register values
    	 *
    	 * Must also be run after the VCSEL period settings are changed
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    
    	uint32_t macro_period_us    = 0;
    	uint32_t timeout_mclks      = 0;
    	uint16_t timeout_encoded    = 0;
    
    	LOG_FUNCTION_START("");
    
    	if (fast_osc_frequency == 0) {
    		status = VL53L1_ERROR_DIVISION_BY_ZERO;
    	} else {
    		/* Update Macro Period for Range A VCSEL Period */
    		macro_period_us =
    				VL53L1_calc_macro_period_us(
    					fast_osc_frequency,
    					ptiming->range_config__vcsel_period_a);
    
    		/*  Update Phase timeout - uses Timing A */
    		timeout_mclks =
    			VL53L1_calc_timeout_mclks(
    				phasecal_config_timeout_us,
    				macro_period_us);
    
    		/* clip as the phase cal timeout register is only 8-bits */
    		if (timeout_mclks > 0xFF)
    			timeout_mclks = 0xFF;
    
    		pgeneral->phasecal_config__timeout_macrop =
    				(uint8_t)timeout_mclks;
    
    		/*  Update MM Timing A timeout */
    		timeout_encoded =
    			VL53L1_calc_encoded_timeout(
    				mm_config_timeout_us,
    				macro_period_us);
    
    		ptiming->mm_config__timeout_macrop_a_hi =
    				(uint8_t)((timeout_encoded & 0xFF00) >> 8);
    		ptiming->mm_config__timeout_macrop_a_lo =
    				(uint8_t) (timeout_encoded & 0x00FF);
    
    		/* Update Range Timing A timeout */
    		timeout_encoded =
    			VL53L1_calc_encoded_timeout(
    				range_config_timeout_us,
    				macro_period_us);
    
    		ptiming->range_config__timeout_macrop_a_hi =
    				(uint8_t)((timeout_encoded & 0xFF00) >> 8);
    		ptiming->range_config__timeout_macrop_a_lo =
    				(uint8_t) (timeout_encoded & 0x00FF);
    
    		/* Update Macro Period for Range B VCSEL Period */
    		macro_period_us =
    				VL53L1_calc_macro_period_us(
    					fast_osc_frequency,
    					ptiming->range_config__vcsel_period_b);
    
    		/* Update MM Timing B timeout */
    		timeout_encoded =
    				VL53L1_calc_encoded_timeout(
    					mm_config_timeout_us,
    					macro_period_us);
    
    		ptiming->mm_config__timeout_macrop_b_hi =
    				(uint8_t)((timeout_encoded & 0xFF00) >> 8);
    		ptiming->mm_config__timeout_macrop_b_lo =
    				(uint8_t) (timeout_encoded & 0x00FF);
    
    		/* Update Range Timing B timeout */
    		timeout_encoded = VL53L1_calc_encoded_timeout(
    							range_config_timeout_us,
    							macro_period_us);
    
    		ptiming->range_config__timeout_macrop_b_hi =
    				(uint8_t)((timeout_encoded & 0xFF00) >> 8);
    		ptiming->range_config__timeout_macrop_b_lo =
    				(uint8_t) (timeout_encoded & 0x00FF);
    	}
    
    	LOG_FUNCTION_END(0);
    
    	return status;
    
    }
    
    
    uint8_t VL53L1_encode_vcsel_period(uint8_t vcsel_period_pclks)
    {
    	/*
    	 * Converts the encoded VCSEL period register value into
    	 * the real period in PLL clocks
    	 */
    
    	uint8_t vcsel_period_reg = 0;
    
    	vcsel_period_reg = (vcsel_period_pclks >> 1) - 1;
    
    	return vcsel_period_reg;
    }
    
    
    uint32_t VL53L1_decode_unsigned_integer(
    	uint8_t  *pbuffer,
    	uint8_t   no_of_bytes)
    {
    	/*
    	 * Decodes a integer number from the buffer
    	 */
    
    	uint8_t   i = 0;
    	uint32_t  decoded_value = 0;
    
    	for (i = 0 ; i < no_of_bytes ; i++) {
    		decoded_value = (decoded_value << 8) + (uint32_t)pbuffer[i];
    	}
    
    	return decoded_value;
    }
    
    
    void VL53L1_encode_unsigned_integer(
    	uint32_t  ip_value,
    	uint8_t   no_of_bytes,
    	uint8_t  *pbuffer)
    {
    	/*
    	 * Encodes an integer number into the buffer
    	 */
    
    	uint8_t   i    = 0;
    	uint32_t  data = 0;
    
    	data = ip_value;
    	for (i = 0; i < no_of_bytes ; i++) {
    		pbuffer[no_of_bytes-i-1] = data & 0x00FF;
    		data = data >> 8;
    	}
    }
    
    
    void VL53L1_spad_number_to_byte_bit_index(
    	uint8_t  spad_number,
    	uint8_t *pbyte_index,
    	uint8_t *pbit_index,
    	uint8_t *pbit_mask)
    {
    
        /**
         *  Converts the input SPAD number into the SPAD Enable byte index, bit index and bit mask
         *
         *  byte_index = (spad_no >> 3)
         *  bit_index  =  spad_no & 0x07
         *  bit_mask   =  0x01 << bit_index
         */
    
        *pbyte_index  = spad_number >> 3;
        *pbit_index   = spad_number & 0x07;
        *pbit_mask    = 0x01 << *pbit_index;
    
    }
    
    
    void VL53L1_encode_row_col(
    	uint8_t  row,
    	uint8_t  col,
    	uint8_t *pspad_number)
    {
    	/**
    	 *  Encodes the input array(row,col) location as SPAD number.
    	 */
    
    	if (row > 7) {
    		*pspad_number = 128 + (col << 3) + (15-row);
    	} else {
    		*pspad_number = ((15-col) << 3) + row;
    	}
    }
    
    
    void VL53L1_decode_zone_size(
    	uint8_t  encoded_xy_size,
    	uint8_t  *pwidth,
    	uint8_t  *pheight)
    {
    
    	/* extract x and y sizes
    	 *
    	 * Important: the sense of the device width and height is swapped
    	 * versus the API sense
    	 *
    	 * MS Nibble = height
    	 * LS Nibble = width
    	 */
    
    	*pheight = encoded_xy_size >> 4;
    	*pwidth  = encoded_xy_size & 0x0F;
    
    }
    
    
    void VL53L1_encode_zone_size(
    	uint8_t  width,
    	uint8_t  height,
    	uint8_t *pencoded_xy_size)
    {
    	/* merge x and y sizes
    	 *
    	 * Important: the sense of the device width and height is swapped
    	 * versus the API sense
    	 *
    	 * MS Nibble = height
    	 * LS Nibble = width
    	 */
    
    	*pencoded_xy_size = (height << 4) + width;
    
    }
    
    
    void VL53L1_decode_zone_limits(
    	uint8_t   encoded_xy_centre,
    	uint8_t   encoded_xy_size,
    	int16_t  *px_ll,
    	int16_t  *py_ll,
    	int16_t  *px_ur,
    	int16_t  *py_ur)
    {
    
    	/*
    	 * compute zone lower left and upper right limits
    	 *
    	 * centre (8,8) width = 16, height = 16  -> (0,0) -> (15,15)
         * centre (8,8) width = 14, height = 16  -> (1,0) -> (14,15)
    	 */
    
    	uint8_t x_centre = 0;
    	uint8_t y_centre = 0;
    	uint8_t width    = 0;
    	uint8_t height   = 0;
    
    	/* decode zone centre and size information */
    
    	VL53L1_decode_row_col(
    		encoded_xy_centre,
    		&y_centre,
    		&x_centre);
    
    	VL53L1_decode_zone_size(
    		encoded_xy_size,
    		&width,
    		&height);
    
    	/* compute bounds and clip */
    
    	*px_ll = (int16_t)x_centre - ((int16_t)width + 1) / 2;
    	if (*px_ll < 0)
    		*px_ll = 0;
    
    	*px_ur = *px_ll + (int16_t)width;
    	if (*px_ur > (VL53L1_SPAD_ARRAY_WIDTH-1))
    		*px_ur = VL53L1_SPAD_ARRAY_WIDTH-1;
    
    	*py_ll = (int16_t)y_centre - ((int16_t)height + 1) / 2;
    	if (*py_ll < 0)
    		*py_ll = 0;
    
    	*py_ur = *py_ll + (int16_t)height;
    	if (*py_ur > (VL53L1_SPAD_ARRAY_HEIGHT-1))
    		*py_ur = VL53L1_SPAD_ARRAY_HEIGHT-1;
    }
    
    
    uint8_t VL53L1_is_aperture_location(
    	uint8_t row,
    	uint8_t col)
    {
    	/*
    	 * Returns > 0 if input (row,col) location  is an aperture
    	 */
    
    	uint8_t is_aperture = 0;
    	uint8_t mod_row     = row % 4;
    	uint8_t mod_col     = col % 4;
    
    	if (mod_row == 0 && mod_col == 2)
    		is_aperture = 1;
    
    	if (mod_row == 2 && mod_col == 0)
    		is_aperture = 1;
    
    	return is_aperture;
    }
    
    
    void VL53L1_calc_mm_effective_spads(
    	uint8_t     encoded_mm_roi_centre,
    	uint8_t     encoded_mm_roi_size,
    	uint8_t     encoded_zone_centre,
    	uint8_t     encoded_zone_size,
    	uint8_t    *pgood_spads,
    	uint16_t    aperture_attenuation,
    	uint16_t   *pmm_inner_effective_spads,
    	uint16_t   *pmm_outer_effective_spads)
    {
    
    	/* Calculates the effective SPAD counts for the MM inner and outer
    	 * regions based on the input MM ROI, Zone info and return good
    	 * SPAD map
    	 */
    
    	int16_t   x         = 0;
    	int16_t   y         = 0;
    
    	int16_t   mm_x_ll   = 0;
    	int16_t   mm_y_ll   = 0;
    	int16_t   mm_x_ur   = 0;
    	int16_t   mm_y_ur   = 0;
    
    	int16_t   zone_x_ll = 0;
    	int16_t   zone_y_ll = 0;
    	int16_t   zone_x_ur = 0;
    	int16_t   zone_y_ur = 0;
    
    	uint8_t   spad_number = 0;
    	uint8_t   byte_index  = 0;
    	uint8_t   bit_index   = 0;
    	uint8_t   bit_mask    = 0;
    
    	uint8_t   is_aperture = 0;
    	uint16_t  spad_attenuation = 0;
    
    	/* decode the MM ROI and Zone limits */
    
    	VL53L1_decode_zone_limits(
    		encoded_mm_roi_centre,
    		encoded_mm_roi_size,
    		&mm_x_ll,
    		&mm_y_ll,
    		&mm_x_ur,
    		&mm_y_ur);
    
    	VL53L1_decode_zone_limits(
    		encoded_zone_centre,
    		encoded_zone_size,
    		&zone_x_ll,
    		&zone_y_ll,
    		&zone_x_ur,
    		&zone_y_ur);
    
    	/*
    	 * Loop though all SPAD within the zone. Check if it is
    	 * a good SPAD then add the  transmission value to either
    	 * the inner or outer effective SPAD count dependent if
    	 * the SPAD lies within the MM ROI.
    	 */
    
    	*pmm_inner_effective_spads = 0;
    	*pmm_outer_effective_spads = 0;
    
    	for (y = zone_y_ll ; y <= zone_y_ur ; y++) {
    		for (x = zone_x_ll ; x <= zone_x_ur ; x++) {
    
    			/* Convert location into SPAD number */
    
    			VL53L1_encode_row_col(
    				(uint8_t)y,
    				(uint8_t)x,
    				&spad_number);
    
    			/* Convert spad number into byte and bit index
    			 * this is required to look up the appropriate
    			 * SPAD enable bit with the 32-byte good SPAD
    			 * enable buffer
    			 */
    
    			VL53L1_spad_number_to_byte_bit_index(
    				spad_number,
    				&byte_index,
    				&bit_index,
    				&bit_mask);
    
    			/* If spad is good then add it */
    
    			if ((pgood_spads[byte_index] & bit_mask) > 0) {
    				/* determine if apertured SPAD or not */
    
    				is_aperture = VL53L1_is_aperture_location(
    					(uint8_t)y,
    					(uint8_t)x);
    
    				if (is_aperture > 0)
    					spad_attenuation = aperture_attenuation;
    				else
    					spad_attenuation = 0x0100;
    
    				/*
    				 * if inside MM roi add to inner effective SPAD count
    				 * otherwise add to outer effective SPAD Count
    				 */
    
    				if (x >= mm_x_ll && x <= mm_x_ur &&
    					y >= mm_y_ll && y <= mm_y_ur)
    					*pmm_inner_effective_spads +=
    						spad_attenuation;
    				else
    					*pmm_outer_effective_spads +=
    						spad_attenuation;
    			}
    		}
    	}
    }
    
    
    /*
     * Encodes VL53L1_GPIO_interrupt_config_t structure to FW register format
     */
    
    uint8_t	VL53L1_encode_GPIO_interrupt_config(
    	VL53L1_GPIO_interrupt_config_t	*pintconf)
    {
    	uint8_t system__interrupt_config;
    
    	system__interrupt_config = pintconf->intr_mode_distance;
    	system__interrupt_config |= ((pintconf->intr_mode_rate) << 2);
    	system__interrupt_config |= ((pintconf->intr_new_measure_ready) << 5);
    	system__interrupt_config |= ((pintconf->intr_no_target) << 6);
    	system__interrupt_config |= ((pintconf->intr_combined_mode) << 7);
    
    	return system__interrupt_config;
    }
    
    /*
     * Decodes FW register to VL53L1_GPIO_interrupt_config_t structure
     */
    
    VL53L1_GPIO_interrupt_config_t VL53L1_decode_GPIO_interrupt_config(
    	uint8_t		system__interrupt_config)
    {
    	VL53L1_GPIO_interrupt_config_t	intconf;
    
    	intconf.intr_mode_distance = system__interrupt_config & 0x03;
    	intconf.intr_mode_rate = (system__interrupt_config >> 2) & 0x03;
    	intconf.intr_new_measure_ready = (system__interrupt_config >> 5) & 0x01;
    	intconf.intr_no_target = (system__interrupt_config >> 6) & 0x01;
    	intconf.intr_combined_mode = (system__interrupt_config >> 7) & 0x01;
    
    	/* set some default values */
    	intconf.threshold_rate_low = 0;
    	intconf.threshold_rate_high = 0;
    	intconf.threshold_distance_low = 0;
    	intconf.threshold_distance_high = 0;
    
    	return intconf;
    }
    
    /*
     * Set GPIO distance threshold
     */
    
    VL53L1_Error VL53L1_set_GPIO_distance_threshold(
    	VL53L1_DEV                      Dev,
    	uint16_t			threshold_high,
    	uint16_t			threshold_low)
    {
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	LOG_FUNCTION_START("");
    
    	pdev->dyn_cfg.system__thresh_high = threshold_high;
    	pdev->dyn_cfg.system__thresh_low = threshold_low;
    
    	LOG_FUNCTION_END(status);
    	return status;
    }
    
    /*
     * Set GPIO rate threshold
     */
    
    VL53L1_Error VL53L1_set_GPIO_rate_threshold(
    	VL53L1_DEV                      Dev,
    	uint16_t			threshold_high,
    	uint16_t			threshold_low)
    {
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	LOG_FUNCTION_START("");
    
    	pdev->gen_cfg.system__thresh_rate_high = threshold_high;
    	pdev->gen_cfg.system__thresh_rate_low = threshold_low;
    
    	LOG_FUNCTION_END(status);
    	return status;
    }
    
    /*
     * Set GPIO thresholds from structure
     */
    
    VL53L1_Error VL53L1_set_GPIO_thresholds_from_struct(
    	VL53L1_DEV                      Dev,
    	VL53L1_GPIO_interrupt_config_t *pintconf)
    {
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	status = VL53L1_set_GPIO_distance_threshold(
    			Dev,
    			pintconf->threshold_distance_high,
    			pintconf->threshold_distance_low);
    
    	if (status == VL53L1_ERROR_NONE) {
    		status =
    			VL53L1_set_GPIO_rate_threshold(
    				Dev,
    				pintconf->threshold_rate_high,
    				pintconf->threshold_rate_low);
    	}
    
    	LOG_FUNCTION_END(status);
    	return status;
    }
    
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_set_ref_spad_char_config(
    	VL53L1_DEV    Dev,
    	uint8_t       vcsel_period_a,
    	uint32_t      phasecal_timeout_us,
    	uint16_t      total_rate_target_mcps,
    	uint16_t      max_count_rate_rtn_limit_mcps,
    	uint16_t      min_count_rate_rtn_limit_mcps,
    	uint16_t      fast_osc_frequency)
    {
    	/*
    	 * Initialises the VCSEL period A and phasecal timeout registers
    	 * for the Reference SPAD Characterisation test
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t buffer[2];
    
    	uint32_t macro_period_us = 0;
    	uint32_t timeout_mclks   = 0;
    
    	LOG_FUNCTION_START("");
    
    	/*
    	 * Update Macro Period for Range A VCSEL Period
    	 */
    	macro_period_us =
    		VL53L1_calc_macro_period_us(
    			fast_osc_frequency,
    			vcsel_period_a);
    
    	/*
    	 *  Calculate PhaseCal timeout and clip to max of 255 macro periods
    	 */
    
    	timeout_mclks = phasecal_timeout_us << 12;
    	timeout_mclks = timeout_mclks + (macro_period_us>>1);
    	timeout_mclks = timeout_mclks / macro_period_us;
    
    	if (timeout_mclks > 0xFF)
    		pdev->gen_cfg.phasecal_config__timeout_macrop = 0xFF;
    	else
    		pdev->gen_cfg.phasecal_config__timeout_macrop =
    				(uint8_t)timeout_mclks;
    
    	pdev->tim_cfg.range_config__vcsel_period_a = vcsel_period_a;
    
    	/*
    	 * Update device settings
    	 */
    
    	if (status == VL53L1_ERROR_NONE) /*lint !e774 always true*/
    		status =
    			VL53L1_WrByte(
    				Dev,
    				VL53L1_PHASECAL_CONFIG__TIMEOUT_MACROP,
    				pdev->gen_cfg.phasecal_config__timeout_macrop);
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WrByte(
    				Dev,
    				VL53L1_RANGE_CONFIG__VCSEL_PERIOD_A,
    				pdev->tim_cfg.range_config__vcsel_period_a);
    
    	/*
    	 * Copy vcsel register value to the WOI registers to ensure that
    	 * it is correctly set for the specified VCSEL period
    	 */
    
    	buffer[0] = pdev->tim_cfg.range_config__vcsel_period_a;
    	buffer[1] = pdev->tim_cfg.range_config__vcsel_period_a;
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WriteMulti(
    				Dev,
    				VL53L1_SD_CONFIG__WOI_SD0,
    				buffer,
    				2); /* It should be be replaced with a define */
    
    	/*
    	 * Set min, target and max rate limits
    	 */
    
    	pdev->customer.ref_spad_char__total_rate_target_mcps =
    			total_rate_target_mcps;
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WrWord(
    				Dev,
    				VL53L1_REF_SPAD_CHAR__TOTAL_RATE_TARGET_MCPS,
    				total_rate_target_mcps);  /* 9.7 format */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WrWord(
    				Dev,
    				VL53L1_RANGE_CONFIG__SIGMA_THRESH,
    				max_count_rate_rtn_limit_mcps);
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WrWord(
    				Dev,
    				VL53L1_RANGE_CONFIG__MIN_COUNT_RATE_RTN_LIMIT_MCPS,
    				min_count_rate_rtn_limit_mcps);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_set_ssc_config(
    	VL53L1_DEV            Dev,
    	VL53L1_ssc_config_t  *pssc_cfg,
    	uint16_t              fast_osc_frequency)
    {
    	/**
    	 * Builds and sends a single I2C multiple byte transaction to
    	 * initialize the device for SSC.
    	 *
    	 * The function also sets the WOI registers based on the input
    	 * vcsel period register value.
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	uint8_t buffer[5];
    
    	uint32_t macro_period_us = 0;
    	uint16_t timeout_encoded = 0;
    
    	LOG_FUNCTION_START("");
    
    	/*
    	 * Update Macro Period for Range A VCSEL Period
    	 */
    	macro_period_us =
    		VL53L1_calc_macro_period_us(
    			fast_osc_frequency,
    			pssc_cfg->vcsel_period);
    
    	/*
    	 *  Update MM Timing A timeout
    	 */
    	timeout_encoded =
    		VL53L1_calc_encoded_timeout(
    			pssc_cfg->timeout_us,
    			macro_period_us);
    
    	/* update VCSEL timings */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WrByte(
    				Dev,
    				VL53L1_CAL_CONFIG__VCSEL_START,
    				pssc_cfg->vcsel_start);
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WrByte(
    				Dev,
    				VL53L1_GLOBAL_CONFIG__VCSEL_WIDTH,
    				pssc_cfg->vcsel_width);
    
    	/* build buffer for timeouts, period and rate limit */
    
        buffer[0] = (uint8_t)((timeout_encoded &  0x0000FF00) >> 8);
        buffer[1] = (uint8_t) (timeout_encoded &  0x000000FF);
        buffer[2] = pssc_cfg->vcsel_period;
        buffer[3] = (uint8_t)((pssc_cfg->rate_limit_mcps &  0x0000FF00) >> 8);
        buffer[4] = (uint8_t) (pssc_cfg->rate_limit_mcps &  0x000000FF);
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WriteMulti(
    				Dev,
    				VL53L1_RANGE_CONFIG__TIMEOUT_MACROP_B_HI,
    				buffer,
    				5);
    
    	/*
    	 * Copy vcsel register value to the WOI registers to ensure that
    	 * it is correctly set for the specified VCSEL period
    	 */
    
        buffer[0] = pssc_cfg->vcsel_period;
        buffer[1] = pssc_cfg->vcsel_period;
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WriteMulti(
    				Dev,
    				VL53L1_SD_CONFIG__WOI_SD0,
    				buffer,
    				2);
    
    	/*
    	 * Write zero to NVM_BIST_CTRL to send RTN CountRate to Patch RAM
    	 * or 1 to write REF CountRate to Patch RAM
    	 */
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WrByte(
    				Dev,
    				VL53L1_NVM_BIST__CTRL,
    				pssc_cfg->array_select);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    
    #ifndef VL53L1_NOCALIB
    VL53L1_Error VL53L1_get_spad_rate_data(
    	VL53L1_DEV                Dev,
    	VL53L1_spad_rate_data_t  *pspad_rates)
    {
    
        /**
         *  Gets the SSC rate map output
         */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
        int               i = 0;
    
        uint8_t  data[512];
        uint8_t *pdata = &data[0];
    
    	LOG_FUNCTION_START("");
    
    	/* Disable Firmware to Read Patch Ram */
    
    	if (status == VL53L1_ERROR_NONE)
    		status = VL53L1_disable_firmware(Dev);
    
        /*
         * Read Return SPADs Rates from patch RAM.
         * Note : platform layer  splits the I2C comms into smaller chunks
         */
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_ReadMulti(
    				Dev,
    				VL53L1_PRIVATE__PATCH_BASE_ADDR_RSLV,
    				pdata,
    				512);
    
        /* now convert into 16-bit number */
        pdata = &data[0];
        for (i = 0 ; i < VL53L1_NO_OF_SPAD_ENABLES ; i++) {
    		pspad_rates->rate_data[i] =
    			(uint16_t)VL53L1_decode_unsigned_integer(pdata, 2);
    		pdata += 2;
        }
    
        /* Initialise structure info */
    
        pspad_rates->buffer_size     = VL53L1_NO_OF_SPAD_ENABLES;
        pspad_rates->no_of_values    = VL53L1_NO_OF_SPAD_ENABLES;
        pspad_rates->fractional_bits = 15;
    
    	/* Re-enable Firmware */
    
    	if (status == VL53L1_ERROR_NONE)
    		status = VL53L1_enable_firmware(Dev);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    #endif
    
    /* Start Patch_LowPowerAutoMode */
    
    VL53L1_Error VL53L1_low_power_auto_data_init(
    	VL53L1_DEV                          Dev
    	)
    {
    
    	/*
    	 * Initializes internal data structures for low power auto mode
    	 */
    
    	/* don't really use this here */
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	LOG_FUNCTION_START("");
    
    	pdev->low_power_auto_data.vhv_loop_bound =
    		VL53L1_TUNINGPARM_LOWPOWERAUTO_VHV_LOOP_BOUND_DEFAULT;
    	pdev->low_power_auto_data.is_low_power_auto_mode = 0;
    	pdev->low_power_auto_data.low_power_auto_range_count = 0;
    	pdev->low_power_auto_data.saved_interrupt_config = 0;
    	pdev->low_power_auto_data.saved_vhv_init = 0;
    	pdev->low_power_auto_data.saved_vhv_timeout = 0;
    	pdev->low_power_auto_data.first_run_phasecal_result = 0;
    	pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0;
    	pdev->low_power_auto_data.dss__required_spads = 0;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_low_power_auto_data_stop_range(
    	VL53L1_DEV                          Dev
    	)
    {
    
    	/*
    	 * Range has been paused but may continue later
    	 */
    
    	/* don't really use this here */
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	LOG_FUNCTION_START("");
    
    	/* doing this ensures stop_range followed by a get_device_results does
    	 * not mess up the counters */
    
    	pdev->low_power_auto_data.low_power_auto_range_count = 0xFF;
    
    	pdev->low_power_auto_data.first_run_phasecal_result = 0;
    	pdev->low_power_auto_data.dss__total_rate_per_spad_mcps = 0;
    	pdev->low_power_auto_data.dss__required_spads = 0;
    
    	/* restore vhv configs */
    	if (pdev->low_power_auto_data.saved_vhv_init != 0)
    		pdev->stat_nvm.vhv_config__init =
    			pdev->low_power_auto_data.saved_vhv_init;
    	if (pdev->low_power_auto_data.saved_vhv_timeout != 0)
    		pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound =
    			pdev->low_power_auto_data.saved_vhv_timeout;
    
    	/* remove phasecal override */
    	pdev->gen_cfg.phasecal_config__override = 0x00;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_config_low_power_auto_mode(
    	VL53L1_general_config_t   *pgeneral,
    	VL53L1_dynamic_config_t   *pdynamic,
    	VL53L1_low_power_auto_data_t *plpadata
    	)
    {
    
    	/*
    	 * Initializes configs for when low power auto presets are selected
    	 */
    
    	/* don't really use this here */
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* set low power auto mode */
    	plpadata->is_low_power_auto_mode = 1;
    
    	/* set low power range count to 0 */
    	plpadata->low_power_auto_range_count = 0;
    
    	/* Turn off MM1/MM2 and DSS2 */
    	pdynamic->system__sequence_config = \
    			VL53L1_SEQUENCE_VHV_EN | \
    			VL53L1_SEQUENCE_PHASECAL_EN | \
    			VL53L1_SEQUENCE_DSS1_EN | \
    			/* VL53L1_SEQUENCE_DSS2_EN | \*/
    			/* VL53L1_SEQUENCE_MM1_EN | \*/
    			/* VL53L1_SEQUENCE_MM2_EN | \*/
    			VL53L1_SEQUENCE_RANGE_EN;
    
    	/* Set DSS to manual/expected SPADs */
    	pgeneral->dss_config__manual_effective_spads_select = 200 << 8;
    	pgeneral->dss_config__roi_mode_control =
    		VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_low_power_auto_setup_manual_calibration(
    	VL53L1_DEV        Dev)
    {
    
    	/*
    	 * Setup ranges after the first one in low power auto mode by turning
    	 * off FW calibration steps and programming static values
    	 */
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	/* don't really use this here */
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* save original vhv configs */
    	pdev->low_power_auto_data.saved_vhv_init =
    		pdev->stat_nvm.vhv_config__init;
    	pdev->low_power_auto_data.saved_vhv_timeout =
    		pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound;
    
    	/* disable VHV init */
    	pdev->stat_nvm.vhv_config__init &= 0x7F;
    	/* set loop bound to tuning param */
    	pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound =
    		(pdev->stat_nvm.vhv_config__timeout_macrop_loop_bound & 0x03) +
    		(pdev->low_power_auto_data.vhv_loop_bound << 2);
    	/* override phasecal */
    	pdev->gen_cfg.phasecal_config__override = 0x01;
    	pdev->low_power_auto_data.first_run_phasecal_result =
    		pdev->dbg_results.phasecal_result__vcsel_start;
    	pdev->gen_cfg.cal_config__vcsel_start =
    		pdev->low_power_auto_data.first_run_phasecal_result;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    VL53L1_Error VL53L1_low_power_auto_update_DSS(
    	VL53L1_DEV        Dev)
    {
    
    	/*
    	 * Do a DSS calculation and update manual config
    	 */
    
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	/* don't really use this here */
    	VL53L1_Error  status = VL53L1_ERROR_NONE;
    
    	uint32_t utemp32a;
    
    	LOG_FUNCTION_START("");
    
    	/* Calc total rate per spad */
    
    	/* 9.7 format */
    	utemp32a = pdev->sys_results.result__peak_signal_count_rate_crosstalk_corrected_mcps_sd0 +
    		pdev->sys_results.result__ambient_count_rate_mcps_sd0;
    
    	/* clip to 16 bits */
    	if (utemp32a > 0xFFFF)
    		utemp32a = 0xFFFF;
    
    	/* shift up to take advantage of 32 bits */
    	/* 9.23 format */
    	utemp32a = utemp32a << 16;
    
    	/* check SPAD count */
    	if (pdev->sys_results.result__dss_actual_effective_spads_sd0 == 0)
    		status = VL53L1_ERROR_DIVISION_BY_ZERO;
    	else {
    		/* format 17.15 */
    		utemp32a = utemp32a /
    			pdev->sys_results.result__dss_actual_effective_spads_sd0;
    		/* save intermediate result */
    		pdev->low_power_auto_data.dss__total_rate_per_spad_mcps =
    			utemp32a;
    
    		/* get the target rate and shift up by 16
    		 * format 9.23 */
    		utemp32a = pdev->stat_cfg.dss_config__target_total_rate_mcps <<
    			16;
    
    		/* check for divide by zero */
    		if (pdev->low_power_auto_data.dss__total_rate_per_spad_mcps == 0)
    			status = VL53L1_ERROR_DIVISION_BY_ZERO;
    		else {
    			/* divide by rate per spad
    			 * format 24.8 */
    			utemp32a = utemp32a /
    				pdev->low_power_auto_data.dss__total_rate_per_spad_mcps;
    
    			/* clip to 16 bit */
    			if (utemp32a > 0xFFFF)
    				utemp32a = 0xFFFF;
    
    			/* save result in low power auto data */
    			pdev->low_power_auto_data.dss__required_spads =
    				(uint16_t)utemp32a;
    
    			/* override DSS config */
    			pdev->gen_cfg.dss_config__manual_effective_spads_select =
    				pdev->low_power_auto_data.dss__required_spads;
    			pdev->gen_cfg.dss_config__roi_mode_control =
    				VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS;
    		}
    
    	}
    
    	if (status == VL53L1_ERROR_DIVISION_BY_ZERO) {
    		/* We want to gracefully set a spad target, not just exit with
    		* an error */
    
    		/* set target to mid point */
    		pdev->low_power_auto_data.dss__required_spads = 0x8000;
    
    		/* override DSS config */
    		pdev->gen_cfg.dss_config__manual_effective_spads_select =
    		pdev->low_power_auto_data.dss__required_spads;
    		pdev->gen_cfg.dss_config__roi_mode_control =
    		VL53L1_DEVICEDSSMODE__REQUESTED_EFFFECTIVE_SPADS;
    
    		/* reset error */
    		status = VL53L1_ERROR_NONE;
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    /* End Patch_LowPowerAutoMode */
    
    vl53l1_core.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file  vl53l1_core_support.c
     *
     * @brief EwokPlus25 core function definition
     */
    
    #include "vl53l1_ll_def.h"
    #include "vl53l1_ll_device.h"
    #include "vl53l1_platform_log.h"
    #include "vl53l1_core_support.h"
    #include "vl53l1_platform_user_data.h"
    #include "vl53l1_platform_user_defines.h"
    
    #ifdef VL53L1_LOGGING
    #include "vl53l1_debug.h"
    #include "vl53l1_register_debug.h"
    #endif
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, \
    		status, fmt, ##__VA_ARGS__)
    
    #define trace_print(level, ...) \
    	_LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_CORE, \
    	level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__)
    
    
    uint32_t VL53L1_calc_pll_period_us(
    	uint16_t  fast_osc_frequency)
    {
    	/*  Calculates PLL frequency using NVM fast_osc_frequency
    	 *  Fast osc frequency fixed point format = unsigned 4.12
    	 *
    	 *  PLL period fixed point format = unsigned 0.24
    	 *  Min input fast osc frequency  = 1 MHz
    	 *  PLL Multiplier = 64 (fixed)
    	 *  Min PLL freq = 64.0MHz
    	 *  -> max PLL period = 1/ 64
    	 *  ->  only the 18 LS bits are used
    	 *
    	 *  2^30 = (2^24) (1.0us) * 4096 (2^12) / 64 (PLL Multiplier)
    	 */
    
    	uint32_t  pll_period_us        = 0;
    
    	LOG_FUNCTION_START("");
    
    	pll_period_us = (0x01 << 30) / fast_osc_frequency;
    
    #ifdef VL53L1_LOGGING
    	trace_print(VL53L1_TRACE_LEVEL_DEBUG,
    			"    %-48s : %10u\n", "pll_period_us",
    			pll_period_us);
    #endif
    
    	LOG_FUNCTION_END(0);
    
    	return pll_period_us;
    }
    
    
    #ifdef PAL_EXTENDED
    uint32_t  VL53L1_duration_maths(
    	uint32_t  pll_period_us,
    	uint32_t  vcsel_parm_pclks,
    	uint32_t  window_vclks,
    	uint32_t  elapsed_mclks)
    {
    	/*
    	 * Generates the ranging duration in us
    	 *
    	 * duration_us = elapsed_mclks * vcsel_perm_pclks *
    	 *                        window_vclks * pll_period_us
    	 *
    	 * returned value in [us] with no fraction bits
    	 */
    
    	uint64_t  tmp_long_int = 0;
    	uint32_t  duration_us  = 0;
    
    	/* PLL period us =  0.24  18 LS bits used
    	 * window_vclks  =  12.0  (2304 max)
    	 * output 30b (6.24)
    	 */
    	duration_us = window_vclks * pll_period_us;
    
    	/* down shift by 12
    	 * output 18b (6.12)
    	 */
    	duration_us = duration_us >> 12;
    
    	/* Save first part of the calc (#1) */
    	tmp_long_int = (uint64_t)duration_us;
    
    	/* Multiply elapsed macro periods (22-bit)
    	 *      by VCSEL parameter 6.4  (max 63.9999)
    	 * output 32b (28.4)
    	 */
    	duration_us = elapsed_mclks * vcsel_parm_pclks;
    
    	/* down shift by 4 to remove fractional bits (#2)
    	 * output 28b (28.0)
    	 */
    	duration_us = duration_us >> 4;
    
    	/* Multiply #1 18b (6.12) by #2  28b (28.0)
    	 * output 46b (34.12)
    	 */
    	tmp_long_int = tmp_long_int * (uint64_t)duration_us;
    
    	/* Remove fractional part
    	 * output 34b (34.0)
    	 */
    	tmp_long_int = tmp_long_int >> 12;
    
    	/* Clip to 32-bits */
    	if (tmp_long_int > 0xFFFFFFFF) {
    		tmp_long_int = 0xFFFFFFFF;
    	}
    
    	duration_us  = (uint32_t)tmp_long_int;
    
    	return duration_us;
    }
    
    
    uint32_t VL53L1_isqrt(uint32_t num)
    {
    
    	/*
    	 * Implements an integer square root
    	 *
    	 * From: http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
    	 */
    
    	uint32_t  res = 0;
    	uint32_t  bit = 1 << 30; /* The second-to-top bit is set: 1 << 14 for 16-bits, 1 << 30 for 32 bits */
    
    	/* "bit" starts at the highest power of four <= the argument. */
    	while (bit > num) {
    		bit >>= 2;
    	}
    
    	while (bit != 0) {
    		if (num >= res + bit)  {
    			num -= res + bit;
    			res = (res >> 1) + bit;
    		} else {
    			res >>= 1;
    		}
    		bit >>= 2;
    	}
    
    	return res;
    }
    
    
    uint16_t VL53L1_rate_maths(
    	int32_t   events,
    	uint32_t  time_us)
    {
    	/*
    	 * Converts events into count rate
    	 *
    	 * Max events = 512 Mcps * 1sec
    	 *            = 512,000,000 events
    	 *            = 29b
    	 *
    	 * If events >  2^24 use  3-bit fractional bits is used internally
    	 * otherwise  7-bit fractional bits are used
    	 */
    
    	uint32_t  tmp_int   = 0;
    	uint32_t  frac_bits = 7;
    	uint16_t  rate_mcps = 0; /* 9.7 format */
    
    	/*
    	 *  Clip input event range
    	 */
    
    	if (events > VL53L1_SPAD_TOTAL_COUNT_MAX) {
    		tmp_int = VL53L1_SPAD_TOTAL_COUNT_MAX;
    	} else if (events > 0) {
    		tmp_int = (uint32_t)events;
    	}
    
    	/*
    	 * if events > VL53L1_SPAD_TOTAL_COUNT_RES_THRES use 3 rather
    	 *  than 7 fractional bits internal to function
    	 */
    
    	if (events > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) {
    		frac_bits = 3;
    	} else {
    		frac_bits = 7;
    	}
    
    	/*
    	 * Create 3 or 7 fractional bits
    	 * output 32b (29.3 or 25.7)
    	 * Divide by range duration in [us] - no fractional bits
    	 */
    	if (time_us > 0) {
    		tmp_int = ((tmp_int << frac_bits) + (time_us / 2)) / time_us;
    	}
    
    	/*
    	 * Re align if reduced resolution
    	 */
    	if (events > VL53L1_SPAD_TOTAL_COUNT_RES_THRES) {
    		tmp_int = tmp_int << 4;
    	}
    
    	/*
    	 * Firmware internal count is 17.7 (24b) but it this
    	 * case clip to 16-bit value for reporting
    	 */
    
    	if (tmp_int > 0xFFFF) {
    		tmp_int = 0xFFFF;
    	}
    
    	rate_mcps =  (uint16_t)tmp_int;
    
    	return rate_mcps;
    }
    
    uint16_t VL53L1_rate_per_spad_maths(
    	uint32_t  frac_bits,
    	uint32_t  peak_count_rate,
    	uint16_t  num_spads,
    	uint32_t  max_output_value)
    {
    
    	uint32_t  tmp_int   = 0;
    
    	/* rate_per_spad Format varies with prog frac_bits */
    	uint16_t  rate_per_spad = 0;
    
    	/* Calculate rate per spad with variable fractional bits */
    
    	/* Frac_bits should be programmed as final frac_bits - 7 as
    	 * the pk_rate contains an inherent 7 bit resolution
    	 */
    
    	if (num_spads > 0) {
    		tmp_int = (peak_count_rate << 8) << frac_bits;
    		tmp_int = (tmp_int + ((uint32_t)num_spads / 2)) / (uint32_t)num_spads;
    	} else {
    		tmp_int = ((peak_count_rate) << frac_bits);
    	}
    
    	/* Clip in case of overwrap - special code */
    
    	if (tmp_int > max_output_value) {
    		tmp_int = max_output_value;
    	}
    
    	rate_per_spad = (uint16_t)tmp_int;
    
    	return rate_per_spad;
    }
    
    int32_t VL53L1_range_maths(
    	uint16_t  fast_osc_frequency,
    	uint16_t  phase,
    	uint16_t  zero_distance_phase,
    	uint8_t   fractional_bits,
    	int32_t   gain_factor,
    	int32_t   range_offset_mm)
    {
    	/*
    	 * Converts phase information into distance in [mm]
    	 */
    
    	uint32_t    pll_period_us = 0; /* 0.24 format */
    	int64_t     tmp_long_int  = 0;
    	int32_t     range_mm      = 0;
    
    	/* Calculate PLL period in [ps] */
    
    	pll_period_us  = VL53L1_calc_pll_period_us(fast_osc_frequency);
    
    	/* Raw range in [mm]
    	 *
    	 * calculate the phase difference between return and reference phases
    	 *
    	 * phases 16b (5.11)
    	 * output 17b including sign bit
    	 */
    
    	tmp_long_int = (int64_t)phase - (int64_t)zero_distance_phase;
    
    	/*
    	 * multiply by the PLL period
    	 *
    	 * PLL period 24bit (0.24) but only 18 LS bits used
    	 *
    	 * Output  35b (0.35) (17b + 18b)
    	 */
    
    	tmp_long_int =  tmp_long_int * (int64_t)pll_period_us;
    
    	/*
    	 * Down shift by 9 - Output 26b (0.26)
    	 */
    
    	tmp_long_int =  tmp_long_int / (0x01 << 9);
    
    	/*
    	 *  multiply by speed of light in air divided by 8
    	 *  Factor of 8 includes 2 for the round trip and 4 scaling
    	 *
    	 *  VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8 = 16b (16.2)
    	 *
    	 *  Output 42b (18.24) (16b + 26b)
    	 */
    
    	tmp_long_int =  tmp_long_int * VL53L1_SPEED_OF_LIGHT_IN_AIR_DIV_8;
    
    	/*
    	 * Down shift by 22 - Output 20b (18.2)
    	 */
    
    	tmp_long_int =  tmp_long_int / (0x01 << 22);
    
    	/* Add range offset */
    	range_mm  = (int32_t)tmp_long_int + range_offset_mm;
    
    	/* apply correction gain */
    	range_mm *= gain_factor;
    	range_mm += 0x0400;
    	range_mm /= 0x0800;
    
    	/* Remove fractional bits */
    	if (fractional_bits == 0)
    		range_mm = range_mm / (0x01 << 2);
    	else if (fractional_bits == 1)
    		range_mm = range_mm / (0x01 << 1);
    
    	return range_mm;
    }
    #endif
    
    uint8_t VL53L1_decode_vcsel_period(uint8_t vcsel_period_reg)
    {
    	/*
    	 * Converts the encoded VCSEL period register value into
    	 * the real period in PLL clocks
    	 */
    
    	uint8_t vcsel_period_pclks = 0;
    
    	vcsel_period_pclks = (vcsel_period_reg + 1) << 1;
    
    	return vcsel_period_pclks;
    }
    
    
    void VL53L1_decode_row_col(
    	uint8_t  spad_number,
    	uint8_t  *prow,
    	uint8_t  *pcol)
    {
    
    	/**
    	 *  Decodes the array (row,col) location from
    	 *  the input SPAD number
    	 */
    
    	if (spad_number > 127) {
    		*prow = 8 + ((255-spad_number) & 0x07);
    		*pcol = (spad_number-128) >> 3;
    	} else {
    		*prow = spad_number & 0x07;
    		*pcol = (127-spad_number) >> 3;
    	}
    }
    
    
    vl53l1_core_support.hvl53l1_def.hvl53l1_error_codes.hvl53l1_error_exceptions.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file   vl53l1_error_strings.c
     * @brief  VL53L1 API functions for decoding error codes to a text string
     */
    
    #include "vl53l1_error_codes.h"
    #include "vl53l1_error_strings.h"
    #include "vl53l1_platform_log.h"
    #include "vl53l1_ll_def.h"
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_API, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_API, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_API, \
    		status, fmt, ##__VA_ARGS__)
    
    
    #ifndef VL53L1_DEBUG
    	#define VL53L1_USE_EMPTY_STRING
    #endif
    
    VL53L1_Error VL53L1_get_pal_error_string(
    	VL53L1_Error   PalErrorCode,
    	char          *pPalErrorString)
    {
    	VL53L1_Error Status = VL53L1_ERROR_NONE;
    
    #ifdef VL53L1_USE_EMPTY_STRING
    	SUPPRESS_UNUSED_WARNING(PalErrorCode);
    #endif
    
    	LOG_FUNCTION_START("");
    
    #ifdef VL53L1_USE_EMPTY_STRING
    	VL53L1_COPYSTRING(pPalErrorString, "");
    #else
    
    	switch (PalErrorCode) {
    	case VL53L1_ERROR_NONE:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_NONE);
    		break;
    	case VL53L1_ERROR_CALIBRATION_WARNING:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_CALIBRATION_WARNING);
    		break;
    	case VL53L1_ERROR_MIN_CLIPPED:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_MIN_CLIPPED);
    		break;
    	case VL53L1_ERROR_UNDEFINED:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_UNDEFINED);
    		break;
    	case VL53L1_ERROR_INVALID_PARAMS:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_INVALID_PARAMS);
    		break;
    	case VL53L1_ERROR_NOT_SUPPORTED:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_NOT_SUPPORTED);
    		break;
    	case VL53L1_ERROR_RANGE_ERROR:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_RANGE_ERROR);
    		break;
    	case VL53L1_ERROR_TIME_OUT:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_TIME_OUT);
    		break;
    	case VL53L1_ERROR_MODE_NOT_SUPPORTED:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_MODE_NOT_SUPPORTED);
    		break;
    	case VL53L1_ERROR_BUFFER_TOO_SMALL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_BUFFER_TOO_SMALL);
    		break;
    	case VL53L1_ERROR_COMMS_BUFFER_TOO_SMALL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_COMMS_BUFFER_TOO_SMALL);
    		break;
    	case VL53L1_ERROR_GPIO_NOT_EXISTING:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_GPIO_NOT_EXISTING);
    		break;
    	case VL53L1_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_GPIO_FUNCTIONALITY_NOT_SUPPORTED);
    		break;
    	case VL53L1_ERROR_CONTROL_INTERFACE:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_CONTROL_INTERFACE);
    		break;
    	case VL53L1_ERROR_INVALID_COMMAND:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_INVALID_COMMAND);
    		break;
    	case VL53L1_ERROR_DIVISION_BY_ZERO:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_DIVISION_BY_ZERO);
    		break;
    	case VL53L1_ERROR_REF_SPAD_INIT:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_REF_SPAD_INIT);
    		break;
    	case VL53L1_ERROR_GPH_SYNC_CHECK_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_GPH_SYNC_CHECK_FAIL);
    		break;
    	case VL53L1_ERROR_STREAM_COUNT_CHECK_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_STREAM_COUNT_CHECK_FAIL);
    		break;
    	case VL53L1_ERROR_GPH_ID_CHECK_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_GPH_ID_CHECK_FAIL);
    		break;
    	case VL53L1_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_ZONE_STREAM_COUNT_CHECK_FAIL);
    		break;
    	case VL53L1_ERROR_ZONE_GPH_ID_CHECK_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_ZONE_GPH_ID_CHECK_FAIL);
    		break;
    
    	case VL53L1_ERROR_XTALK_EXTRACTION_NO_SAMPLE_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_XTALK_EXTRACTION_NO_SAMPLES_FAIL);
    		break;
    	case VL53L1_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_XTALK_EXTRACTION_SIGMA_LIMIT_FAIL);
    		break;
    
    	case VL53L1_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_OFFSET_CAL_NO_SAMPLE_FAIL);
    		break;
    	case VL53L1_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_OFFSET_CAL_NO_SPADS_ENABLED_FAIL);
    		break;
    	case VL53L1_ERROR_ZONE_CAL_NO_SAMPLE_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_ZONE_CAL_NO_SAMPLE_FAIL);
    		break;
    
    	case VL53L1_WARNING_OFFSET_CAL_MISSING_SAMPLES:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_OFFSET_CAL_MISSING_SAMPLES);
    		break;
    	case VL53L1_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_OFFSET_CAL_SIGMA_TOO_HIGH);
    		break;
    	case VL53L1_WARNING_OFFSET_CAL_RATE_TOO_HIGH:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_OFFSET_CAL_RATE_TOO_HIGH);
    		break;
    	case VL53L1_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_OFFSET_CAL_SPAD_COUNT_TOO_LOW);
    		break;
    
    	case VL53L1_WARNING_ZONE_CAL_MISSING_SAMPLES:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_ZONE_CAL_MISSING_SAMPLES);
    		break;
    	case VL53L1_WARNING_ZONE_CAL_SIGMA_TOO_HIGH:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_ZONE_CAL_SIGMA_TOO_HIGH);
    		break;
    	case VL53L1_WARNING_ZONE_CAL_RATE_TOO_HIGH:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_ZONE_CAL_RATE_TOO_HIGH);
    		break;
    
    	case VL53L1_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_REF_SPAD_CHAR_NOT_ENOUGH_SPADS);
    		break;
    	case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_HIGH);
    		break;
    	case VL53L1_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_WARNING_REF_SPAD_CHAR_RATE_TOO_LOW);
    		break;
    
    	case VL53L1_WARNING_XTALK_MISSING_SAMPLES:
    			VL53L1_COPYSTRING(pPalErrorString,
    				VL53L1_STRING_WARNING_XTALK_MISSING_SAMPLES);
    			break;
    	case VL53L1_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT:
    			VL53L1_COPYSTRING(pPalErrorString,
    				VL53L1_STRING_WARNING_XTALK_NO_SAMPLES_FOR_GRADIENT);
    			break;
    	case VL53L1_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT:
    			VL53L1_COPYSTRING(pPalErrorString,
    				VL53L1_STRING_WARNING_XTALK_SIGMA_LIMIT_FOR_GRADIENT);
    			break;
    
    	case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_OLD:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_OLD);
    		break;
    	case VL53L1_ERROR_DEVICE_FIRMWARE_TOO_NEW:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_DEVICE_FIRMWARE_TOO_NEW);
    		break;
    	case VL53L1_ERROR_UNIT_TEST_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_UNIT_TEST_FAIL);
    		break;
    	case VL53L1_ERROR_FILE_READ_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_FILE_READ_FAIL);
    		break;
    	case VL53L1_ERROR_FILE_WRITE_FAIL:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_FILE_WRITE_FAIL);
    		break;
    	case VL53L1_ERROR_NOT_IMPLEMENTED:
    		VL53L1_COPYSTRING(pPalErrorString,
    			VL53L1_STRING_ERROR_NOT_IMPLEMENTED);
    		break;
    	default:
    		VL53L1_COPYSTRING(pPalErrorString,
    				VL53L1_STRING_UNKNOW_ERROR_CODE);
    	}
    
    #endif
    
    	LOG_FUNCTION_END(Status);
    
    	return Status;
    }
    
    vl53l1_error_strings.hvl53l1_ll_def.hvl53l1_ll_device.hvl53l1_nvm_map.hvl53l1_preset_setup.hvl53l1_register_funcs.cvl53l1_register_funcs.hvl53l1_register_map.hvl53l1_register_settings.hvl53l1_register_structs.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file  vl53l1_silicon_core.c
     *
     * @brief EwokPlus25 low level silicon LL Driver function definition
     */
    
    
    #include "vl53l1_ll_def.h"
    #include "vl53l1_platform.h"
    #include "vl53l1_register_map.h"
    #include "vl53l1_core.h"
    #include "vl53l1_silicon_core.h"
    
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, fmt, ##__VA_ARGS__)
    
    
    VL53L1_Error VL53L1_is_firmware_ready_silicon(
    	VL53L1_DEV     Dev,
    	uint8_t       *pready)
    {
    	/**
    	 * Determines if the firmware is ready to range
    	 *
    	 * There are 2 different behaviors depending on whether
    	 * power force is enabled or not
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t  comms_buffer[5];
    
    	LOG_FUNCTION_START("");
    
    	/* read interrupt and power force reset status */
    
    	status = VL53L1_ReadMulti(
    					Dev,
    					VL53L1_INTERRUPT_MANAGER__ENABLES,
    					comms_buffer,
    					5);
    
    	if (status == VL53L1_ERROR_NONE) {
    
    		pdev->dbg_results.interrupt_manager__enables =
    				comms_buffer[0];
    		pdev->dbg_results.interrupt_manager__clear =
    				comms_buffer[1];
    		pdev->dbg_results.interrupt_manager__status =
    				comms_buffer[2];
    		pdev->dbg_results.mcu_to_host_bank__wr_access_en =
    				comms_buffer[3];
    		pdev->dbg_results.power_management__go1_reset_status =
    				comms_buffer[4];
    
    		if ((pdev->sys_ctrl.power_management__go1_power_force & 0x01) == 0x01) {
    
    				if (((pdev->dbg_results.interrupt_manager__enables & 0x1F) == 0x1F) &&
    					((pdev->dbg_results.interrupt_manager__clear   & 0x1F) == 0x1F))
    					*pready = 0x01;
    				else
    					*pready = 0x00;
    
    		} else {
    
    			/* set ready flag if bit 0 is zero i.g G01 is in reset */
    			if ((pdev->dbg_results.power_management__go1_reset_status & 0x01) == 0x00)
    				*pready = 0x01;
    			else
    				*pready = 0x00;
    		}
    
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    vl53l1_silicon_core.hvl53l1_tuning_parm_defaults.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    /**
     * @file  vl53l1_wait.c
     *
     * @brief EwokPlus25 low level Driver wait function definition
     */
    
    
    #include "vl53l1_ll_def.h"
    #include "vl53l1_ll_device.h"
    #include "vl53l1_platform.h"
    #include "vl53l1_core.h"
    #include "vl53l1_silicon_core.h"
    #include "vl53l1_wait.h"
    #include "vl53l1_register_settings.h"
    
    
    #define LOG_FUNCTION_START(fmt, ...) \
    	_LOG_FUNCTION_START(VL53L1_TRACE_MODULE_CORE, fmt, ##__VA_ARGS__)
    #define LOG_FUNCTION_END(status, ...) \
    	_LOG_FUNCTION_END(VL53L1_TRACE_MODULE_CORE, status, ##__VA_ARGS__)
    #define LOG_FUNCTION_END_FMT(status, fmt, ...) \
    	_LOG_FUNCTION_END_FMT(VL53L1_TRACE_MODULE_CORE, status, \
    		fmt, ##__VA_ARGS__)
    
    
    VL53L1_Error VL53L1_wait_for_boot_completion(
    	VL53L1_DEV     Dev)
    {
    
    	/* Waits for firmware boot to finish
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t      fw_ready  = 0;
    
    	LOG_FUNCTION_START("");
    
    	if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) {
    
    		/* blocking version */
    
    		status =
    			VL53L1_poll_for_boot_completion(
    				Dev,
    				VL53L1_BOOT_COMPLETION_POLLING_TIMEOUT_MS);
    
    	} else {
    
    		/* implement non blocking version below */
    
    		fw_ready = 0;
    		while (fw_ready == 0x00 && status == VL53L1_ERROR_NONE) {
    			status = VL53L1_is_boot_complete(
    				Dev,
    				&fw_ready);
    
    			if (status == VL53L1_ERROR_NONE) {
    				status = VL53L1_WaitMs(
    					Dev,
    					VL53L1_POLLING_DELAY_MS);
    			}
    		}
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    
    }
    
    
    VL53L1_Error VL53L1_wait_for_firmware_ready(
    	VL53L1_DEV     Dev)
    {
    
    	/* If in timed mode or single shot then check firmware is ready
    	 * before sending handshake
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t      fw_ready  = 0;
    	uint8_t      mode_start  = 0;
    
    	LOG_FUNCTION_START("");
    
    	/* Filter out tje measure mode part of the mode
    	 * start register
    	 */
    	mode_start =
    		pdev->sys_ctrl.system__mode_start &
    		VL53L1_DEVICEMEASUREMENTMODE_MODE_MASK;
    
    	/*
    	 * conditional wait for firmware ready
    	 * only waits for timed and single shot modes
    	 */
    
    	if ((mode_start == VL53L1_DEVICEMEASUREMENTMODE_TIMED) ||
    		(mode_start == VL53L1_DEVICEMEASUREMENTMODE_SINGLESHOT)) {
    
    		if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) {
    
    			/* blocking version */
    
    			status =
    				VL53L1_poll_for_firmware_ready(
    					Dev,
    					VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS);
    
    		} else {
    
    			/* implement non blocking version below */
    
    			fw_ready = 0;
    			while (fw_ready == 0x00 && status == VL53L1_ERROR_NONE) {
    				status = VL53L1_is_firmware_ready(
    					Dev,
    					&fw_ready);
    
    				if (status == VL53L1_ERROR_NONE) {
    					status = VL53L1_WaitMs(
    						Dev,
    						VL53L1_POLLING_DELAY_MS);
    				}
    			}
    		}
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_wait_for_range_completion(
    	VL53L1_DEV     Dev)
    {
    
    	/* Wrapper function for waiting for range completion
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t      data_ready  = 0;
    
    	LOG_FUNCTION_START("");
    
    	if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) {
    
    		/* blocking version */
    
    		status =
    			VL53L1_poll_for_range_completion(
    				Dev,
    				VL53L1_RANGE_COMPLETION_POLLING_TIMEOUT_MS);
    
    	} else {
    
    		/* implement non blocking version below */
    
    		data_ready = 0;
    		while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) {
    			status = VL53L1_is_new_data_ready(
    				Dev,
    				&data_ready);
    
    			if (status == VL53L1_ERROR_NONE) {
    				status = VL53L1_WaitMs(
    					Dev,
    					VL53L1_POLLING_DELAY_MS);
    			}
    		}
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_wait_for_test_completion(
    	VL53L1_DEV     Dev)
    {
    
    	/* Wrapper function for waiting for test mode completion
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t      data_ready  = 0;
    
    	LOG_FUNCTION_START("");
    
    	if (pdev->wait_method == VL53L1_WAIT_METHOD_BLOCKING) {
    
    		/* blocking version */
    
    		status =
    			VL53L1_poll_for_range_completion(
    				Dev,
    				VL53L1_TEST_COMPLETION_POLLING_TIMEOUT_MS);
    
    	} else {
    
    		/* implement non blocking version below */
    
    		data_ready = 0;
    		while (data_ready == 0x00 && status == VL53L1_ERROR_NONE) {
    			status = VL53L1_is_new_data_ready(
    				Dev,
    				&data_ready);
    
    			if (status == VL53L1_ERROR_NONE) {
    				status = VL53L1_WaitMs(
    					Dev,
    					VL53L1_POLLING_DELAY_MS);
    			}
    		}
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    
    
    VL53L1_Error VL53L1_is_boot_complete(
    	VL53L1_DEV     Dev,
    	uint8_t       *pready)
    {
    	/**
    	 * Determines if the firmware finished booting by reading
    	 * bit 0 of firmware__system_status register
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	uint8_t  firmware__system_status = 0;
    
    	LOG_FUNCTION_START("");
    
    	/* read current range interrupt state */
    
    	status =
    		VL53L1_RdByte(
    			Dev,
    			VL53L1_FIRMWARE__SYSTEM_STATUS,
    			&firmware__system_status);
    
    	/* set *pready = 1 if new range data ready complete
    	 * zero otherwise
    	 */
    
    	if ((firmware__system_status & 0x01) == 0x01) {
    		*pready = 0x01;
    		VL53L1_init_ll_driver_state(
    			Dev,
    			VL53L1_DEVICESTATE_SW_STANDBY);
    	} else {
    		*pready = 0x00;
    		VL53L1_init_ll_driver_state(
    			Dev,
    			VL53L1_DEVICESTATE_FW_COLDBOOT);
    	}
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_is_firmware_ready(
    	VL53L1_DEV     Dev,
    	uint8_t       *pready)
    {
    	/**
    	 * Determines if the firmware is ready to range
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	LOG_FUNCTION_START("");
    
    	status = VL53L1_is_firmware_ready_silicon(
    					Dev,
    					pready);
    
    	pdev->fw_ready = *pready;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_is_new_data_ready(
    	VL53L1_DEV     Dev,
    	uint8_t       *pready)
    {
    	/**
    	 * Determines if new range data is ready by reading bit 0 of
    	 * VL53L1_GPIO__TIO_HV_STATUS to determine the current state
    	 * of output interrupt pin
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t  gpio__mux_active_high_hv = 0;
    	uint8_t  gpio__tio_hv_status      = 0;
    	uint8_t  interrupt_ready          = 0;
    
    	LOG_FUNCTION_START("");
    
    	gpio__mux_active_high_hv =
    			pdev->stat_cfg.gpio_hv_mux__ctrl &
    			VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK;
    
    	if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH)
    		interrupt_ready = 0x01;
    	else
    		interrupt_ready = 0x00;
    
    	/* read current range interrupt state */
    
    	status = VL53L1_RdByte(
    					Dev,
    					VL53L1_GPIO__TIO_HV_STATUS,
    					&gpio__tio_hv_status);
    
    	/* set *pready = 1 if new range data ready complete zero otherwise */
    
    	if ((gpio__tio_hv_status & 0x01) == interrupt_ready)
    		*pready = 0x01;
    	else
    		*pready = 0x00;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    
    
    VL53L1_Error VL53L1_poll_for_boot_completion(
    	VL53L1_DEV    Dev,
    	uint32_t      timeout_ms)
    {
    	/**
    	 * Polls the bit 0 of the FIRMWARE__SYSTEM_STATUS register to see if
    	 * the firmware is ready.
    	 */
    
    	VL53L1_Error status       = VL53L1_ERROR_NONE;
    
    	LOG_FUNCTION_START("");
    
    	/* after reset for the firmware blocks I2C access while
    	 * it copies the NVM data into the G02 host register banks
    	 * The host must wait the required time to allow the copy
    	 * to complete before attempting to read the firmware status
    	 */
    
    	status = VL53L1_WaitUs(
    			Dev,
    			VL53L1_FIRMWARE_BOOT_TIME_US);
    
    	if (status == VL53L1_ERROR_NONE)
    		status =
    			VL53L1_WaitValueMaskEx(
    				Dev,
    				timeout_ms,
    				VL53L1_FIRMWARE__SYSTEM_STATUS,
    				0x01,
    				0x01,
    				VL53L1_POLLING_DELAY_MS);
    
    	if (status == VL53L1_ERROR_NONE)
    		VL53L1_init_ll_driver_state(Dev, VL53L1_DEVICESTATE_SW_STANDBY);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_poll_for_firmware_ready(
    	VL53L1_DEV    Dev,
    	uint32_t      timeout_ms)
    {
    	/**
    	 * Polls the bit 0 of the FIRMWARE__SYSTEM_STATUS register to see if
    	 * the firmware is ready.
    	 */
    
    	VL53L1_Error status          = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint32_t     start_time_ms   = 0;
    	uint32_t     current_time_ms = 0;
    	int32_t      poll_delay_ms   = VL53L1_POLLING_DELAY_MS;
    	uint8_t      fw_ready        = 0;
    
    	/* calculate time limit in absolute time */
    
    	VL53L1_GetTickCount(&start_time_ms); /*lint !e534 ignoring return*/
    	pdev->fw_ready_poll_duration_ms = 0;
    
    	/* wait until firmware is ready, timeout reached on error occurred */
    
    	while ((status == VL53L1_ERROR_NONE) &&
    		   (pdev->fw_ready_poll_duration_ms < timeout_ms) &&
    		   (fw_ready == 0)) {
    
    		status = VL53L1_is_firmware_ready(
    			Dev,
    			&fw_ready);
    
    		if (status == VL53L1_ERROR_NONE &&
    			fw_ready == 0 &&
    			poll_delay_ms > 0) {
    			status = VL53L1_WaitMs(
    				Dev,
    				poll_delay_ms);
    		}
    
    		/*
    		 * Update polling time (Compare difference rather than
    		 * absolute to negate 32bit wrap around issue)
    		 */
    		VL53L1_GetTickCount(&current_time_ms);  /*lint !e534 ignoring return*/
    		pdev->fw_ready_poll_duration_ms =
    				current_time_ms - start_time_ms;
    	}
    
    	if (fw_ready == 0 && status == VL53L1_ERROR_NONE)
    		status = VL53L1_ERROR_TIME_OUT;
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    VL53L1_Error VL53L1_poll_for_range_completion(
    	VL53L1_DEV     Dev,
    	uint32_t       timeout_ms)
    {
    	/**
    	 * Polls bit 0 of VL53L1_GPIO__TIO_HV_STATUS to determine
    	 * the state of output interrupt pin
    	 *
    	 * Interrupt may be either active high or active low. Use active_high to
    	 * select the required level check
    	 */
    
    	VL53L1_Error status = VL53L1_ERROR_NONE;
    	VL53L1_LLDriverData_t *pdev = VL53L1DevStructGetLLDriverHandle(Dev);
    
    	uint8_t  gpio__mux_active_high_hv = 0;
    	uint8_t  interrupt_ready          = 0;
    
    	LOG_FUNCTION_START("");
    
    	gpio__mux_active_high_hv =
    			pdev->stat_cfg.gpio_hv_mux__ctrl &
    			VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_MASK;
    
    	if (gpio__mux_active_high_hv == VL53L1_DEVICEINTERRUPTLEVEL_ACTIVE_HIGH)
    		interrupt_ready = 0x01;
    	else
    		interrupt_ready = 0x00;
    
    	status =
    		VL53L1_WaitValueMaskEx(
    			Dev,
    			timeout_ms,
    			VL53L1_GPIO__TIO_HV_STATUS,
    			interrupt_ready,
    			0x01,
    			VL53L1_POLLING_DELAY_MS);
    
    	LOG_FUNCTION_END(status);
    
    	return status;
    }
    
    
    vl53l1_wait.h
    /*
    * Copyright (c) 2017, STMicroelectronics - All Rights Reserved
    *
    * This file is part of VL53L1 Core and is dual licensed,
    * either 'STMicroelectronics
    * Proprietary license'
    * or 'BSD 3-clause "New" or "Revised" License' , at your option.
    *
    ********************************************************************************
    *
    * 'STMicroelectronics Proprietary license'
    *
    ********************************************************************************
    *
    * License terms: STMicroelectronics Proprietary in accordance with licensing
    * terms at www.st.com/sla0081
    *
    * STMicroelectronics confidential
    * Reproduction and Communication of this document is strictly prohibited unless
    * specifically authorized in writing by STMicroelectronics.
    *
    *
    ********************************************************************************
    *
    * Alternatively, VL53L1 Core may be distributed under the terms of
    * 'BSD 3-clause "New" or "Revised" License', in which case the following
    * provisions apply instead of the ones mentioned above :
    *
    ********************************************************************************
    *
    * License terms: BSD 3-clause "New" or "Revised" License.
    *
    * Redistribution and use in source and binary forms, with or without
    * modification, are permitted provided that the following conditions are met:
    *
    * 1. Redistributions of source code must retain the above copyright notice, this
    * list of conditions and the following disclaimer.
    *
    * 2. Redistributions in binary form must reproduce the above copyright notice,
    * this list of conditions and the following disclaimer in the documentation
    * and/or other materials provided with the distribution.
    *
    * 3. Neither the name of the copyright holder nor the names of its contributors
    * may be used to endorse or promote products derived from this software
    * without specific prior written permission.
    *
    * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
    * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
    * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
    * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    *
    *
    ********************************************************************************
    *
    */
    
    
    #include "vl53l1_platform.h"
    // #include "vl53l1_platform_log.h"
    #include "vl53l1_api.h"
    
    // #include "stm32xxx_hal.h"
    #include <string.h>
    // #include <time.h>
    // #include <math.h>
    
    
    // #define I2C_TIME_OUT_BASE   10
    // #define I2C_TIME_OUT_BYTE   1
    
    // #ifdef VL53L1_LOG_ENABLE
    // #define trace_print(level, ...) VL53L1_trace_print_module_function(VL53L1_TRACE_MODULE_PLATFORM, level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__)
    // #define trace_i2c(...) VL53L1_trace_print_module_function(VL53L1_TRACE_MODULE_NONE, VL53L1_TRACE_LEVEL_NONE, VL53L1_TRACE_FUNCTION_I2C, ##__VA_ARGS__)
    // #endif
    
    // #ifndef HAL_I2C_MODULE_ENABLED
    // #warning "HAL I2C module must be enable "
    // #endif
    
    //extern I2C_HandleTypeDef hi2c1;
    //#define VL53L0X_pI2cHandle    (&hi2c1)
    
    /* when not customized by application define dummy one */
    // #ifndef VL53L1_GetI2cBus
    /** This macro can be overloaded by user to enforce i2c sharing in RTOS context
     */
    // #   define VL53L1_GetI2cBus(...) (void)0
    // #endif
    
    // #ifndef VL53L1_PutI2cBus
    /** This macro can be overloaded by user to enforce i2c sharing in RTOS context
     */
    // #   define VL53L1_PutI2cBus(...) (void)0
    // #endif
    
    // uint8_t _I2CBuffer[256];
    
    // int _I2CWrite(VL53L1_DEV Dev, uint8_t *pdata, uint32_t count) {
    //     int status = 0;
    //     return status;
    // }
    
    // int _I2CRead(VL53L1_DEV Dev, uint8_t *pdata, uint32_t count) {
    //    int status = 0;
    //    return Status;
    // }
    
    VL53L1_Error VL53L1_WriteMulti(VL53L1_DEV Dev, uint16_t index, uint8_t *pdata, uint32_t count) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    // the ranging_sensor_comms.dll will take care of the page selection
    VL53L1_Error VL53L1_ReadMulti(VL53L1_DEV Dev, uint16_t index, uint8_t *pdata, uint32_t count) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    VL53L1_Error VL53L1_WrByte(VL53L1_DEV Dev, uint16_t index, uint8_t data) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    VL53L1_Error VL53L1_WrWord(VL53L1_DEV Dev, uint16_t index, uint16_t data) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    VL53L1_Error VL53L1_WrDWord(VL53L1_DEV Dev, uint16_t index, uint32_t data) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    VL53L1_Error VL53L1_UpdateByte(VL53L1_DEV Dev, uint16_t index, uint8_t AndData, uint8_t OrData) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    VL53L1_Error VL53L1_RdByte(VL53L1_DEV Dev, uint16_t index, uint8_t *data) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    VL53L1_Error VL53L1_RdWord(VL53L1_DEV Dev, uint16_t index, uint16_t *data) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    VL53L1_Error VL53L1_RdDWord(VL53L1_DEV Dev, uint16_t index, uint32_t *data) {
        VL53L1_Error Status = VL53L1_ERROR_NONE;
        return Status;
    }
    
    VL53L1_Error VL53L1_GetTickCount(
    	uint32_t *ptick_count_ms)
    {
    	VL53L1_Error status  = VL53L1_ERROR_NONE;
    	return status;
    }
    
    //#define trace_print(level, ...) \
    //	_LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_PLATFORM, \
    //	level, VL53L1_TRACE_FUNCTION_NONE, ##__VA_ARGS__)
    
    //#define trace_i2c(...) \
    //	_LOG_TRACE_PRINT(VL53L1_TRACE_MODULE_NONE, \
    //	VL53L1_TRACE_LEVEL_NONE, VL53L1_TRACE_FUNCTION_I2C, ##__VA_ARGS__)
    
    VL53L1_Error VL53L1_GetTimerFrequency(int32_t *ptimer_freq_hz)
    {
    	VL53L1_Error status  = VL53L1_ERROR_NONE;
    	return status;
    }
    
    VL53L1_Error VL53L1_WaitMs(VL53L1_Dev_t *pdev, int32_t wait_ms){
    	VL53L1_Error status  = VL53L1_ERROR_NONE;
    	return status;
    }
    
    VL53L1_Error VL53L1_WaitUs(VL53L1_Dev_t *pdev, int32_t wait_us){
    	VL53L1_Error status  = VL53L1_ERROR_NONE;
    	return status;
    }
    
    VL53L1_Error VL53L1_WaitValueMaskEx(
    	VL53L1_Dev_t *pdev,
    	uint32_t      timeout_ms,
    	uint16_t      index,
    	uint8_t       value,
    	uint8_t       mask,
    	uint32_t      poll_delay_ms)
    {
    	VL53L1_Error status  = VL53L1_ERROR_NONE;
    	return status;
    }
    
    
    
    
    

    vl53l1_platform.hvl53l1_platform_log.h

    vl53l1_platform_user_config.hvl53l1_platform_user_data.h

    vl53l1_platform_user_defines.hvl53l1_types.h

    3. Resistor value is from R1-R4 is 20k.

    4. Please refer to the attached diagram. same connection configurations are working with ESP32.

    5. Please refer to the attached library and help us with the TWI communication with the TOF sensor (VL53L1X).

    Best regards,

    Shubham

  • Hello again, Shubham

    Thank you for providing the drivers.
    As mentioned I do not expect this to stem from a logical error in the officially supplied drivers, but it could stem from a mismatch in configuration. In your diagram you are using external pullup resistors. The nrfx TWI driver enables internal pullups by default. Have you disabled the internal pullups, since you are using external ones?
    Please see these questions from my previous comment:

    ShubMane said:
    4. Please refer to the attached diagram. same connection configurations are working with ESP32.
    Karl Ylvisaker said:
    Which pins are you using for this on the nRF52832?

    Exactly which pins on the nRF device are you trying to use for your TWI peripheral? Your drawing does not include this information.

    Karl Ylvisaker said:
    Do you have access to a logic analyzer, so we could take a look at what might be happening on the lines?


    Please answer these questions so we may proceed with the debugging of your issue. 

    Best regards,
    Karl

  • Hello Karl,

    Suspecting that we had been found the issue regarding the I2C communication of the vl53l1x.

    please refer to the image. (I2C) the frame format of VL53L1x.

    Address length size is about to be 16 bit with the separation of the MSB[15:8] and LSB[7:0]. so we have seen the TWI driver regarding that, files are "nrf_drv_twi.h" and "nrf_drv_twi.c" files. so in the TWI driver, only 8 bits of data were allowed to be passed within them

    might be this is an issue that happens for the I2C communication. because we had even checked all the external sensor drivers that are provided in the SDK for example HTS221 the address length size is 8 bit.

    we had an interface with the hts221 with vl53l1x on TWI bus. hts221 is workingly fine but vl53l1x is not working fine.

    The nrfx TWI driver was also enabled even we had that also checked.

    please check for the issue and let us know. please refer to the I2C frame format of VL53L1X.

    because all the external sensor drivers provided in SDK having the register's address length is 8 bit.

  • Hello Karl,

    In the above, I am talking about the internal register's address length of the sensors for reading and writing in them. and not about the slave address.

Reply Children
  • Hello Karl,

    For resolving the issue, can we have some options like multiple read or write???

  • Hello again,

    ShubMane said:
    we had an interface with the hts221 with vl53l1x on TWI bus. hts221 is workingly fine but vl53l1x is not working fine.

    Are you saying that you connected the HTS221 in the exact same way as you have tried connecting the VL53l1X, and was able to communicate with it as expected?

    ShubMane said:
    because all the external sensor drivers provided in SDK having the register's address length is 8 bit.

    All TWI addresses are 7 bit, with the 8th bit of the byte indicating whether it is a read or a write command for the 7 bit address. Sometimes, this is concatinated into a single address, such as WHO_AM_I_READ or similar. All TWI addresses are 7 bit as per the specification.

    ShubMane said:
    For resolving the issue, can we have some options like multiple read or write???

    Sure, you can do multiple reads or writes in the same transaction if you would like (no STOP between reads, for example). You can do this by using the nrfx_twi_xfer with the SUSPEND flag.

    I repeat myself because it would be very helpful to know for the continued debugging of this case:

    Karl Ylvisaker said:
    Karl Ylvisaker said:
    Which pins are you using for this on the nRF52832?

    Exactly which pins on the nRF device are you trying to use for your TWI peripheral? Your drawing does not include this information.

    Karl Ylvisaker said:
    Do you have access to a logic analyzer, so we could take a look at what might be happening on the lines?

    Please take a moment to answer these questions.

    Best regards,
    Karl

  • Hello Karl,

    How to enable the multiple writes as well as multiple reads in the TWI.

    if possible please send the example for multiple writes as well as multiple read.

  • Hello again,

    ShubMane said:
    How to enable the multiple writes as well as multiple reads in the TWI.

    By this, do you mean multiple reads or writes without a stop condition in between?
    If so, please see my mention of the SUSPEND flag in my previous comment.

    ShubMane said:
    if possible please send the example for multiple writes as well as multiple read.

    Unfortunately I do not have any example that demonstrate the use of the SUSPEND flag, but you could try it out by modifying the TWI sensor example, for instance.
    If you intend to do this, you will have to change the TWI0_USE_EASY_DMA define to 0, so that the example uses the TWI driver (that has the SUSPEND option) rather than the TWIM driver (that does not have the SUSPEND option) behind the scenes.

    Best regards,
    Karl

Related