Capteurs humidité-pression, Capteur de Luminosité / Distance

Capteurs humidité-pression, Capteur de Luminosité / Distance

Carte VL6180x : Capteur de Luminosité / Distance

VL6180x.jpg

X-NUCLEO-6180XA1.JPG

Rappels Bus I2C

Bloc Diagram P-NUCLEO-6180X1 Shield

bloc_diagram_vl6180x.svg

Datasheet VL6180x

Datasheet Shield ST P-NUCLEO-6180X1

Quick Start Guide Shield ST P-NUCLEO-6180X1

Driver VL6180x

vl6180x_def.h

/**
 * @file VL6180x_def.h
 *
 * @brief Type definitions for vl6180x api.
 *
 */


#ifndef _VL6180x_DEF
#define _VL6180x_DEF

/** API major version */
#define VL6180x_API_REV_MAJOR   3
/** API minor version */
#define VL6180x_API_REV_MINOR   2
/** API sub version */
#define VL6180x_API_REV_SUB     0

#define VL6180X_STR_HELPER(x) #x
#define VL6180X_STR(x) VL6180X_STR_HELPER(x)

#include "vl6180x_cfg.h"
#include "../../Inc/types.h"

/*
 * check configuration macro raise error or warning and suggest a default value
 */

#ifndef VL6180x_UPSCALE_SUPPORT
#error "VL6180x_UPSCALE_SUPPORT not defined"
/* TODO you must define value for  upscale support in your vl6180x_cfg.h  */
#endif

#ifndef VL6180x_ALS_SUPPORT
#error "VL6180x_ALS_SUPPORT not defined"
/* TODO you must define VL6180x_ALS_SUPPORT  with a value in your vl6180x_cfg.h  set to 0 do disable*/
#endif

#ifndef VL6180x_HAVE_DMAX_RANGING
#error "VL6180x_HAVE_DMAX_RANGING not defined"
/* TODO you may remove or comment these #error and keep the default below  or update your vl6180x_cfg.h .h file */
/**
 * force VL6180x_HAVE_DMAX_RANGING to not supported when not part of cfg file
 */
#define VL6180x_HAVE_DMAX_RANGING   0
#endif

#ifndef VL6180x_EXTENDED_RANGE
#define VL6180x_EXTENDED_RANGE   0
#endif

#ifndef VL6180x_WRAP_AROUND_FILTER_SUPPORT
#error "VL6180x_WRAP_AROUND_FILTER_SUPPORT not defined ?"
/* TODO you may remove or comment these #error and keep the default below  or update vl6180x_cfg.h file */
/**
 * force VL6180x_WRAP_AROUND_FILTER_SUPPORT to not supported when not part of cfg file
 */
#define VL6180x_WRAP_AROUND_FILTER_SUPPORT 0
#endif



#ifndef VL6180x_HAVE_MULTI_READ
#   define VL6180x_HAVE_MULTI_READ  0
#endif

/**
 * Force VL6180x_CACHED_REG to default 0 when not defined
 */
#ifndef VL6180x_CACHED_REG
#   define VL6180x_CACHED_REG  0
#else
#   define VL6180x_FIRST_CACHED_INDEX      0x04D
#   define VL6180x_LAST_CACHED_INDEX       (VL6180x_FIRST_CACHED_INDEX+55)
#   define VL6180x_CACHED_REG_CNT           (VL6180x_LAST_CACHED_INDEX-VL6180x_FIRST_CACHED_INDEX+1)
#endif

/****************************************
 * PRIVATE define do not edit
 ****************************************/

/** Maximal buffer size ever use in i2c */
#define VL6180x_MAX_I2C_XFER_SIZE   8 /* At present time it 6 byte max but that can change */

#if VL6180x_UPSCALE_SUPPORT < 0
/**
 * @def VL6180x_HAVE_UPSCALE_DATA
 * @brief  is defined if device data structure has data so when user configurable up-scale is active
 */
#define VL6180x_HAVE_UPSCALE_DATA /* have data only for user configurable up-scale config */
#endif

#if VL6180x_WRAP_AROUND_FILTER_SUPPORT
/**
 * @def VL6180x_HAVE_WRAP_AROUND_DATA
 * @brief  is defined if device data structure has filter data so when active in cfg file
 */
#define  VL6180x_HAVE_WRAP_AROUND_DATA
#endif

#if VL6180x_ALS_SUPPORT != 0
/**
 * @def  VL6180x_HAVE_ALS_DATA
 * @brief is defined when als data are include in device data structure so when als suport if configured
 */
#define VL6180x_HAVE_ALS_DATA
#endif


#if VL6180x_WRAP_AROUND_FILTER_SUPPORT || VL6180x_HAVE_DMAX_RANGING
	#define	VL6180x_HAVE_RATE_DATA
#endif

/** Error and warning code returned by API
 *
 * negative value are true error mostly fatal\n
 * positive value  are warning most of time it's ok to continue\n
 */
enum VL6180x_ErrCode_t {
	API_NO_ERROR        = 0,
	CALIBRATION_WARNING = 1,  /*!< warning invalid calibration data may be in used \a  VL6180x_InitData() \a VL6180x_GetOffsetCalibrationData \a VL6180x_SetOffsetCalibrationData*/
	MIN_CLIPED          = 2,  /*!< warning parameter passed was clipped to min before to be applied */
	NOT_GUARANTEED      = 3,  /*!< Correct operation is not guaranteed typically using extended ranging on vl6180x */

	API_ERROR      = -1,    /*!< Unqualified error */
	INVALID_PARAMS = -2,    /*!< parameter passed is invalid or out of range */
	NOT_SUPPORTED  = -3,    /*!< function is not supported in current mode or configuration */
	RANGE_ERROR    = -4,    /*!< device report a ranging error interrupt status */
	TIME_OUT       = -5,    /*!< aborted due to time out */
};

/**
 * Filtered result data structure  range data is to be used
 */
typedef struct RangeFilterResult_tag {
	uint16_t range_mm;      /*!< Filtered ranging value */
	uint16_t rawRange_mm;   /*!< raw range value (scaled) */
	uint32_t filterError;   /*!< current filter error code */
} RangeFilterResult_t;

/**
 * "small" unsigned data type used in filter
 *
 * if data space saving is not a concern it can be change to platform native unsigned int
 */
typedef uint32_t  FilterType1_t;

/**
 * @def FILTER_NBOF_SAMPLES
 * @brief sample history len used for wrap around filtering
 */
#define FILTER_NBOF_SAMPLES             10
/**
 * Wrap around filter internal data
 */
struct FilterData_t {
	uint32_t MeasurementIndex;                      /*!< current measurement index */
	uint32_t MeasurementsSinceLastFlush;            /*!< Number of measurements done since last time buffer has been flushed */
	uint16_t LastTrueRange[FILTER_NBOF_SAMPLES];    /*!< filtered/corrected  distance history */
	uint32_t LastReturnRates[FILTER_NBOF_SAMPLES];  /*!< Return rate history */
	uint16_t StdFilteredReads;                      /*!< internal use */
	FilterType1_t Default_ZeroVal;                  /*!< internal use */
	FilterType1_t Default_VAVGVal;                  /*!< internal use */
	FilterType1_t NoDelay_ZeroVal;                  /*!< internal use */
	FilterType1_t NoDelay_VAVGVal;                  /*!< internal use */
	FilterType1_t Previous_VAVGDiff;                /*!< internal use */
	uint32_t FilteringOnGoingConsecutiveStates;    /*!< internal use */
	uint32_t filterError;                           /*!< current filter error code */
};

#if  VL6180x_HAVE_DMAX_RANGING
typedef int32_t DMaxFix_t;
struct DMaxData_t {
	uint32_t ambTuningWindowFactor_K; /*!<  internal algo tuning (*1000) */

	DMaxFix_t retSignalAt400mm;  /*!< intermediate dmax computation value caching @a #SYSRANGE_CROSSTALK_COMPENSATION_RATE and private reg 0x02A */
    /* int32_t RegB8; */             /*!< register 0xB8 cached to speed reduce i2c traffic for dmax computation */
    /* place all word data below to optimize struct packing */
    /* int32_t minSignalNeeded; */    /*!< optimized computation intermediate base on register cached value */
	int32_t snrLimit_K;         /*!< cached and optimized computation intermediate from  @a #SYSRANGE_MAX_AMBIENT_LEVEL_MULT */
	uint16_t ClipSnrLimit;      /*!< Max value for snr limit */
    /* place all byte data below to optimize packing */
    /* uint8_t MaxConvTime; */        /*!< cached max convergence time @a #SYSRANGE_MAX_CONVERGENCE_TIME*/
};
#endif

struct RangeIgnoreData_t {
	uint16_t ValidHeight;
	uint16_t IgnoreThreshold;
	uint8_t Enabled;
};
/**
 * @struct VL6180xDevData_t
 *
 * @brief Per VL6180x device St private data structure \n
 * End user should never access any of these field directly
 *
 * These must never access directly but only via VL6180xDev/SetData(dev, field) macro
 */
struct VL6180xDevData_t {

	uint32_t Part2PartAmbNVM;  /*!< backed up NVM value */
	uint32_t XTalkCompRate_KCps; /*! Cached XTlak Compensation Rate */

	uint16_t EceFactorM;        /*!< Ece Factor M numerator  */
	uint16_t EceFactorD;        /*!< Ece Factor D denominator*/

	struct RangeIgnoreData_t RangeIgnore;

#ifdef VL6180x_HAVE_ALS_DATA
	uint16_t IntegrationPeriod; /*!< cached als Integration period avoid slow read from device at each measure */
	uint16_t AlsGainCode;       /*!< cached Als gain avoid slow read from device at each measure */
	uint16_t AlsScaler;         /*!< cached Als scaler avoid slow read from device at each measure */
#endif

#ifdef VL6180x_HAVE_UPSCALE_DATA
	uint8_t UpscaleFactor;      /*!<  up-scaling factor*/
#endif

#ifdef VL6180x_HAVE_WRAP_AROUND_DATA
	uint8_t WrapAroundFilterActive; /*!< Filter on/off */
	struct FilterData_t FilterData; /*!< Filter internal data state history ... */
#endif

#if VL6180x_CACHED_REG
	uint8_t CacheFilled;             /*!< Set if valid data got fetched use to control when to fill up register cache */
	uint8_t CachedRegs[VL6180x_CACHED_REG_CNT];          /*!< Cache register storage */
#endif
#if VL6180x_HAVE_DMAX_RANGING
	struct DMaxData_t DMaxData;
	uint8_t DMaxEnable;
#endif
	int8_t  Part2PartOffsetNVM;     /*!< backed up NVM value */
};


/**
 * @struct VL6180x_RangeData_t
 * @brief Range and any optional measurement data.
 */
typedef struct {
	int32_t range_mm;          /*!< range distance in mm. */
	int32_t signalRate_mcps;   /*!< signal rate (MCPS)\n these is a 9.7 fix point value, which is effectively a measure of target reflectance.*/
	uint32_t errorStatus;      /*!< Error status of the current measurement. \n see @a ::RangeError_u @a VL6180x_GetRangeStatusErrString() */


#ifdef VL6180x_HAVE_RATE_DATA
	uint32_t rtnAmbRate;    /*!< Return Ambient rate in KCount per sec related to \a RESULT_RANGE_RETURN_AMB_COUNT */
	uint32_t rtnRate;       /*!< Return rate in KCount per sec  related to \a RESULT_RANGE_RETURN_SIGNAL_COUNT  */
	uint32_t rtnConvTime;   /*!< Return Convergence time \a RESULT_RANGE_RETURN_CONV_TIME */
	uint32_t refConvTime;   /*!< Reference convergence time \a RESULT_RANGE_REFERENCE_CONV_TIME */
#endif


#if VL6180x_HAVE_DMAX_RANGING
	uint32_t DMax;              /*!< DMax  when applicable */
#endif

#ifdef VL6180x_HAVE_WRAP_AROUND_DATA
	RangeFilterResult_t FilteredData; /*!< Filter result main range_mm is updated */
#endif
} VL6180x_RangeData_t;


/** use where fix point 9.7 bit values are expected
 *
 * given a floating point value f it's .7 bit point is (int)(f*(1<<7))*/
typedef uint16_t FixPoint97_t;

/** lux data type */
typedef uint32_t lux_t;

/**
 * @brief This data type defines als  measurement data.
 */
typedef struct VL6180x_AlsData_st {
	lux_t lux;                 /**< Light measurement (Lux) */
	uint32_t errorStatus;      /**< Error status of the current measurement. \n
	* No Error := 0. \n
	* Refer to product sheets for other error codes. */
} VL6180x_AlsData_t;

/**
 * @brief Range status Error code
 *
 * @a VL6180x_GetRangeStatusErrString() if configured ( @a #VL6180x_RANGE_STATUS_ERRSTRING )
 * related to register @a #RESULT_RANGE_STATUS and additional post processing
 */
typedef enum {
	NoError = 0,               /*!< 0  0b0000 NoError  */
	VCSEL_Continuity_Test,     /*!< 1  0b0001 VCSEL_Continuity_Test */
	VCSEL_Watchdog_Test,       /*!< 2  0b0010 VCSEL_Watchdog_Test */
	VCSEL_Watchdog,            /*!< 3  0b0011 VCSEL_Watchdog */
	PLL1_Lock,                 /*!< 4  0b0100 PLL1_Lock */
	PLL2_Lock,                 /*!< 5  0b0101 PLL2_Lock */
	Early_Convergence_Estimate,/*!< 6  0b0110 Early_Convergence_Estimate */
	Max_Convergence,           /*!< 7  0b0111 Max_Convergence */
	No_Target_Ignore,          /*!< 8  0b1000 No_Target_Ignore */
	Not_used_9,                /*!< 9  0b1001 Not_used */
	Not_used_10,               /*!< 10 0b1010 Not_used_ */
	Max_Signal_To_Noise_Ratio, /*!< 11 0b1011 Max_Signal_To_Noise_Ratio*/
	Raw_Ranging_Algo_Underflow,/*!< 12 0b1100 Raw_Ranging_Algo_Underflow*/
	Raw_Ranging_Algo_Overflow, /*!< 13 0b1101 Raw_Ranging_Algo_Overflow */
	Ranging_Algo_Underflow,    /*!< 14 0b1110 Ranging_Algo_Underflow */
	Ranging_Algo_Overflow,     /*!< 15 0b1111 Ranging_Algo_Overflow */

	/* code below are addition for API/software side they are not hardware*/
	RangingFiltered = 0x10,     /*!< 16 0b10000 filtered by post processing*/
	DataNotReady = 0x12,             /*!< 18 0b10011 New data sample not ready */

} RangeError_u;


/** @defgroup device_regdef Device registers & masks definitions
 *  @brief    Device registers and masks definitions
 */


/** @ingroup device_regdef
 * @{*/

/**
 * The device model ID
 */
#define IDENTIFICATION_MODEL_ID                 0x000
/**
 * Revision identifier of the Device for major change.
 */
#define IDENTIFICATION_MODULE_REV_MAJOR         0x003
/**
 * Revision identifier of the Device for minor change.
 */
#define IDENTIFICATION_MODULE_REV_MINOR         0x004


/**
 * @def SYSTEM_MODE_GPIO0
 * @brief Configures polarity and select which function gpio 0 serves.
 *  Gpio0 is chip enable at power up ! Be aware of all h/w implication of turning it to output.
 *  Same definition as #SYSTEM_MODE_GPIO1
 * @ingroup device_regdef
 */
#define SYSTEM_MODE_GPIO0                       0x010
/**
 * @def SYSTEM_MODE_GPIO1
 * @brief Configures polarity and select what als or ranging functionality gpio pin serves.
 *
 * Function can be #GPIOx_SELECT_OFF  #GPIOx_SELECT_GPIO_INTERRUPT_OUTPUT.\n
 * Same definition apply to register GPIO0 that is used as chip enable at power up.
 * @ingroup device_regdef
 */
#define SYSTEM_MODE_GPIO1                       0x011
    /** gpio pad POLARITY mask in #SYSTEM_MODE_GPIO1 (and/or 0) write  1  to set active high polarity (positive edge) */
    #define GPIOx_POLARITY_SELECT_MASK              0x20
    /** gpio pad Function select shift in #SYSTEM_MODE_GPIO1 or 0 */
    #define GPIOx_FUNCTIONALITY_SELECT_SHIFT          1
    /** gpio pad Function select mask in #SYSTEM_MODE_GPIO1 or 0 */
    #define GPIOx_FUNCTIONALITY_SELECT_MASK          (0xF<<GPIOx_FUNCTIONALITY_SELECT_SHIFT)
    /** select no interrupt in #SYSTEM_MODE_GPIO1 pad is put in  Hi-Z*/
    #define GPIOx_SELECT_OFF                        0x00
    /** select gpiox as interrupt output in  #SYSTEM_MODE_GPIO1 */
    #define GPIOx_SELECT_GPIO_INTERRUPT_OUTPUT      0x08
    /** select range as source for interrupt on in #SYSTEM_MODE_GPIO1 */
    #define GPIOx_MODE_SELECT_RANGING               0x00
    /** select als as source for interrupt on in #SYSTEM_MODE_GPIO1 */
    #define GPIOx_MODE_SELECT_ALS                   0x01


/**
 * @def SYSTEM_INTERRUPT_CONFIG_GPIO
 *
 * @brief   Configure Als and Ranging interrupt reporting
 *
 * Possible values for Range and ALS are\n
 *
 * #CONFIG_GPIO_INTERRUPT_DISABLED\n
 * #CONFIG_GPIO_INTERRUPT_LEVEL_LOW\n
 * #CONFIG_GPIO_INTERRUPT_LEVEL_HIGH\n
 * #CONFIG_GPIO_INTERRUPT_OUT_OF_WINDOW\n
 * #CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY\n
 * Apply respective rang/als shift and mask \n
 *  #CONFIG_GPIO_RANGE_SHIFT and full reg mask #CONFIG_GPIO_RANGE_MASK\n
 *  #CONFIG_GPIO_ALS_SHIFT and full reg mask #CONFIG_GPIO_ALS_MASK\n
 *
 * \sa GPIO use for interrupt #SYSTEM_MODE_GPIO0 or #SYSTEM_MODE_GPIO1\n
 * @ingroup device_regdef
 */
#define SYSTEM_INTERRUPT_CONFIG_GPIO           0x014
    /** RANGE bits shift in #SYSTEM_INTERRUPT_CONFIG_GPIO */
    #define CONFIG_GPIO_RANGE_SHIFT            0
    /** RANGE bits mask in #SYSTEM_INTERRUPT_CONFIG_GPIO  (unshifted)*/
    #define CONFIG_GPIO_RANGE_MASK             (0x7<<CONFIG_GPIO_RANGE_SHIFT)
    /** ALS bits shift in #SYSTEM_INTERRUPT_CONFIG_GPIO */
    #define CONFIG_GPIO_ALS_SHIFT              3
    /** ALS bits mask in #SYSTEM_INTERRUPT_CONFIG_GPIO  (unshifted)*/
    #define CONFIG_GPIO_ALS_MASK               (0x7<<CONFIG_GPIO_ALS_SHIFT)
    /** interrupt is disabled */
    #define CONFIG_GPIO_INTERRUPT_DISABLED         0x00
    /** trigger when value < low threshold */
    #define CONFIG_GPIO_INTERRUPT_LEVEL_LOW        0x01
    /** trigger when value < low threshold */
    #define CONFIG_GPIO_INTERRUPT_LEVEL_HIGH       0x02
    /** trigger when outside range defined by high low threshold */
    #define CONFIG_GPIO_INTERRUPT_OUT_OF_WINDOW    0x03
    /** trigger when new sample are ready */
    #define CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY 0x04

/**
 *  @def SYSTEM_INTERRUPT_CLEAR
 *  @brief Writing to this register will clear interrupt source
 *
 *  Use or combination of any #INTERRUPT_CLEAR_RANGING , #INTERRUPT_CLEAR_ALS , #INTERRUPT_CLEAR_ERROR
 *  @ingroup device_regdef
 */
#define SYSTEM_INTERRUPT_CLEAR                0x015
    /** clear ranging interrupt in write to #SYSTEM_INTERRUPT_CLEAR */
    #define INTERRUPT_CLEAR_RANGING                0x01
    /** clear als interrupt  in write to #SYSTEM_INTERRUPT_CLEAR */
    #define INTERRUPT_CLEAR_ALS                    0x02
    /** clear error interrupt in write to #SYSTEM_INTERRUPT_CLEAR */
    #define INTERRUPT_CLEAR_ERROR                  0x04

/** After power up or reset this register will start reading 1 when device is ready */
#define SYSTEM_FRESH_OUT_OF_RESET             0x016

/**
 * @def SYSTEM_GROUPED_PARAMETER_HOLD
 * @brief Writing 1/0 activate/deactivate safe host update of multiple register in critical group \n
 *        rather use \a VL6180x_SetGroupParamHold()
 *
 * The critical register group is made of: \n
 * #SYSTEM_INTERRUPT_CONFIG_GPIO \n
 * #SYSRANGE_THRESH_HIGH \n
 * #SYSRANGE_THRESH_LOW \n
 * #SYSALS_INTEGRATION_PERIOD \n
 * #SYSALS_ANALOGUE_GAIN \n
 * #SYSALS_THRESH_HIGH \n
 * #SYSALS_THRESH_LOW
 * @ingroup device_regdef
 */
#define SYSTEM_GROUPED_PARAMETER_HOLD         0x017


/**
 * @def SYSRANGE_START
 * @brief Start/stop and set operating range mode
 *
 * Write Combination of #MODE_START_STOP  and #MODE_CONTINUOUS to select and start desired operation.
 *
 * @ingroup device_regdef
 */
#define SYSRANGE_START                        0x018
    /** mask existing bit in #SYSRANGE_START*/
    #define SYSRANGE_START_MODE_MASK          0x03
    /** bit 0 in #SYSRANGE_START write 1 toggle state in continuous mode and arm next shot in single shot mode */
    #define MODE_START_STOP                   0x01
    /** bit 1 write 1 in #SYSRANGE_START set continuous operation mode */
    #define MODE_CONTINUOUS                   0x02
    /** bit 1 write 0 in #SYSRANGE_START set single shot mode */
    #define MODE_SINGLESHOT                   0x00

/**
 * @def SYSRANGE_THRESH_HIGH
 * High level range  threshold (must be scaled)
 * @ingroup device_regdef
 */
#define SYSRANGE_THRESH_HIGH                  0x019

/**
 * @def SYSRANGE_THRESH_LOW
 * Low level range  threshold (must be scaled)
 * @ingroup device_regdef
 */
#define SYSRANGE_THRESH_LOW                   0x01A

/**
 * @def SYSRANGE_INTERMEASUREMENT_PERIOD
 * @brief Continuous mode intermeasurement delay \a VL6180x_RangeSetInterMeasPeriod()
 *
 * Time delay between measurements in Ranging continuous mode.\n
 * Range 0-254 (0 = 10ms).\n Step size = 10ms.
 *
 * @ingroup device_regdef
 */
#define SYSRANGE_INTERMEASUREMENT_PERIOD      0x01B

/**
 * @brief Maximum time to run measurement in Ranging modes.
 * Range 1 - 63 ms (1 code = 1 ms);
 *
 * Measurement aborted when limit reached to aid power  reduction.\
 * For example, 0x01 = 1ms, 0x0a = 10ms.\
 * Note: Effective max_convergence_time depends on readout_averaging_sample_period setting.
 *
 * @ingroup device_regdef
 */
#define SYSRANGE_MAX_CONVERGENCE_TIME         0x01C
/**@brief Cross talk compensation rate
 * @warning  never write register directly use @a VL6180x_SetXTalkCompensationRate()
 * refer to manual for calibration procedure and computation
 * @ingroup device_regdef
 */
#define SYSRANGE_CROSSTALK_COMPENSATION_RATE  0x01E
/**
 * @brief Minimum range value in mm to qualify for crosstalk compensation
 */
#define SYSRANGE_CROSSTALK_VALID_HEIGHT       0x021
#define SYSRANGE_EARLY_CONVERGENCE_ESTIMATE   0x022
#define SYSRANGE_PART_TO_PART_RANGE_OFFSET    0x024
/**
 * @brief range ignore valid height
 * @warning  do not program directly use @a VL6180x_RangeIgnoreConfigure() and @a VL6180x_RangeIgnoreSetEnable()
 */
#define SYSRANGE_RANGE_IGNORE_VALID_HEIGHT    0x025
/**
 * @brief range ignore threshold
 * @warning  do not program directly use @a VL6180x_RangeIgnoreConfigure() and @a VL6180x_RangeIgnoreSetEnable()
 */
#define SYSRANGE_RANGE_IGNORE_THRESHOLD       0x026
#define SYSRANGE_EMITTER_BLOCK_THRESHOLD      0x028
#define SYSRANGE_MAX_AMBIENT_LEVEL_THRESH     0x02A
#define SYSRANGE_MAX_AMBIENT_LEVEL_MULT       0x02C
/** @brief  various Enable check enable register
 *  @a VL6180x_RangeSetEceState()
 *  @a VL6180x_RangeIgnoreConfigure() and @a VL6180x_RangeIgnoreSetEnable()
 */
#define SYSRANGE_RANGE_CHECK_ENABLES          0x02D
    #define RANGE_CHECK_ECE_ENABLE_MASK      0x01
    #define RANGE_CHECK_RANGE_ENABLE_MASK    0x02
    #define RANGE_CHECK_SNR_ENABLE           0x10

#define SYSRANGE_VHV_RECALIBRATE              0x02E
#define SYSRANGE_VHV_REPEAT_RATE              0x031

/**
 * @def SYSALS_START
 * @brief Start/stop and set operating als mode
 *
 * same bit definition as range \a #SYSRANGE_START \n
 */
#define SYSALS_START                          0x038

/** ALS low Threshold high */
#define SYSALS_THRESH_HIGH                    0x03A
/** ALS low Threshold low */
#define SYSALS_THRESH_LOW                     0x03C
/** ALS intermeasurement period */
#define SYSALS_INTERMEASUREMENT_PERIOD        0x03E
/**
 * @warning or value with 0x40 when writing to these register*/
#define SYSALS_ANALOGUE_GAIN                  0x03F
/** ALS integration period */
#define SYSALS_INTEGRATION_PERIOD             0x040

/**
 * @brief Result range status
 *
 *  Hold the various range interrupt flags and error Specific error codes
 */
#define RESULT_RANGE_STATUS                   0x04D
    /** Device ready for new command bit 0*/
    #define RANGE_DEVICE_READY_MASK       0x01
    /** mask for error status covers bits [7:4]  in #RESULT_RANGE_STATUS @a ::RangeError_u */
    #define RANGE_ERROR_CODE_MASK         0xF0 /* */
    /** range error bit position in #RESULT_RANGE_STATUS */
    #define RANGE_ERROR_CODE_SHIFT        4

/**
 * @def RESULT_ALS_STATUS
 * @brief Result  als status \n
 *  Hold the various als interrupt flags and Specific error codes
 */
#define RESULT_ALS_STATUS                     0x4E
    /** Device ready for new command bit 0*/
   #define ALS_DEVICE_READY_MASK       0x01

/**
 * @def RESULT_ALS_VAL
 * @brief 16 Bit ALS count output value.
 *
 * Lux value depends on Gain and integration settings and calibrated lux/count setting
 * \a VL6180x_AlsGetLux() \a VL6180x_AlsGetMeasurement()
 */
#define RESULT_ALS_VAL                        0x50

/**
 * @def FW_ALS_RESULT_SCALER
 * @brief Als scaler register  Bits [3:0] analogue gain 1 to 16x
 * these register content is cached by API in \a VL6180xDevData_t::AlsScaler
 * for lux computation acceleration
 */
#define FW_ALS_RESULT_SCALER                  0x120


/**
 * these union can be use as a generic bit field type for map #RESULT_INTERRUPT_STATUS_GPIO register
 * @ingroup device_regdef
 */
typedef union IntrStatus_u {
	uint8_t val;           /*!< raw 8 bit register value*/
	struct  {
		unsigned Range:3; /*!< Range status one of :\n  \a #RES_INT_STAT_GPIO_LOW_LEVEL_THRESHOLD  \n \a #RES_INT_STAT_GPIO_HIGH_LEVEL_THRESHOLD  \n \a #RES_INT_STAT_GPIO_OUT_OF_WINDOW \n \a #RES_INT_STAT_GPIO_NEW_SAMPLE_READY */
		unsigned Als:3; /*!< Als status one of: \n \a #RES_INT_STAT_GPIO_LOW_LEVEL_THRESHOLD  \n \a #RES_INT_STAT_GPIO_HIGH_LEVEL_THRESHOLD  \n \a #RES_INT_STAT_GPIO_OUT_OF_WINDOW \n \a #RES_INT_STAT_GPIO_NEW_SAMPLE_READY  */
		unsigned Error:2; /*!<  Error status of: \n \a #RES_INT_ERROR_LASER_SAFETY  \n \a #RES_INT_ERROR_PLL */
	} status;                 /*!< interrupt status as bit field */
} IntrStatus_t;

/**
 * @def RESULT_INTERRUPT_STATUS_GPIO
 * @brief System interrupt status report selected interrupt for als and ranging
 *
 * These register can be polled even if no gpio pins is active\n
 * What reported is selected by \a  #SYSTEM_INTERRUPT_CONFIG_GPIO \n
 * Range mask with \a #RES_INT_RANGE_MASK and shit by \a #RES_INT_RANGE_SHIFT
 * Als   mask with \a #RES_INT_ALS_MASK and shit by \a #RES_INT_ALS_SHIFT
 * Result value express condition (or combination?)
 * \a #RES_INT_STAT_GPIO_LOW_LEVEL_THRESHOLD \n
 * \a #RES_INT_STAT_GPIO_HIGH_LEVEL_THRESHOLD \n
 * \a #RES_INT_STAT_GPIO_OUT_OF_WINDOW \n
 * \a #RES_INT_STAT_GPIO_NEW_SAMPLE_READY
 *
 * @ingroup device_regdef
 */
#define RESULT_INTERRUPT_STATUS_GPIO          0x4F
    /** ranging interrupt 1st bit position in #RESULT_INTERRUPT_STATUS_GPIO */
    #define RES_INT_RANGE_SHIFT  0
    /** ALS interrupt 1st bit position in #RESULT_INTERRUPT_STATUS_GPIO */
    #define RES_INT_ALS_SHIFT    3
    /** interrupt bit position in #RESULT_INTERRUPT_STATUS_GPIO */
    #define RES_INT_ERROR_SHIFT  6
    /** Ranging interrupt mask in #RESULT_INTERRUPT_STATUS_GPIO (prior to shift)  \sa IntrStatus_t */
    #define RES_INT_RANGE_MASK (0x7<<RES_INT_RANGE_SHIFT)
    /** als interrupt mask in #RESULT_INTERRUPT_STATUS_GPIO (prior to shift)  \sa IntrStatus_t */
    #define RES_INT_ALS_MASK   (0x7<<RES_INT_ALS_SHIFT)

    /** low threshold condition in #RESULT_INTERRUPT_STATUS_GPIO for */
    #define RES_INT_STAT_GPIO_LOW_LEVEL_THRESHOLD  0x01
    /** high threshold condition in #RESULT_INTERRUPT_STATUS_GPIO for ALs or Rage*/
    #define RES_INT_STAT_GPIO_HIGH_LEVEL_THRESHOLD 0x02
    /** out of window condition in #RESULT_INTERRUPT_STATUS_GPIO */
    #define RES_INT_STAT_GPIO_OUT_OF_WINDOW        0x03
    /** new sample ready in #RESULT_INTERRUPT_STATUS_GPIO */
    #define RES_INT_STAT_GPIO_NEW_SAMPLE_READY     0x04
    /** error  in #RESULT_INTERRUPT_STATUS_GPIO */
    #define RES_INT_ERROR_MASK (0x3<<RES_INT_ERROR_SHIFT)
	/** laser safety error on #RES_INT_ERROR_MASK of #RESULT_INTERRUPT_STATUS_GPIO */
	#define RES_INT_ERROR_LASER_SAFETY  1
	/** pll 1 or 2 error on #RES_INT_ERROR_MASK of #RESULT_INTERRUPT_STATUS_GPIO*/
	#define RES_INT_ERROR_PLL           2

/**
 * Final range result value presented to the user for use. Unit is in mm.
 */
#define RESULT_RANGE_VAL                        0x062

/**
 * Raw Range result value with offset applied (no cross talk compensation applied). Unit is in mm.
 */
#define RESULT_RANGE_RAW                        0x064

/**
 * @brief Sensor count rate of signal returns correlated to IR emitter.
 *
 * Computed from RETURN_SIGNAL_COUNT / RETURN_CONV_TIME. Mcps 9.7 format
 */
#define RESULT_RANGE_SIGNAL_RATE                0x066

/**
 * @brief Return signal count
 *
 *  Sensor count output value attributed to signal correlated to IR emitter on the Return array.
 */
#define RESULT_RANGE_RETURN_SIGNAL_COUNT        0x06C

/**
 * @brief Reference signal count
 *
 * sensor count output value attributed to signal correlated to IR emitter on the Reference array.
 */
#define RESULT_RANGE_REFERENCE_SIGNAL_COUNT     0x070

/**
 * @brief Return ambient count
 *
 * sensor count output value attributed to uncorrelated ambient signal on the Return array.
 * Must be multiplied by 6 if used to calculate the ambient to signal threshold
 */
#define RESULT_RANGE_RETURN_AMB_COUNT           0x074

/**
 * @brief   Reference ambient count
 *
 * Sensor count output value attributed to uncorrelated ambient signal on the Reference array.
 */
#define RESULT_RANGE_REFERENCE_AMB_COUNT        0x078

/**
 * sensor count output value attributed to signal on the Return array.
 */
#define RESULT_RANGE_RETURN_CONV_TIME           0x07C

/**
 * sensor count output value attributed to signal on the Reference array.
 */
#define RESULT_RANGE_REFERENCE_CONV_TIME        0x080


/**
 * @def RANGE_SCALER
 * @brief RANGE scaling register
 *
 * Never should  user write directly onto that register directly \a VL6180x_UpscaleSetScaling()
 */
#define RANGE_SCALER                            0x096

/**
 * @def READOUT_AVERAGING_SAMPLE_PERIOD
 * @brief Readout averaging sample period register
 *
 *
 * The internal readout averaging sample period can be adjusted from 0 to 255.
 * Increasing the sampling period decreases noise but also reduces the effective
 * max convergence time and increases power consumption
 * Each unit sample period corresponds to around 64.5 μs additional processing time.
 * The recommended setting is 48 which equates to around 4.3 ms.
 *
 * see datasheet for more detail
 */
#define READOUT_AVERAGING_SAMPLE_PERIOD     0x10A

/**
 * @def I2C_SLAVE_DEVICE_ADDRESS
 * User programmable I2C address (7-bit). Device address can be re-designated after power-up.
 * @warning What programmed in the register 7-0 are bit 8-1 of i2c address on bus (bit 0 is rd/wr)
 * so what prohamd is commonly whar ergfer as adrerss /2
 * @sa VL6180x_SetI2CAddress()
 */
#define I2C_SLAVE_DEVICE_ADDRESS               0x212

#endif /* _VL6180x_DEF */

vl6180x_cfg.h


/**
 * @file VL6180x_cfg.h
 *
 * Proximity and ALS configuration
 */

#ifndef VL6180x_CFG_H_
#define VL6180x_CFG_H_

/**
 * @def VL6180x_UPSCALE_SUPPORT
 * @brief Configure up-scale capabilities and default up-scale factor for ranging operations
 * 
 * @li 1 : Fixed scaling by 1 (no up-scaling support)
 * @li 2 : Fixed scaling by 2
 * @li 3 : Fixed scaling by 3
 * @li  -1 -2 -3 : Run time programmable through @a VL6180x_UpscaleSetScaling(). Default scaling factore is -VL6180x_UPSCALE_SUPPORT \n
 */
#define VL6180x_UPSCALE_SUPPORT -1

/**
 * @def VL6180x_ALS_SUPPORT
 * @brief Enable ALS support
 *
 * Set to 0 if ALS is not used in application. This can help reducing code size if it is a concern.
 */
#define VL6180x_ALS_SUPPORT      1

/**
 * @def VL6180x_HAVE_DMAX_RANGING
 * @brief Enable DMax calculation for ranging applications.
 *  
 * When set to 1, __Dmax__ is returned by API typically when  @a VL6180x_RangePollMeasurement() high level
 * function is called (this is returned in @a VL6180x_RangeData_t structure).
 * __Dmax__ is an estimation of the maximum distance (in mm) the product can report a valid distance of a 17% target for 
 * the current ambient light conditions (__Dmax__ decreases when ambient light increases). __Dmax__ should be used only
 * when the product is not able to return a valid distance (no object or object is too far from the ranging sensor).
 * Typically, this is done by checking the __errorStatus__ field of the @a VL6180x_RangeData_t structure returned by 
 * the @a VL6180x_RangePollMeasurement() function.
 * You may refer to ::RangeError_u to get full list of supported error codes.
 * @warning Dmax is estimated for a 17% grey target. If the real target has a reflectance lower than 17%, report Dmax could be over-estimated 
 */
#define VL6180x_HAVE_DMAX_RANGING   1

/**
 * @def VL6180x_WRAP_AROUND_FILTER_SUPPORT
 * @brief Enable wrap around filter (WAF) feature
 *  
 * In specific conditions, when targeting a mirror or a very reflective metal, a __wrap around__ effect can occur internally to the
 * ranging product which results in returning a wrong distance (under-estimated). Goal of the WAF is to detect this wrap arround effect
 * and to filter it by returning a non-valid distance : __errorStatus__ set to 16 (see ::RangeError_u)
 * @warning Wrap-around filter can not be used when device is running in continuous mode 
 * 
 * @li 0 : Filter is not supported, no filtering code is included in API
 * @li 1 : Filter is supported and active by default
 * @li -1 : Filter is supported but is not active by default @a VL6180x_FilterSetState() can turn it on and off at any time
 */
#define VL6180x_WRAP_AROUND_FILTER_SUPPORT   1

/**
 * @def VL6180x_EXTENDED_RANGE
 * @brief Enable extended ranging support
 *
 * Device that do not formally support extended ranging should only be used with a scaling factor of 1.
 * Correct operation with scaling factor other than 1 (>200mm ) is not granted by ST.
 */
#define VL6180x_EXTENDED_RANGE 0


#if (VL6180x_EXTENDED_RANGE) && (VL6180x_ALS_SUPPORT)
#warning "Als support should be OFF for extended range"
#endif

#endif
/** @} */ // end of api_config

/* VL6180x_CFG_H_ */

vl6180x_api.h

#ifndef VL6180x_API_H_
#define VL6180x_API_H_

#include "vl6180x_platform.h"
#include "main.h"
#include "drv_i2c.h"

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Check and set default platform dependent configuration
 */
#ifndef VL6180x_SINGLE_DEVICE_DRIVER
#error "VL6180x_SINGLE_DEVICE_DRIVER not defined"
/* TODO you may remove or comment these #error but it is best you update your vl6180x_platform.h file to define it*/
#endif


#ifndef VL6180x_RANGE_STATUS_ERRSTRING
#warning "VL6180x_RANGE_STATUS_ERRSTRING not defined ?"
/* TODO you may remove or comment these #warning and keep the default below to keep compatibility
   or update your vl6180x_platform.h file */
/**
 * force VL6180x_RANGE_STATUS_ERRSTRING to not supported when not part of any cfg file
 */
#define VL6180x_RANGE_STATUS_ERRSTRING  0
#endif

#ifndef VL6180X_SAFE_POLLING_ENTER
#warning "VL6180X_SAFE_POLLING_ENTER not defined, likely old vl6180x_cfg.h file ?"
/* TODO you may remove or comment these #warning and keep the default below to keep compatibility
   or update your vl6180x_platform.h file */
/**
 * force VL6180X_SAFE_POLLING_ENTER to off when not in cfg file
 */
#define VL6180X_SAFE_POLLING_ENTER 0 /* off by default as in api 2.0 */
#endif

#ifndef VL6180X_LOG_ENABLE
/**
 * Force VL6180X_LOG_ENABLE to none as default
 */
#define VL6180X_LOG_ENABLE  0
#endif

#if VL6180x_RANGE_STATUS_ERRSTRING
/**@def VL6180x_HAVE_RANGE_STATUS_ERRSTRING
 * @brief is defined when @a #VL6180x_RANGE_STATUS_ERRSTRING is enable
 */
#define  VL6180x_HAVE_RANGE_STATUS_ERRSTRING
#endif



/** @brief Get API version as "hex integer" 0xMMnnss
 */
#define VL6180x_ApiRevInt  ((VL6180x_API_REV_MAJOR<<24)+(VL6180x_API_REV_MINOR<<16)+VL6180x_API_REV_SUB)

/** Get API version as string for exe "2.1.12" "
 */
#define VL6180x_ApiRevStr  VL6180X_STR(VL6180x_API_REV_MAJOR) "." VL6180X_STR(VL6180x_API_REV_MINOR) "." VL6180X_STR(VL6180x_API_REV_SUB)

/** @defgroup api_init Init functions
 *  @brief    API init functions
 *  @ingroup api_hl
 *  @{
 */

uint8_t VL6180x_Identification(VL6180xDev_t dev);


/**
 * @brief Wait for device booted after chip enable (hardware standby)
 * @par Function Description
 * After Chip enable Application you can also simply wait at least 1ms to ensure device is ready
 * @warning After device chip enable (gpio0) de-asserted  user must wait gpio1 to get asserted (hardware standby).
 * or wait at least 400usec prior to do any low level access or api call .
 *
 * This function implements polling for standby but you must ensure 400usec from chip enable passed\n
 * @warning Calling this function if device is not fresh out of reset will  result in an indefinite loop\n
 *
 * @param dev  The device
 * @return     0 on success
 */
int VL6180x_WaitDeviceBooted(VL6180xDev_t dev);

/**
 *
 * @brief One time device initialization
 *
 * To be called once and only once after device is brought out of reset (Chip enable) and booted see @a VL6180x_WaitDeviceBooted()
 *
 * @par Function Description
 * When not used after a fresh device "power up" or reset, it may return @a #CALIBRATION_WARNING
 * meaning wrong calibration data may have been fetched from device that can result in unpredictable and wrong ranging values\n
 *
 * @param dev  The device
 * @return     0 on success,  @a #CALIBRATION_WARNING if failed
 */
int VL6180x_InitData(VL6180xDev_t dev);

/**
 * @brief Configure GPIO1 function and set polarity.
 * @par Function Description
 * To be used prior to arm single shot measure or start  continuous mode.
 *
 * The function uses @a VL6180x_SetupGPIOx() for setting gpio 1.
 * @warning  changing polarity can generate a spurious interrupt on pins.
 * It sets an interrupt flags condition that must be cleared to avoid polling hangs. \n
 * It is safe to run VL6180x_ClearAllInterrupt() just after.
 *
 * @param dev           The device
 * @param IntFunction   The interrupt functionality to use one of :\n
 *  @a #GPIOx_SELECT_OFF \n
 *  @a #GPIOx_SELECT_GPIO_INTERRUPT_OUTPUT
 * @param ActiveHigh  The interrupt line polarity see ::IntrPol_e
 *      use @a #INTR_POL_LOW (falling edge) or @a #INTR_POL_HIGH (rising edge)
 * @return 0 on success
 */
int VL6180x_SetupGPIO1(VL6180xDev_t dev, uint8_t IntFunction, int ActiveHigh);

 /**
  * @brief  Prepare device for operation
  * @par Function Description
  * Does static initialization and reprogram common default settings \n
  * Device is prepared for new measure, ready single shot ranging or ALS typical polling operation\n
  * After prepare user can : \n
  * @li Call other API function to set other settings\n
  * @li Configure the interrupt pins, etc... \n
  * @li Then start ranging or ALS operations in single shot or continuous mode
  *
  * @param dev   The device
  * @return      0 on success
  */
int VL6180x_Prepare(VL6180xDev_t dev);

 /** @}  */


/** @defgroup api_hl_range Ranging functions
 *  @brief    Ranging functions
 *  @ingroup api_hl
 *  @{
 */

/**
 * @brief Start continuous ranging mode
 *
 * @details End user should ensure device is in idle state and not already running
 */
int VL6180x_RangeStartContinuousMode(VL6180xDev_t dev);

/**
 * @brief Start single shot ranging measure
 *
 * @details End user should ensure device is in idle state and not already running
 */
int VL6180x_RangeStartSingleShot(VL6180xDev_t dev);

/**
 * @brief Set maximum convergence time
 *
 * @par Function Description
 * Setting a low convergence time can impact maximal detectable distance.
 * Refer to VL6180x Datasheet Table 7 : Typical range convergence time.
 * A typical value for up to x3 scaling is 50 ms
 *
 * @param dev
 * @param MaxConTime_msec
 * @return 0 on success. <0 on error. >0 for calibration warning status
 */
int VL6180x_RangeSetMaxConvergenceTime(VL6180xDev_t dev, uint8_t  MaxConTime_msec);

/**
  * @brief Single shot Range measurement in polling mode.
  *
  * @par Function Description
  * Kick off a new single shot range  then wait for ready to retrieve it by polling interrupt status \n
  * Ranging must be prepared by a first call to  @a VL6180x_Prepare() and it is safer to clear  very first poll call \n
  * This function reference VL6180x_PollDelay(dev) porting macro/call on each polling loop,
  * but PollDelay(dev) may never be called if measure in ready on first poll loop \n
  * Should not be use in continuous mode operation as it will stop it and cause stop/start misbehaviour \n
  * \n This function clears Range Interrupt status , but not error one. For that uses  @a VL6180x_ClearErrorInterrupt() \n
  * This range error is not related VL6180x_RangeData_t::errorStatus that refer measure status \n
  *
  * @param dev          The device
  * @param pRangeData   Will be populated with the result ranging data @a  VL6180x_RangeData_t
  * @return 0 on success , @a #RANGE_ERROR if device reports an error case in it status (not cleared) use
  *
  * \sa ::VL6180x_RangeData_t
  */
int VL6180x_RangePollMeasurement(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData);

/**
 * @brief Check for measure readiness and get it if ready
 *
 * @par Function Description
 * Using this function is an alternative to @a VL6180x_RangePollMeasurement() to avoid polling operation. This is suitable for applications
 * where host CPU is triggered on a interrupt (not from VL6180X) to perform ranging operation. In this scenario, we assume that the very first ranging
 * operation is triggered by a call to @a VL6180x_RangeStartSingleShot(). Then, host CPU regularly calls @a VL6180x_RangeGetMeasurementIfReady() to
 * get a distance measure if ready. In case the distance is not ready, host may get it at the next call.\n
 *
 * @warning
 * This function does not re-start a new measurement : this is up to the host CPU to do it.\n
 * This function clears Range Interrupt for measure ready , but not error interrupts. For that, uses  @a VL6180x_ClearErrorInterrupt() \n
 *
 * @param dev  The device
 * @param pRangeData  Will be populated with the result ranging data if available
 * @return  0 on success and <0 in case of error. Please check pRangeData.errorStatus to check is new measurement is ready or not.
 */
int VL6180x_RangeGetMeasurementIfReady(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData);

/**
 * @brief Retrieve range measurements set  from device
 *
 * @par Function Description
 * The measurement is made of range_mm status and error code @a VL6180x_RangeData_t \n
 * Based on configuration selected extra measures are included.
 *
 * @warning should not be used in continuous if wrap around filter is active \n
 * Does not perform any wait nor check for result availability or validity.
 *\sa VL6180x_RangeGetResult for "range only" measurement
 *
 * @param dev         The device
 * @param pRangeData  Pointer to the data structure to fill up
 * @return            0 on success
 */
int VL6180x_RangeGetMeasurement(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData);

/**
 * @brief Get ranging result and only that
 *
 * @par Function Description
 * Unlike @a VL6180x_RangeGetMeasurement() this function only retrieves the range in millimeter \n
 * It does any required up-scale translation\n
 * It can be called after success status polling or in interrupt mode \n
 * @warning these function is not doing wrap around filtering \n
 * This function doesn't perform any data ready check!
 *
 * @param dev        The device
 * @param pRange_mm  Pointer to range distance
 * @return           0 on success
 */
int VL6180x_RangeGetResult(VL6180xDev_t dev, int32_t *pRange_mm);

/**
 * @brief Configure ranging interrupt reported to application
 *
 * @param dev            The device
 * @param ConfigGpioInt  Select ranging report\n select one (and only one) of:\n
 *   @a #CONFIG_GPIO_INTERRUPT_DISABLED \n
 *   @a #CONFIG_GPIO_INTERRUPT_LEVEL_LOW \n
 *   @a #CONFIG_GPIO_INTERRUPT_LEVEL_HIGH \n
 *   @a #CONFIG_GPIO_INTERRUPT_OUT_OF_WINDOW \n
 *   @a #CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY
 * @return   0 on success
 */
int VL6180x_RangeConfigInterrupt(VL6180xDev_t dev, uint8_t ConfigGpioInt);


/**
 * @brief Clear range interrupt
 *
 * @param dev    The device
 * @return  0    On success
 */
#define VL6180x_RangeClearInterrupt(dev) VL6180x_ClearInterrupt(dev, INTERRUPT_CLEAR_RANGING)

/**
 * @brief Return ranging error interrupt status
 *
 * @par Function Description
 * Appropriate Interrupt report must have been selected first by @a VL6180x_RangeConfigInterrupt() or @a  VL6180x_Prepare() \n
 *
 * Can be used in polling loop to wait for a given ranging event or in interrupt to read the trigger \n
 * Events triggers are : \n
 * @a #RES_INT_STAT_GPIO_LOW_LEVEL_THRESHOLD \n
 * @a #RES_INT_STAT_GPIO_HIGH_LEVEL_THRESHOLD \n
 * @a #RES_INT_STAT_GPIO_OUT_OF_WINDOW \n (RES_INT_STAT_GPIO_LOW_LEVEL_THRESHOLD|RES_INT_STAT_GPIO_HIGH_LEVEL_THRESHOLD)
 * @a #RES_INT_STAT_GPIO_NEW_SAMPLE_READY \n
 *
 * @sa IntrStatus_t
 * @param dev        The device
 * @param pIntStatus Pointer to status variable to update
 * @return           0 on success
 */
int VL6180x_RangeGetInterruptStatus(VL6180xDev_t dev, uint8_t *pIntStatus);

#if VL6180x_RANGE_STATUS_ERRSTRING

extern const char *ROMABLE_DATA VL6180x_RangeStatusErrString[];
/**
 * @brief Human readable error string for range error status
 *
 * @param RangeErrCode  The error code as stored on @a VL6180x_RangeData_t::errorStatus
 * @return  error string , NULL for invalid RangeErrCode
 * @sa ::RangeError_u
 */
const char *VL6180x_RangeGetStatusErrString(uint8_t RangeErrCode);
#else
#define VL6180x_RangeGetStatusErrString(...) NULL
#endif

/** @}  */

#if VL6180x_ALS_SUPPORT

/** @defgroup api_hl_als ALS functions
 *  @brief    ALS functions
 *  @ingroup api_hl
 *  @{
 */

/**
 * @brief   Run a single ALS measurement in single shot polling mode
 *
 * @par Function Description
 * Kick off a new single shot ALS then wait new measurement ready to retrieve it ( polling system interrupt status register for als) \n
 * ALS must be prepared by a first call to @a VL6180x_Prepare() \n
 * \n Should not be used in continuous or interrupt mode it will break it and create hazard in start/stop \n
 *
 * @param dev          The device
 * @param pAlsData     Als data structure to fill up @a VL6180x_AlsData_t
 * @return             0 on success
 */
int VL6180x_AlsPollMeasurement(VL6180xDev_t dev, VL6180x_AlsData_t *pAlsData);


/**
 * @brief  Get actual ALS measurement
 *
 * @par Function Description
 * Can be called after success status polling or in interrupt mode to retrieve ALS measurement from device \n
 * This function doesn't perform any data ready check !
 *
 * @param dev        The device
 * @param pAlsData   Pointer to measurement struct @a VL6180x_AlsData_t
 * @return  0 on success
 */
int VL6180x_AlsGetMeasurement(VL6180xDev_t dev, VL6180x_AlsData_t *pAlsData);

/**
 * @brief  Configure ALS interrupts provide to application
 *
 * @param dev            The Device
 * @param ConfigGpioInt  Select one (and only one) of : \n
 *   @a #CONFIG_GPIO_INTERRUPT_DISABLED \n
 *   @a #CONFIG_GPIO_INTERRUPT_LEVEL_LOW \n
 *   @a #CONFIG_GPIO_INTERRUPT_LEVEL_HIGH \n
 *   @a #CONFIG_GPIO_INTERRUPT_OUT_OF_WINDOW \n
 *   @a #CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY
 * @return               0 on success may return #INVALID_PARAMS for invalid mode
 */
int VL6180x_AlsConfigInterrupt(VL6180xDev_t dev, uint8_t ConfigGpioInt);


/**
 * @brief Set ALS integration period
 *
 * @param dev        The device
 * @param period_ms  Integration period in msec. Value in between 50 to 100 msec is recommended\n
 * @return           0 on success
 */
int VL6180x_AlsSetIntegrationPeriod(VL6180xDev_t dev, uint16_t period_ms);

/**
 * @brief Set ALS "inter-measurement period"
 *
 * @par Function Description
 * The so call data-sheet "inter measurement period" is actually an extra inter-measurement delay
 *
 * @param dev        The device
 * @param intermeasurement_period_ms Inter measurement time in milli second\n
 *        @warning applied value is clipped to 2550 ms\n
 * @return           0 on success if value is
 */
int VL6180x_AlsSetInterMeasurementPeriod(VL6180xDev_t dev,  uint16_t intermeasurement_period_ms);

/**
 * @brief Set ALS analog gain code
 *
 * @par Function Description
 * ALS gain code value programmed in @a SYSALS_ANALOGUE_GAIN .
 * @param dev   The device
 * @param gain  Gain code see datasheet or AlsGainLookUp for real value. Value is clipped to 7.
 * @return  0 on success
 */

int VL6180x_AlsSetAnalogueGain(VL6180xDev_t dev, uint8_t gain);
/**
 * @brief Set thresholds for ALS continuous mode
 * @warning Threshold are raw device value not lux!
 *
 * @par Function Description
 * Basically value programmed in @a SYSALS_THRESH_LOW and @a SYSALS_THRESH_HIGH registers
 * @param dev   The device
 * @param low   ALS low raw threshold for @a SYSALS_THRESH_LOW
 * @param high  ALS high raw threshold for  @a SYSALS_THRESH_HIGH
 * @return  0 on success
 */
int VL6180x_AlsSetThresholds(VL6180xDev_t dev, uint8_t low, uint8_t high);

/**
 * @brief  Clear ALS interrupt
 *
 * @param dev    The device
 * @return  0    On success
 */
 #define VL6180x_AlsClearInterrupt(dev) VL6180x_ClearInterrupt(dev, INTERRUPT_CLEAR_ALS)

/**
 * Read ALS interrupt status
 * @param dev         Device
 * @param pIntStatus  Pointer to status
 * @return            0 on success
 */
int VL6180x_AlsGetInterruptStatus(VL6180xDev_t dev, uint8_t *pIntStatus);

/** @}  */
#endif

/** @defgroup api_ll_init Init functions
 *  @brief    Init functions
 *  @ingroup api_ll
 *  @{
 */

/**
 * @brief Low level ranging and ALS register static settings (you should call @a VL6180x_Prepare() function instead)
 *
 * @param dev
 * @return 0 on success
 */
int VL6180x_StaticInit(VL6180xDev_t dev);

 /** @}  */

/** @defgroup api_ll_range Ranging functions
 *  @brief    Ranging Low Level functions
 *  @ingroup api_ll
 *  @{
 */

/**
 * @brief Wait for device to be ready (before a new ranging command can be issued by application)
 * @param dev        The device
 * @param MaxLoop    Max Number of i2c polling loop see @a #msec_2_i2cloop
 * @return           0 on success. <0 when fail \n
 *                   @ref VL6180x_ErrCode_t::TIME_OUT for time out \n
 *                   @ref VL6180x_ErrCode_t::INVALID_PARAMS if MaxLop<1
 */
int VL6180x_RangeWaitDeviceReady(VL6180xDev_t dev, int MaxLoop);

/**
 * @brief Program Inter measurement period (used only in continuous mode)
 *
 * @par Function Description
 * When trying to set too long time, it returns #INVALID_PARAMS
 *
 * @param dev     The device
 * @param InterMeasTime_msec Requires inter-measurement time in msec
 * @return 0 on success
 */
int VL6180x_RangeSetInterMeasPeriod(VL6180xDev_t dev, uint32_t  InterMeasTime_msec);


/**
 * @brief Set device ranging scaling factor
 *
 * @par Function Description
 * The ranging scaling factor is applied on the raw distance measured by the device to increase operating ranging at the price of the precision.
 * Changing the scaling factor when device is not in f/w standby state (free running) is not safe.
 * It can be source of spurious interrupt, wrongly scaled range etc ...
 * @warning __This  function doesns't update high/low threshold and other programmed settings linked to scaling factor__.
 *  To ensure proper operation, threshold and scaling changes should be done following this procedure: \n
 *  @li Set Group hold  : @a VL6180x_SetGroupParamHold() \n
 *  @li Get Threshold @a VL6180x_RangeGetThresholds() \n
 *  @li Change scaling : @a VL6180x_UpscaleSetScaling() \n
 *  @li Set Threshold : @a VL6180x_RangeSetThresholds() \n
 *  @li Unset Group Hold : @a VL6180x_SetGroupParamHold()
 *
 * @param dev      The device
 * @param scaling  Scaling factor to apply (1,2 or 3)
 * @return          0 on success when up-scale support is not configured it fail for any
 *                  scaling than the one statically configured.
 */
int VL6180x_UpscaleSetScaling(VL6180xDev_t dev, uint8_t scaling);

/**
 * @brief Get current ranging scaling factor
 *
 * @param dev The device
 * @return    The current scaling factor
 */
int VL6180x_UpscaleGetScaling(VL6180xDev_t dev);


/**
 * @brief Give filtered state (wrap-around filter) of a range measurement
 * @param pRangeData  Range measurement data
 * @return  0 means measure was not filtered,  when not 0 range from device got filtered by filter post processing
 */
#define VL6180x_RangeIsFilteredMeasurement(pRangeData) ((pRangeData)->errorStatus == RangingFiltered)

/**
 * @brief Get the maximal distance for actual scaling
 * @par Function Description
 * Do not use prior to @a VL6180x_Prepare() or at least @a VL6180x_InitData()
 *
 * Any range value more than the value returned by this function is to be considered as "no target detected"
 * or "no target in detectable range"
 * @warning The maximal distance depends on the scaling
 *
 * @param dev The device
 * @return    The maximal range limit for actual mode and scaling
 */
uint16_t VL6180x_GetUpperLimit(VL6180xDev_t dev);

/**
 * @brief Apply low and high ranging thresholds that are considered only in continuous mode
 *
 * @par Function Description
 * This function programs low and high ranging thresholds that are considered in continuous mode :
 * interrupt will be raised only when an object is detected at a distance inside this [low:high] range.
 * The function takes care of applying current scaling factor if any.\n
 * To be safe, in continuous operation, thresholds must be changed under "group parameter hold" cover.
 * Group hold can be activated/deactivated directly in the function or externally (then set 0)
 * using /a VL6180x_SetGroupParamHold() function.
 *
 * @param dev      The device
 * @param low      Low threshold in mm
 * @param high     High threshold in mm
 * @param SafeHold  Use of group parameters hold to surround threshold programming.
 * @return  0 On success
 */
int VL6180x_RangeSetThresholds(VL6180xDev_t dev, uint16_t low, uint16_t high, int SafeHold);

/**
 * @brief  Get scaled high and low threshold from device
 *
 * @par Function Description
 * Due to scaling factor, the returned value may be different from what has been programmed first (precision lost).
 * For instance VL6180x_RangeSetThresholds(dev,11,22) with scale 3
 * will read back 9 ((11/3)x3) and 21 ((22/3)x3).

 * @param dev  The device
 * @param low  scaled low Threshold ptr  can be NULL if not needed
 * @param high scaled High Threshold ptr can be NULL if not needed
 * @return 0 on success, return value is undefined if both low and high are NULL
 * @warning return value is undefined if both low and high are NULL
 */
int VL6180x_RangeGetThresholds(VL6180xDev_t dev, uint16_t *low, uint16_t *high);

/**
 * @brief Set ranging raw thresholds (scaling not considered so not recommended to use it)
 *
 * @param dev  The device
 * @param low  raw low threshold set to raw register
 * @param high raw high threshold set to raw  register
 * @return 0 on success
 */
int VL6180x_RangeSetRawThresholds(VL6180xDev_t dev, uint8_t low, uint8_t high);

/**
 * @brief Set Early Convergence Estimate ratio
 * @par Function Description
 * For more information on ECE check datasheet
 * @warning May return a calibration warning in some use cases
 *
 * @param dev        The device
 * @param FactorM    ECE factor M in M/D
 * @param FactorD    ECE factor D in M/D
 * @return           0 on success. <0 on error. >0 on warning
 */
int VL6180x_RangeSetEceFactor(VL6180xDev_t dev, uint16_t  FactorM, uint16_t FactorD);

/**
 * @brief Set Early Convergence Estimate state (See #SYSRANGE_RANGE_CHECK_ENABLES register)
 * @param dev       The device
 * @param enable    State to be set 0=disabled, otherwise enabled
 * @return          0 on success
 */
int VL6180x_RangeSetEceState(VL6180xDev_t dev, int enable);

/**
 * @brief Set activation state of the wrap around filter
 * @param dev   The device
 * @param state New activation state (0=off,  otherwise on)
 * @return      0 on success
 */
int VL6180x_FilterSetState(VL6180xDev_t dev, int state);

/**
 * Get activation state of the wrap around filter
 * @param dev  The device
 * @return     Filter enabled or not, when filter is not supported it always returns 0S
 */
int VL6180x_FilterGetState(VL6180xDev_t dev);


/**
 * @brief Set activation state of  DMax computation
 * @param dev   The device
 * @param state New activation state (0=off,  otherwise on)
 * @return      0 on success
 */
int VL6180x_DMaxSetState(VL6180xDev_t dev, int state);

/**
 * Get activation state of DMax computation
 * @param dev  The device
 * @return     Filter enabled or not, when filter is not supported it always returns 0S
 */
int VL6180x_DMaxGetState(VL6180xDev_t dev);


/**
 * @brief Set ranging mode and start/stop measure (use high level functions instead : @a VL6180x_RangeStartSingleShot() or @a VL6180x_RangeStartContinuousMode())
 *
 * @par Function Description
 * When used outside scope of known polling single shot stopped state, \n
 * user must ensure the device state is "idle" before to issue a new command.
 *
 * @param dev   The device
 * @param mode  A combination of working mode (#MODE_SINGLESHOT or #MODE_CONTINUOUS) and start/stop condition (#MODE_START_STOP) \n
 * @return      0 on success
 */
int VL6180x_RangeSetSystemMode(VL6180xDev_t dev, uint8_t mode);

/**
 * @brief Enable/disable range ignore feature
 *
 * @par  Function Description
 * Enable range ignore feature to ensure that the device does not range on the cover glass because of cross-talk. 
 * @a VL6180x_RangeIgnoreConfigure() should be run first to configure feature prior to enable it.
 *
 * @param dev             The Device
 * @param EnableState     Feature state to set 0= off else =on
 * @return                0 on success
 */
int VL6180x_RangeIgnoreSetEnable(VL6180xDev_t dev, int EnableState);

/**
 * @brief Configure Range ignore feature
 *
 * @par  Function Description
 * When return signal rate is below the IgnoreThreshold and return distance is below the ValidHeight, the distance will be ignored 
 * @warning It is recommended to enable range ignore feature and configure it only when device is in stop or idle state
 * @warning Once this function is called, next call to @a VL6180x_InitData() function without reseting the device will result in wrong ranging operation
 * @param dev				The Device
 * @param ValidHeight_mm    Valid height in mm (unscaled ie not raw  value before scaling)
 * @param IgnoreThreshold	Ignore threshold in fixpoint 9.7 MegaCount/sec
 * @return
 */
int VL6180x_RangeIgnoreConfigure(VL6180xDev_t dev, uint16_t ValidHeight_mm, uint16_t IgnoreThreshold);
/** @}  */

/** @defgroup api_ll_range_calibration Ranging calibration functions
 *  @brief    Ranging calibration functions
 *  @ingroup api_ll
 *  @{
 */
/**
 * @brief Get part to part calibration offset
 *
 * @par Function Description
 * Should only be used after a successful call to @a VL6180x_InitData to backup device nvm value
 *
 * @param dev  The device
 * @return part to part calibration offset from device
 */
int8_t VL6180x_GetOffsetCalibrationData(VL6180xDev_t dev);

/**
 * Set or over-write part to part calibration offset and apply it immediately
 * \sa VL6180x_InitData(), VL6180x_GetOffsetCalibrationData()
 * @param dev     The device
 * @param offset   Offset
 * @return  0 on success
 */
int  VL6180x_SetOffsetCalibrationData(VL6180xDev_t dev, int8_t offset);

/**
 * @brief Set Cross talk compensation rate
 *
 * @par Function Description
 * It programs register @a #SYSRANGE_CROSSTALK_COMPENSATION_RATE
 *
 * @param dev  The device
 * @param Rate Compensation rate (9.7 fix point) see datasheet for details
 * @return     0 on success
 */
int  VL6180x_SetXTalkCompensationRate(VL6180xDev_t dev, FixPoint97_t Rate);

/** @}  */



#if VL6180x_ALS_SUPPORT
/** @defgroup api_ll_als ALS functions
 *  @brief    ALS functions
 *  @ingroup api_ll
 *  @{
 */

/**
 * @brief Wait for device to be ready for new als operation or max pollign loop (time out)
 * @param dev        The device
 * @param MaxLoop    Max Number of i2c polling loop see @a #msec_2_i2cloop
 * @return           0 on success. <0 when @a VL6180x_ErrCode_t::TIME_OUT if timed out
 */
int VL6180x_AlsWaitDeviceReady(VL6180xDev_t dev, int MaxLoop);

/**
 * @brief Set ALS system mode and start/stop measure
 *
 * @warning When used outside after single shot polling, \n
 * User must ensure  the device state is ready before issuing a new command (using @a VL6180x_AlsWaitDeviceReady()). \n
 * Non respect of this, can cause loss of interrupt or device hanging.
 *
 * @param dev   The device
 * @param mode  A combination of working mode (#MODE_SINGLESHOT or #MODE_CONTINUOUS) and start condition (#MODE_START_STOP) \n
 * @return      0 on success
 */
int VL6180x_AlsSetSystemMode(VL6180xDev_t dev, uint8_t mode);

/** @}  */
#endif

/** @defgroup api_ll_misc Misc functions
 *  @brief    Misc functions
 *  @ingroup api_ll
 *  @{
 */

/**
 * Set Group parameter Hold state
 *
 * @par Function Description
 * Group parameter holds @a #SYSTEM_GROUPED_PARAMETER_HOLD enable safe update (non atomic across multiple measure) by host
 * \n The critical register group is composed of: \n
 * #SYSTEM_INTERRUPT_CONFIG_GPIO \n
 * #SYSRANGE_THRESH_HIGH \n
 * #SYSRANGE_THRESH_LOW \n
 * #SYSALS_INTEGRATION_PERIOD \n
 * #SYSALS_ANALOGUE_GAIN \n
 * #SYSALS_THRESH_HIGH \n
 * #SYSALS_THRESH_LOW
 *
 *
 * @param dev   The device
 * @param Hold  Group parameter Hold state to be set (on/off)
 * @return      0 on success
 */
int VL6180x_SetGroupParamHold(VL6180xDev_t dev, int Hold);

/**
 * @brief Set new device i2c address
 *
 * After completion the device will answer to the new address programmed.
 *
 * @sa AN4478: Using multiple VL6180X's in a single design
 * @param dev       The device
 * @param NewAddr   The new i2c address (8 bits)
 * @return          0 on success
 */
int VL6180x_SetI2CAddress(VL6180xDev_t dev, uint8_t NewAddr);

/**
 * @brief Fully configure gpio 0/1 pin : polarity and functionality
 *
 * @param dev          The device
 * @param pin          gpio pin 0 or 1
 * @param IntFunction  Pin functionality : either #GPIOx_SELECT_OFF or #GPIOx_SELECT_GPIO_INTERRUPT_OUTPUT (refer to #SYSTEM_MODE_GPIO1 register definition)
 * @param ActiveHigh   Set active high polarity, or active low see @a ::IntrPol_e
 * @return             0 on success
 */
int VL6180x_SetupGPIOx(VL6180xDev_t dev, int pin, uint8_t IntFunction, int ActiveHigh);


/**
 * @brief Set interrupt pin polarity for the given GPIO
 *
 * @param dev          The device
 * @param pin          Pin 0 or 1
 * @param active_high  select active high or low polarity using @ref IntrPol_e
 * @return             0 on success
 */
int VL6180x_SetGPIOxPolarity(VL6180xDev_t dev, int pin, int active_high);

/**
 * Select interrupt functionality for the given GPIO
 *
 * @par Function Description
 * Functionality refer to @a SYSTEM_MODE_GPIO0
 *
 * @param dev            The device
 * @param pin            Pin to configure 0 or 1 (gpio0 or gpio1)\nNote that gpio0 is chip enable at power up !
 * @param functionality  Pin functionality : either #GPIOx_SELECT_OFF or #GPIOx_SELECT_GPIO_INTERRUPT_OUTPUT (refer to #SYSTEM_MODE_GPIO1 register definition)
 * @return              0 on success
 */
int VL6180x_SetGPIOxFunctionality(VL6180xDev_t dev, int pin, uint8_t functionality);

/**
 * #brief Disable and turn to Hi-Z gpio output pin
 *
 * @param dev  The device
 * @param pin  The pin number to disable 0 or 1
 * @return     0 on success
 */
int VL6180x_DisableGPIOxOut(VL6180xDev_t dev, int pin);

/**
 * @def msec_2_i2cloop
 * @brief  Number of I2C polling loop (an 8 bit register) to run for maximal wait time.
 *
 * @par Function Description
 * When polling via I2C the overall time is mainly the I2C transaction time because it is a slow bus
 *   one 8 bit register poll on I2C bus timing is shown below: \n
 *   start + addr_w(a)  + 2x8bit index(a)  + stop  + start  + addr_rd(a)  + 1x8bit data_rd(a) + stop \n
 *   1        8   1        2*(8+1)           1       1          8     1        8           1    1 \n
 *  so 49 serial bits
 *
 * @param  time_ms  Time to wait in milli second 10
 * @param  i2c_khz  I2C bus frequencies in KHz  for instance 400
 * @return The number of loops (at least 1)
 */
#define msec_2_i2cloop(time_ms, i2c_khz) (((time_ms) * (i2c_khz) / 49) + 1)

/** @}  */



/**
 * polarity use in @a VL6180x_SetupGPIOx() , @a VL6180x_SetupGPIO1()
 */
typedef enum {
	INTR_POL_LOW = 0, /*!< set active low polarity best setup for falling edge */
	INTR_POL_HIGH = 1, /*!< set active high polarity best setup for rising edge */
} IntrPol_e;

/** @defgroup api_ll_intr Interrupts management functions
 *  @brief    Interrupts management functions
 *  @ingroup api_ll
 *  @{
 */

/**
 * @brief     Get all interrupts cause
 *
 * @param dev    The device
 * @param status Ptr to interrupt status. You can use @a IntrStatus_t::val
 * @return 0 on success
 */
int VL6180x_GetInterruptStatus(VL6180xDev_t dev, uint8_t *status);

/**
 * @brief Clear given system interrupt condition
 *
 * @par Function Description
 * Clear given interrupt cause by writing into register #SYSTEM_INTERRUPT_CLEAR register.
 * @param dev       The device
 * @param IntClear  Which interrupt source to clear. Use any combinations of #INTERRUPT_CLEAR_RANGING , #INTERRUPT_CLEAR_ALS , #INTERRUPT_CLEAR_ERROR.
 * @return  0       On success
 */
int VL6180x_ClearInterrupt(VL6180xDev_t dev, uint8_t IntClear);

/**
 * @brief Clear error interrupt
 *
 * @param dev    The device
 * @return  0    On success
 */
 #define VL6180x_ClearErrorInterrupt(dev) VL6180x_ClearInterrupt(dev, INTERRUPT_CLEAR_ERROR)

/**
 * @brief Clear All interrupt causes (als+range+error)
 *
 * @param dev    The device
 * @return  0    On success
 */
#define VL6180x_ClearAllInterrupt(dev) VL6180x_ClearInterrupt(dev, INTERRUPT_CLEAR_ERROR|INTERRUPT_CLEAR_RANGING|INTERRUPT_CLEAR_ALS)

/** @}  */


/** @defgroup api_reg API Register access functions
 *  @brief    Registers access functions called by API core functions
 *  @ingroup api_ll
 *  @{
 */

/**
 * Write VL6180x single byte register
 * @param dev   The device
 * @param index The register index
 * @param data  8 bit register data
 * @return success
 */
extern int VL6180x_WrByte(VL6180xDev_t dev, uint16_t index, uint8_t data);
/**
 * Thread safe VL6180x Update (rd/modify/write) single byte register
 *
 * Final_reg = (Initial_reg & and_data) |or_data
 *
 * @param dev   The device
 * @param index The register index
 * @param AndData  8 bit and data
 * @param OrData   8 bit or data
 * @return 0 on success
 */
extern int VL6180x_UpdateByte(VL6180xDev_t dev, uint16_t index, uint8_t AndData, uint8_t OrData);
/**
 * Write VL6180x word register
 * @param dev   The device
 * @param index The register index
 * @param data  16 bit register data
 * @return  0 on success
 */
extern int VL6180x_WrWord(VL6180xDev_t dev, uint16_t index, uint16_t data);
/**
 * Write VL6180x double word (4 byte) register
 * @param dev   The device
 * @param index The register index
 * @param data  32 bit register data
 * @return  0 on success
 */
extern int VL6180x_WrDWord(VL6180xDev_t dev, uint16_t index, uint32_t data);

/**
 * Read VL6180x single byte register
 * @param dev   The device
 * @param index The register index
 * @param data  pointer to 8 bit data
 * @return 0 on success
 */
extern int VL6180x_RdByte(VL6180xDev_t dev, uint16_t index, uint8_t *data);

/**
 * Read VL6180x word (2byte) register
 * @param dev   The device
 * @param index The register index
 * @param data  pointer to 16 bit data
 * @return 0 on success
 */
extern int VL6180x_RdWord(VL6180xDev_t dev, uint16_t index, uint16_t *data);

/**
 * Read VL6180x dword (4byte) register
 * @param dev   The device
 * @param index The register index
 * @param data  pointer to 32 bit data
 * @return 0 on success
 */
extern int VL6180x_RdDWord(VL6180xDev_t dev, uint16_t index, uint32_t *data);


/**
 * Read VL6180x multiple bytes
 * @note required only if #VL6180x_HAVE_MULTI_READ is set
 * @param dev   The device
 * @param index The register index
 * @param data  pointer to 8 bit data
 * @param nData number of data bytes to read
 * @return 0 on success
 */
extern int VL6180x_RdMulti(VL6180xDev_t dev, uint16_t index, uint8_t *data, int nData);

/** @}  */




#ifdef __cplusplus
}
#endif

#endif /* VL6180x_API_H_ */

vl6180x_api.c


#include "vl6180x_api.h"

#define VL6180x_9to7Conv(x) (x)
#define REFRESH_CACHED_DATA_AFTER_INIT  1
#define IsValidGPIOFunction(x) ((x) == GPIOx_SELECT_GPIO_INTERRUPT_OUTPUT || (x) == GPIOx_SELECT_OFF)
/** default value ECE factor Molecular */
#define DEF_ECE_FACTOR_M    85
/** default value ECE factor Denominator */
#define DEF_ECE_FACTOR_D    100
/** default value ALS integration time */
#define DEF_INT_PEFRIOD     100
/** default value ALS gain */
#define DEF_ALS_GAIN        1
/** default value ALS scaler */
#define DEF_ALS_SCALER      1
/** default value for DMAX Enable */
#define DEF_DMAX_ENABLE     1
/** default ambient tuning factor %x1000 */
#define DEF_AMBIENT_TUNING  80

#define DEF_CROSS_TALK_VALID_HEIGHT_VALUE   20


#if VL6180x_SINGLE_DEVICE_DRIVER
extern  struct VL6180xDevData_t SingleVL6180xDevData;
#define VL6180xDevDataGet(dev, field) (SingleVL6180xDevData.field)
#define VL6180xDevDataSet(dev, field, data) SingleVL6180xDevData.field = (data)
#endif

#define LUXRES_FIX_PREC 8
#define GAIN_FIX_PREC    8  /* ! if not sme as LUX_PREC then :( adjust GetLux */
#define AN_GAIN_MULT    (1 << GAIN_FIX_PREC)


static int32_t _GetAveTotalTime(VL6180xDev_t dev);
static int VL6180x_RangeSetEarlyConvergenceEestimateThreshold(VL6180xDev_t dev);


//ScalerLookUP scaling factor-1 to register #RANGE_SCALER lookup
static const uint16_t ScalerLookUP[]      ROMABLE_DATA = {253, 127, 84}; /* lookup table for scaling->scalar 1x2x 3x */

//scaling factor to Upper limit look up
static const uint16_t UpperLimitLookUP[]  ROMABLE_DATA = {185, 370, 580}; /* lookup table for scaling->limit  1x2x3x */
/**
 * Als Code gain to fix point gain lookup
 */
static const uint16_t AlsGainLookUp[8]    ROMABLE_DATA = {
	(uint16_t)(20.0f * AN_GAIN_MULT),
	(uint16_t)(10.0f * AN_GAIN_MULT),
	(uint16_t)(5.0f  * AN_GAIN_MULT),
	(uint16_t)(2.5f  * AN_GAIN_MULT),
	(uint16_t)(1.67f * AN_GAIN_MULT),
	(uint16_t)(1.25f * AN_GAIN_MULT),
	(uint16_t)(1.0f  * AN_GAIN_MULT),
	(uint16_t)(40.0f * AN_GAIN_MULT),
};


#if VL6180x_RANGE_STATUS_ERRSTRING
const char *ROMABLE_DATA VL6180x_RangeStatusErrString[] = {
	"No Error",
	"VCSEL Continuity Test",
	"VCSEL Watchdog Test",
	"VCSEL Watchdog",
	"PLL1 Lock",
	"PLL2 Lock",
	"Early Convergence Estimate",
	"Max Convergence",
	"No Target Ignore",
	"Not used 9",
	"Not used 10",
	"Max Signal To Noise Ratio",
	"Raw Ranging Algo Underflow",
	"Raw Ranging Algo Overflow",
	"Ranging Algo Underflow",
	"Ranging Algo Overflow",

	"Filtered by post processing (WAF)",
	"Ranging filtering (WAF) on-going",
	"Data not ready",
};

const char *VL6180x_RangeGetStatusErrString(uint8_t RangeErrCode)
{
	if (RangeErrCode > sizeof(VL6180x_RangeStatusErrString) / sizeof(VL6180x_RangeStatusErrString[0]))
		return NULL;
	return  VL6180x_RangeStatusErrString[RangeErrCode];
}
#endif

#if VL6180x_UPSCALE_SUPPORT == 1
	#define _GetUpscale(dev, ...)  1
	#define _SetUpscale(...) -1
	#define DEF_UPSCALE 1
#elif VL6180x_UPSCALE_SUPPORT == 2
	#define _GetUpscale(dev, ...)  2
	#define _SetUpscale(...)
	#define DEF_UPSCALE 2
#elif VL6180x_UPSCALE_SUPPORT == 3
	#define _GetUpscale(dev, ...)  3
	#define _SetUpscale(...)
	#define DEF_UPSCALE 3
#else
	#define DEF_UPSCALE (-(VL6180x_UPSCALE_SUPPORT))
	#define _GetUpscale(dev, ...) VL6180xDevDataGet(dev, UpscaleFactor)
	#define _SetUpscale(dev, Scaling) VL6180xDevDataSet(dev, UpscaleFactor, Scaling)
#endif


#if VL6180x_SINGLE_DEVICE_DRIVER
/**
 * the unique driver data  When single device driver is active
 */
struct VL6180xDevData_t VL6180x_DEV_DATA_ATTR  SingleVL6180xDevData = {
	.EceFactorM        = DEF_ECE_FACTOR_M,
	.EceFactorD        = DEF_ECE_FACTOR_D,
#ifdef VL6180x_HAVE_UPSCALE_DATA
	.UpscaleFactor     = DEF_UPSCALE,
#endif
#ifdef VL6180x_HAVE_ALS_DATA
	.IntegrationPeriod = DEF_INT_PEFRIOD,
	.AlsGainCode       = DEF_ALS_GAIN,
	.AlsScaler         = DEF_ALS_SCALER,
#endif
#ifdef VL6180x_HAVE_DMAX_RANGING
	.DMaxEnable =   DEF_DMAX_ENABLE,
#endif
};
#endif /* VL6180x_SINGLE_DEVICE_DRIVER */



#define Fix7_2_KCPs(x) ((((uint32_t)(x))*1000)>>7)


#if VL6180x_WRAP_AROUND_FILTER_SUPPORT || VL6180x_HAVE_DMAX_RANGING
static int _GetRateResult(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData);
#endif

#if VL6180x_WRAP_AROUND_FILTER_SUPPORT
static int _filter_Init(VL6180xDev_t dev);
static int _filter_GetResult(VL6180xDev_t dev, VL6180x_RangeData_t *pData);
	#define _IsWrapArroundActive(dev) VL6180xDevDataGet(dev, WrapAroundFilterActive)
#else
	#define _IsWrapArroundActive(dev) 0
#endif


#if VL6180x_HAVE_DMAX_RANGING
	void _DMax_OneTimeInit(VL6180xDev_t dev);
	static int _DMax_InitData(VL6180xDev_t dev);
	static int _DMax_Compute(VL6180xDev_t dev, VL6180x_RangeData_t *pRange);
	#define _IsDMaxActive(dev) VL6180xDevDataGet(dev, DMaxEnable)
#else
	#define _DMax_InitData(...) 0 /* success */
	#define _DMax_OneTimeInit(...) (void)0
	#define _IsDMaxActive(...) 0
#endif

static int VL6180x_RangeStaticInit(VL6180xDev_t dev);
static int  VL6180x_UpscaleStaticInit(VL6180xDev_t dev);

//==========================================================

int VL6180x_UpdateByte(VL6180xDev_t dev, uint16_t index, uint8_t AndData, uint8_t OrData){

    int  status;
    uint8_t buffer[3];


    buffer[0]=index>>8;
    buffer[1]=index&0xFF;

    status=VL6180x_I2CWrite(dev, (uint8_t *)buffer,(uint8_t)2);
    if( !status ){
        /* read data direct onto buffer */
        status=VL6180x_I2CRead(dev, &buffer[2],1);
        if( !status ){
            buffer[2]=(buffer[2]&AndData)|OrData;
            status=VL6180x_I2CWrite(dev, buffer, (uint8_t)3);
        }
    }



    return status;
}
//================================================================

int VL6180x_WaitDeviceBooted(VL6180xDev_t dev)
{
	uint8_t FreshOutReset;
	int status;

	do {
		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSTEM_FRESH_OUT_OF_RESET, &FreshOutReset);
	} while (FreshOutReset != 1 && status == 0);

	return status;
}

//================================================================**

uint8_t VL6180x_Identification(VL6180xDev_t dev)
{
	uint8_t Id;
	i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, IDENTIFICATION_MODEL_ID, &Id);
	return Id;
}

//================================================================
int VL6180x_InitData(VL6180xDev_t dev)
{
	int status, dmax_status ;
	int8_t offset;
	uint8_t FreshOutReset;
	uint32_t CalValue;
	uint16_t u16;
	uint32_t XTalkCompRate_KCps;


	VL6180xDevDataSet(dev, EceFactorM, DEF_ECE_FACTOR_M);
	VL6180xDevDataSet(dev, EceFactorD, DEF_ECE_FACTOR_D);

	VL6180xDevDataSet(dev, RangeIgnore.Enabled, 0);

#ifdef VL6180x_HAVE_UPSCALE_DATA
	VL6180xDevDataSet(dev, UpscaleFactor,  DEF_UPSCALE);
#endif

#ifdef VL6180x_HAVE_ALS_DATA
	VL6180xDevDataSet(dev, IntegrationPeriod, DEF_INT_PEFRIOD);
	VL6180xDevDataSet(dev, AlsGainCode, DEF_ALS_GAIN);
	VL6180xDevDataSet(dev, AlsScaler, DEF_ALS_SCALER);
#endif

#ifdef VL6180x_HAVE_WRAP_AROUND_DATA
	VL6180xDevDataSet(dev, WrapAroundFilterActive, (VL6180x_WRAP_AROUND_FILTER_SUPPORT > 0));
	VL6180xDevDataSet(dev, DMaxEnable, DEF_DMAX_ENABLE);
#endif

	_DMax_OneTimeInit(dev);
	do {

		HAL_Delay(500);
		/* backup offset initial value from nvm these must be done prior any over call that use offset */
		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_PART_TO_PART_RANGE_OFFSET, (uint8_t *)&offset);
		if (status) {
			term_printf("SYSRANGE_PART_TO_PART_RANGE_OFFSET rd fail\n\r");
			break;
		}
		VL6180xDevDataSet(dev, Part2PartOffsetNVM, offset);

		status = i2c1_ReadReg16Word32(VL6180x_I2C_ADDRESS, SYSRANGE_RANGE_IGNORE_THRESHOLD, &CalValue);
		if (status) {
			term_printf("Part2PartAmbNVM rd fail\n\r");
			break;
		}
		if ((CalValue&0xFFFF0000) == 0) {
			CalValue = 0x00CE03F8;
		}
		VL6180xDevDataSet(dev, Part2PartAmbNVM, CalValue);

		status = i2c1_ReadReg16Word16(VL6180x_I2C_ADDRESS, SYSRANGE_CROSSTALK_COMPENSATION_RATE , &u16);
		if (status) {
			term_printf("SYSRANGE_CROSSTALK_COMPENSATION_RATE rd fail\n\r ");
			break;
		}
		XTalkCompRate_KCps = Fix7_2_KCPs(u16);
		VL6180xDevDataSet(dev, XTalkCompRate_KCps, XTalkCompRate_KCps);

		dmax_status = _DMax_InitData(dev);
		if (dmax_status < 0) {
			term_printf("DMax init failure\n\r");
			break;
		}

		/* Read or wait for fresh out of reset  */
		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSTEM_FRESH_OUT_OF_RESET, &FreshOutReset);
		if (status) {
			term_printf("SYSTEM_FRESH_OUT_OF_RESET rd fail\n\r");
			break;
		}
		if (FreshOutReset != 1 || dmax_status)
			status = CALIBRATION_WARNING;

	} while (0);

	return status;
}
//======================================================================
int8_t VL6180x_GetOffsetCalibrationData(VL6180xDev_t dev)
{
	int8_t offset;
	offset = VL6180xDevDataGet(dev, Part2PartOffsetNVM);
	return offset;
}
//======================================================================
int  VL6180x_SetOffsetCalibrationData(VL6180xDev_t dev, int8_t offset)
{
	int status;
	VL6180xDevDataSet(dev, Part2PartOffsetNVM, offset);
	offset /= _GetUpscale(dev);
	status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_PART_TO_PART_RANGE_OFFSET, offset);
	return status;
}
//======================================================================
int  VL6180x_SetXTalkCompensationRate(VL6180xDev_t dev, FixPoint97_t Rate)
{
	int status;
	status = i2c1_WriteReg16Word16(VL6180x_I2C_ADDRESS, SYSRANGE_CROSSTALK_COMPENSATION_RATE, Rate);
	if (status == 0) {
		uint32_t XTalkCompRate_KCps;
		XTalkCompRate_KCps = Fix7_2_KCPs(Rate);
		VL6180xDevDataSet(dev, XTalkCompRate_KCps, XTalkCompRate_KCps);
		/* update dmax whenever xtalk rate changes */
		status = _DMax_InitData(dev);
	}
	return status;
}
//======================================================================
int VL6180x_SetI2CAddress(VL6180xDev_t dev, uint8_t NewAddress)
{
	int status;

	status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, I2C_SLAVE_DEVICE_ADDRESS, NewAddress / 2);
	if (status) {
		term_printf("new i2c addr Wr fail\n\r");
	}
	return status;
}
//======================================================================
uint16_t VL6180x_GetUpperLimit(VL6180xDev_t dev)
{
	uint16_t limit;
	int scaling;
	scaling = _GetUpscale(dev);
	limit = UpperLimitLookUP[scaling - 1];
	return limit;
}
//======================================================================
int VL6180x_StaticInit(VL6180xDev_t dev)
{
	int status = 0, init_status;
	if (_GetUpscale(dev) == 1 && !(VL6180x_UPSCALE_SUPPORT < 0))
		init_status = VL6180x_RangeStaticInit(dev);
	else
		init_status = VL6180x_UpscaleStaticInit(dev);

	if (init_status < 0) {
		term_printf("StaticInit fail");
		goto error;
	} else if (init_status > 0) {
		term_printf("StaticInit warning");
	}

	#if REFRESH_CACHED_DATA_AFTER_INIT
	#ifdef VL6180x_HAVE_ALS_DATA
	/* update cached value after tuning applied */
	do {
		uint8_t data;
		status =  i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, FW_ALS_RESULT_SCALER, &data);
		if (status)
			break;
		VL6180xDevDataSet(dev, AlsScaler, data);

		status =  i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSALS_ANALOGUE_GAIN, &data);
		if (status)
			break;
		VL6180x_AlsSetAnalogueGain(dev, data);
	} while (0);
	#endif
	#endif /* REFRESH_CACHED_DATA_AFTER_INIT */
	if (status < 0) {
		term_printf("StaticInit fail");
	}
	if (!status && init_status) {
		status = init_status;
	}
error:
	return status;
}
//================================================================
int VL6180x_SetGroupParamHold(VL6180xDev_t dev, int Hold)
{
	int status;
	uint8_t value;
	if (Hold)
		value = 1;
	else
		value = 0;
	status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSTEM_GROUPED_PARAMETER_HOLD, value);
	return status;

}
//================================================================
int VL6180x_Prepare(VL6180xDev_t dev)
{
	int status;
	LOG_FUNCTION_START("");

	do {
		status = VL6180x_StaticInit(dev);
		if (status < 0)
			break;

		/* set range InterruptMode to new sample */
		status = VL6180x_RangeConfigInterrupt(dev, CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY);
		if (status)
			break;

		/* set default threshold */
		status = VL6180x_RangeSetRawThresholds(dev, 10, 200);
		if (status) {
			term_printf("VL6180x_RangeSetRawThresholds fail");
			break;
		}
	#if VL6180x_ALS_SUPPORT
		status = VL6180x_AlsSetIntegrationPeriod(dev, 100);
		if (status)
			break;
		status = VL6180x_AlsSetInterMeasurementPeriod(dev,  200);
		if (status)
			break;
		status = VL6180x_AlsSetAnalogueGain(dev,  0);
		if (status)
			break;
		status = VL6180x_AlsSetThresholds(dev, 0, 0xFF);
		if (status)
			break;
		/* set Als InterruptMode to new sample */
		status = VL6180x_AlsConfigInterrupt(dev, CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY);
		if (status) {
			term_printf("VL6180x_AlsConfigInterrupt fail\n\r");
			break;
		}
	#endif
	#if VL6180x_WRAP_AROUND_FILTER_SUPPORT
		_filter_Init(dev);
	#endif
		/* make sure to reset any left previous condition that can hangs first poll */
		status = VL6180x_ClearAllInterrupt(dev);
	} while (0);


	return status;
}
//================================================================
#if VL6180x_ALS_SUPPORT
int VL6180x_AlsGetLux(VL6180xDev_t dev, lux_t *pLux)
{
	int status;
	uint16_t RawAls;
	uint32_t luxValue = 0;
	uint32_t IntPeriod;
	uint32_t AlsAnGain;
	uint32_t GainFix;
	uint32_t AlsScaler;

	#if LUXRES_FIX_PREC !=  GAIN_FIX_PREC
	#error "LUXRES_FIX_PREC != GAIN_FIX_PREC  review these code to be correct"
	#endif
	const uint32_t LuxResxIntIme = (uint32_t)(0.56f * DEF_INT_PEFRIOD * (1 << LUXRES_FIX_PREC));

	status = i2c1_ReadReg16Word16(VL6180x_I2C_ADDRESS, RESULT_ALS_VAL, &RawAls);
	if (!status) {
		/* wer are yet here at no fix point */
		IntPeriod = VL6180xDevDataGet(dev, IntegrationPeriod);
		AlsScaler = VL6180xDevDataGet(dev, AlsScaler);
		IntPeriod++; /* what stored is real time  ms -1 and it can be 0 for or 0 or 1ms */
		luxValue = (uint32_t)RawAls * LuxResxIntIme; /* max # 16+8bits + 6bit (0.56*100)  */
		luxValue /= IntPeriod;                         /* max # 16+8bits + 6bit 16+8+1 to 9 bit */
		/* between  29 - 21 bit */
		AlsAnGain = VL6180xDevDataGet(dev, AlsGainCode);
		GainFix = AlsGainLookUp[AlsAnGain];
		luxValue = luxValue / (AlsScaler * GainFix);
		*pLux = luxValue;
	}
	return status;
}
//================================================================
int VL6180x_AlsGetMeasurement(VL6180xDev_t dev, VL6180x_AlsData_t *pAlsData)
{
	int status;
	uint8_t ErrStatus;

	status = VL6180x_AlsGetLux(dev, &pAlsData->lux);
	if (!status) {
		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, RESULT_ALS_STATUS, &ErrStatus);
		pAlsData->errorStatus = ErrStatus >> 4;
	}

	return status;
}

//================================================================
int VL6180x_AlsPollMeasurement(VL6180xDev_t dev, VL6180x_AlsData_t *pAlsData)
{
	int status;
	int ClrStatus;
	uint8_t IntStatus;


	#if VL6180X_SAFE_POLLING_ENTER
	/* if device get stopped with left interrupt uncleared , it is required to clear them now or poll for new condition will never occur*/
	status = VL6180x_AlsClearInterrupt(dev);
	if (status) {
		////VL6180x_ErrLog("VL6180x_AlsClearInterrupt fail");
		goto over;
	}
	#endif

	status = VL6180x_AlsSetSystemMode(dev, MODE_START_STOP | MODE_SINGLESHOT);
	if (status) {
		term_printf("VL6180x_AlsSetSystemMode fail\n\r");
		goto over;
	}

	/* poll for new sample ready */
	while (1) {
		status = VL6180x_AlsGetInterruptStatus(dev, &IntStatus);
		if (status) {
			break;
		}
		if (IntStatus == RES_INT_STAT_GPIO_NEW_SAMPLE_READY) {
			break; /* break on new data (status is 0)  */
		}

	//	VL6180x_PollDelay(dev);
	};

	if (!status) {
		status = VL6180x_AlsGetMeasurement(dev, pAlsData);
	}

	ClrStatus = VL6180x_AlsClearInterrupt(dev);
	if (ClrStatus) {
		term_printf("VL6180x_AlsClearInterrupt fail\n\r");
		if (!status) {
		    status = ClrStatus; /* leave previous if already on error */
		}
	}
over:


	return status;
}
//================================================================
int VL6180x_AlsGetInterruptStatus(VL6180xDev_t dev, uint8_t *pIntStatus)
{
	int status;
	uint8_t IntStatus;

	status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, RESULT_INTERRUPT_STATUS_GPIO, &IntStatus);
	*pIntStatus = (IntStatus >> 3) & 0x07;

	return status;
}
//================================================================
int VL6180x_AlsWaitDeviceReady(VL6180xDev_t dev, int MaxLoop)
{
	int status;
	int  n;
	uint8_t u8;
	LOG_FUNCTION_START("%d", (int)MaxLoop);
	if (MaxLoop < 1) {
		status = INVALID_PARAMS;
	} else {
		for (n = 0; n < MaxLoop; n++) {
			status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, RESULT_ALS_STATUS, &u8);
			if (status)
				break;
			u8 = u8 & ALS_DEVICE_READY_MASK;
			if (u8)
				break;

		}
		if (!status && !u8) {
			status = TIME_OUT;
		}
	}
	LOG_FUNCTION_END(status);
	return status;
}
//================================================================
int VL6180x_AlsSetSystemMode(VL6180xDev_t dev, uint8_t mode)
{
	int status;
	LOG_FUNCTION_START("%d", (int)mode);
	/* FIXME if we are called back to back real fast we are not checking
	 * if previous mode "set" got absorbed => bit 0 must be 0 so that wr 1 work */
	if (mode <= 3) {
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSALS_START, mode);
	} else {
		status = INVALID_PARAMS;
	}
	LOG_FUNCTION_END(status);
	return status;
}
//================================================================
int VL6180x_AlsConfigInterrupt(VL6180xDev_t dev, uint8_t ConfigGpioInt)
{
	int status;

	if (ConfigGpioInt <= CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY) {
		status = VL6180x_UpdateByte(dev, SYSTEM_INTERRUPT_CONFIG_GPIO, (uint8_t)(~CONFIG_GPIO_ALS_MASK), (ConfigGpioInt << 3));
	} else {
		term_printf("Invalid config mode param %d\n\r", (int)ConfigGpioInt);
		status = INVALID_PARAMS;
	}
	LOG_FUNCTION_END(status);
	return status;
}
//================================================================
int VL6180x_AlsSetThresholds(VL6180xDev_t dev, uint8_t low, uint8_t high)
{
	int status;

	status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSALS_THRESH_LOW, low);
	if (!status) {
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSALS_THRESH_HIGH, high);
	}
	return status;
}
//================================================================
int VL6180x_AlsSetAnalogueGain(VL6180xDev_t dev, uint8_t gain)
{
	int status;
	uint8_t GainTotal;

	gain &= ~0x40;
	if (gain > 7) {
		gain = 7;
	}
	GainTotal = gain | 0x40;

	status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSALS_ANALOGUE_GAIN, GainTotal);
	if (!status) {
		VL6180xDevDataSet(dev, AlsGainCode, gain);
	}

	return status;
}
//================================================================
int VL6180x_AlsSetInterMeasurementPeriod(VL6180xDev_t dev,  uint16_t intermeasurement_period_ms)
{
	int status;

	/* clipping: range is 0-2550ms */
	if (intermeasurement_period_ms >= 255 * 10)
		intermeasurement_period_ms = 255 * 10;
	status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSALS_INTERMEASUREMENT_PERIOD, (uint8_t)(intermeasurement_period_ms / 10));

	return status;
}
//================================================================
int VL6180x_AlsSetIntegrationPeriod(VL6180xDev_t dev, uint16_t period_ms)
{
	int status;
	uint16_t SetIntegrationPeriod;


	if (period_ms >= 1)
		SetIntegrationPeriod = period_ms - 1;
	else
		SetIntegrationPeriod = period_ms;

	if (SetIntegrationPeriod > 464) {
		SetIntegrationPeriod = 464;
	} else if (SetIntegrationPeriod == 255)   {
		SetIntegrationPeriod++; /* can't write 255 since this causes the device to lock out.*/
	}

	status = i2c1_WriteReg16Word16(VL6180x_I2C_ADDRESS, SYSALS_INTEGRATION_PERIOD, SetIntegrationPeriod);
	if (!status) {
		VL6180xDevDataSet(dev, IntegrationPeriod, SetIntegrationPeriod) ;
	}

	return status;
}
#endif /* HAVE_ALS_SUPPORT */
//================================================================
int VL6180x_RangePollMeasurement(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData)
{
	int status;
	int ClrStatus;
	IntrStatus_t IntStatus;

	/* start single range measurement */

	#if VL6180X_SAFE_POLLING_ENTER
	/* if device get stopped with left interrupt uncleared , it is required to clear them now or poll for new condition will never occur*/
	status = VL6180x_RangeClearInterrupt(dev);
	if (status) {
		////VL6180x_ErrLog("VL6180x_RangeClearInterrupt fail");
		goto done;
	}
	#endif
	/* //![single_shot_snipet] */
	status = VL6180x_RangeSetSystemMode(dev, MODE_START_STOP | MODE_SINGLESHOT);
	if (status) {
	//	//VL6180x_ErrLog("VL6180x_RangeSetSystemMode fail");
		goto done;
	}


	/* poll for new sample ready */
	while (1) {
		status = VL6180x_RangeGetInterruptStatus(dev, &IntStatus.val);
		if (status) {
			break;
		}
		if (IntStatus.status.Range == RES_INT_STAT_GPIO_NEW_SAMPLE_READY || IntStatus.status.Error != 0) {
			break;
		}

	//	VL6180x_PollDelay(dev);
	}
	/* //![single_shot_snipet] */

	if (!status) {
		status = VL6180x_RangeGetMeasurement(dev, pRangeData);
	}

	/*  clear range interrupt source */
	ClrStatus = VL6180x_RangeClearInterrupt(dev);
	if (ClrStatus) {
	//	//VL6180x_ErrLog("VL6180x_RangeClearInterrupt fail");
		/*  leave initial status if already in error  */
		if (!status) {
			status = ClrStatus;
		}
	}
done:
	return status;
}
//================================================================

#if VL6180x_CACHED_REG

int VL6180x_GetCachedDWord(VL6180xDev_t dev, uint16_t  index, uint32_t *pValue)
{
	int status;
	uint32_t Value;
	if (VL6180xDevDataGet(dev, CacheFilled) != 0 &&
		index >= VL6180x_FIRST_CACHED_INDEX  &&
		index <= (VL6180x_LAST_CACHED_INDEX - 3)) {
		uint8_t *pBytes = &VL6180xDevDataGet(dev, CachedRegs[index - VL6180x_FIRST_CACHED_INDEX]);
		Value = ((uint32_t)pBytes[0] << 24) |
				((uint32_t)pBytes[1] << 16) |
				((uint32_t)pBytes[2] << 8) |
				(uint32_t)pBytes[3];
		*pValue = Value;
		status = 0;
	} else {
		status =  i2c1_ReadReg16Word32(VL6180x_I2C_ADDRESS, index, pValue);
	}
	return status;
}

int VL6180x_GetCachedWord(VL6180xDev_t dev, uint16_t  index, uint16_t *pValue)
{
	int status;
	uint32_t Value;
	if (VL6180xDevDataGet(dev, CacheFilled) != 0 &&
		index >= VL6180x_FIRST_CACHED_INDEX  &&
		index <= (VL6180x_LAST_CACHED_INDEX - 1)) {
		uint8_t *pBytes = &VL6180xDevDataGet(dev, CachedRegs[index - VL6180x_FIRST_CACHED_INDEX]);
		Value = ((uint32_t)pBytes[0] << 8) | (uint32_t)pBytes[1];
		*pValue = Value;
		status = 0;
	} else {
		status =  i2c1_ReadReg16Word16(VL6180x_I2C_ADDRESS, index, pValue);
	}
	return status;
}

int VL6180x_GetCachedByte(VL6180xDev_t dev, uint16_t  index, uint8_t *pValue)
{
	int status;
	uint8_t Value;
	if (VL6180xDevDataGet(dev, CacheFilled) != 0 &&
		index >= VL6180x_FIRST_CACHED_INDEX &&
		index <= VL6180x_LAST_CACHED_INDEX) {
		Value = VL6180xDevDataGet(dev, CachedRegs[index - VL6180x_FIRST_CACHED_INDEX]);
		*pValue = Value;
		status = 0;
	} else {
		status =  i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, index, pValue);
	}
	return status;
}


int _CachedRegs_Fetch(VL6180xDev_t dev)
{
	int status;
	uint8_t *Buffer;
	if (VL6180xDevDataGet(dev, CacheFilled) == 0) {
		VL6180xDevDataSet(dev, CacheFilled, 1);
		Buffer = &VL6180xDevDataGet(dev, CachedRegs[0]);
		status = i2c1_ReadReg16Buffer(VL6180x_I2C_ADDRESS, VL6180x_FIRST_CACHED_INDEX, Buffer, VL6180x_CACHED_REG_CNT);
	} else {
		status = 0 ;
	}
	return status;
}

void _CachedRegs_Flush(VL6180xDev_t dev)
{
	VL6180xDevDataSet(dev, CacheFilled, 0);
}

#else
#   define _CachedRegs_Fetch(...) 0
#   define _CachedRegs_Flush(...) (void)0
#   define _Fetch_CachedRegs(...) 0
#   define VL6180x_GetCachedByte(dev, index, pValue) i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, index, pValue)
#   define VL6180x_GetCachedWord(dev, index, pValue) i2c1_ReadReg16Word16(VL6180x_I2C_ADDRESS, index, pValue)
#   define VL6180x_GetCachedDWord(dev, index, pValue) i2c1_ReadReg16Word32(VL6180x_I2C_ADDRESS, index, pValue)
#endif /* VL6180x_CACHED_REG */

//================================================================

int VL6180x_RangeGetMeasurement(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData)
{
	int status;
	uint16_t RawRate;
	uint8_t RawStatus;

	status = _CachedRegs_Fetch(dev);
	if (status) {
		term_printf("Cache register read fai\n\rl");
		goto error;
	}
	status = VL6180x_RangeGetResult(dev, &pRangeData->range_mm);
	if (!status) {
		status = VL6180x_GetCachedWord(dev, RESULT_RANGE_SIGNAL_RATE, &RawRate);
		if (!status) {
			pRangeData->signalRate_mcps = VL6180x_9to7Conv(RawRate);
			status = VL6180x_GetCachedByte(dev, RESULT_RANGE_STATUS, &RawStatus);
			if (!status) {
				pRangeData->errorStatus = RawStatus >> 4;
			} else {
			term_printf("Rd RESULT_RANGE_STATUS fail\n\r");
			}
	#if VL6180x_WRAP_AROUND_FILTER_SUPPORT || VL6180x_HAVE_DMAX_RANGING
			status = _GetRateResult(dev, pRangeData);
			if (status)
				goto error;
	#endif
	#if VL6180x_WRAP_AROUND_FILTER_SUPPORT
			/* if enabled run filter */
			if (_IsWrapArroundActive(dev)) {
				status = _filter_GetResult(dev, pRangeData);
				if (!status) {
					/* patch the range status and measure if it is filtered */
					if(pRangeData->FilteredData.filterError != NoError) {
						pRangeData->errorStatus = pRangeData->FilteredData.filterError;
						pRangeData->range_mm = pRangeData->FilteredData.range_mm;
					}
				}
			}
	#endif

	#if VL6180x_HAVE_DMAX_RANGING
			if (_IsDMaxActive(dev)) {
				_DMax_Compute(dev, pRangeData);
			}
	#endif
		} else {
		term_printf("Rd RESULT_RANGE_SIGNAL_RATE fail\n\r");
		}
	} else {
		term_printf("VL6180x_GetRangeResult fail\n\r");
	}
error:
	_CachedRegs_Flush(dev);

	return status;
}
//=============================================================================

int VL6180x_RangeGetMeasurementIfReady(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData)
{
	int status;
	IntrStatus_t IntStatus;

	LOG_FUNCTION_START();
	status = VL6180x_RangeGetInterruptStatus(dev, &IntStatus.val);
	if (status == 0) {
		if (IntStatus.status.Range == RES_INT_STAT_GPIO_NEW_SAMPLE_READY ||
			IntStatus.status.Error != 0) {
			status = VL6180x_RangeGetMeasurement(dev, pRangeData);
			if (status == 0) {
				/*  clear range interrupt source */
				status = VL6180x_RangeClearInterrupt(dev);
				if (status) {
					term_printf("VL6180x_RangeClearInterrupt fail\n\r");
				}
			}
		} else {
			pRangeData->errorStatus = DataNotReady;
		}
	} else {
		term_printf("fail to get interrupt status\n\r");
	}
	LOG_FUNCTION_END(status) ;
	return status;
}
//=============================================================================
int VL6180x_FilterSetState(VL6180xDev_t dev, int state)
{
	int status;
	#if VL6180x_WRAP_AROUND_FILTER_SUPPORT
	VL6180xDevDataSet(dev, WrapAroundFilterActive, state);
	status = 0;
	#else
	status =  NOT_SUPPORTED;
	#endif
	return status;
}
//=============================================================================
int VL6180x_FilterGetState(VL6180xDev_t dev)
{
	int status;
	#if VL6180x_WRAP_AROUND_FILTER_SUPPORT
	status = VL6180xDevDataGet(dev, WrapAroundFilterActive);
	#else
	status = 0;
	#endif
	return status;
}
//=============================================================================
int VL6180x_RangeGetResult(VL6180xDev_t dev, int32_t *pRange_mm)
{
	int status;
	uint8_t RawRange;
	int32_t Upscale;
	status = VL6180x_GetCachedByte(dev, RESULT_RANGE_VAL, &RawRange);
	if (!status) {
		Upscale = _GetUpscale(dev);
		*pRange_mm = Upscale * (int32_t)RawRange;
	}
	return status;
}
//=============================================================================
int VL6180x_RangeSetRawThresholds(VL6180xDev_t dev, uint8_t low, uint8_t high)
{
	int status;
	status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_THRESH_HIGH, high);
	if (!status) {
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_THRESH_LOW, low);
	}
	return status;
}
//=============================================================================
int VL6180x_RangeSetThresholds(VL6180xDev_t dev, uint16_t low, uint16_t high, int UseSafeParamHold)
{
	int status;
	int scale;
	scale = _GetUpscale(dev, UpscaleFactor);
	if (low > scale * 255 || high > scale * 255) {
		status = INVALID_PARAMS;
	} else {
		do {
			if (UseSafeParamHold) {
				status = VL6180x_SetGroupParamHold(dev, 1);
				if (status)
					break;
		    }
		    status = VL6180x_RangeSetRawThresholds(dev, (uint8_t)(low / scale), (uint8_t)(high / scale));
		    if (status) {
				term_printf("VL6180x_RangeSetRawThresholds fail\n\r");
		    }
		    if (UseSafeParamHold) {
				int HoldStatus;
				/* tryt to unset param hold vene if previous fail */
				HoldStatus = VL6180x_SetGroupParamHold(dev, 0);
				if (!status)
					status = HoldStatus;
		    }
		} while (0);
	}
	return status;
}
//=============================================================================
int VL6180x_RangeGetThresholds(VL6180xDev_t dev, uint16_t *low, uint16_t *high)
{
	int status = 0;
	uint8_t RawLow, RawHigh;
	int scale;
	scale = _GetUpscale(dev, UpscaleFactor);
	do {
		if (high != NULL) {
			status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_THRESH_HIGH, &RawHigh);
			if (status) {
				term_printf("rd SYSRANGE_THRESH_HIGH fail");
				break;
			}
			*high = (uint16_t)RawHigh * scale;
		}
		if (low != NULL) {
		    status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_THRESH_LOW, &RawLow);
			if (status) {
				term_printf("rd SYSRANGE_THRESH_LOW fail");
				break;
		    }
		    *low = (uint16_t)RawLow * scale;
		}
	} while (0);
	return status;
}
//=============================================================================
int VL6180x_RangeGetInterruptStatus(VL6180xDev_t dev, uint8_t *pIntStatus)
{
	int status;
	uint8_t IntStatus;
	status = VL6180x_GetCachedByte(dev, RESULT_INTERRUPT_STATUS_GPIO, &IntStatus);
	*pIntStatus = IntStatus & 0xC7;
	return status;
}
//=============================================================================
int VL6180x_GetInterruptStatus(VL6180xDev_t dev, uint8_t *IntStatus)
{
	int status;
	status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, RESULT_INTERRUPT_STATUS_GPIO, IntStatus);
	return status;
}
//=============================================================================
int VL6180x_ClearInterrupt(VL6180xDev_t dev, uint8_t IntClear)
{
	int status;
	if (IntClear <= 7) {
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSTEM_INTERRUPT_CLEAR, IntClear);
	} else {
		status = INVALID_PARAMS;
	}
	return status;
}
//=============================================================================
static int VL6180x_RangeStaticInit(VL6180xDev_t dev)
{
	int status;
	/* REGISTER_TUNING_SR03_270514_CustomerView.txt */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0207, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0208, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0096, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0097, 0xfd);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e3, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e4, 0x04);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e5, 0x02);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e6, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e7, 0x03);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00f5, 0x02);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00d9, 0x05);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00db, 0xce);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00dc, 0x03);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00dd, 0xf8);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x009f, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00a3, 0x3c);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00b7, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00bb, 0x3c);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00b2, 0x09);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00ca, 0x09);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0198, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01b0, 0x17);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01ad, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00ff, 0x05);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0100, 0x05);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0199, 0x05);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01a6, 0x1b);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01ac, 0x3e);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01a7, 0x1f);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0030, 0x00);

	/* Recommended : Public registers - See data sheet for more detail */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0011, 0x10); /* Enables polling for New Sample ready when measurement completes */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x010a, 0x30); /* Set the averaging sample period (compromise between lower noise and increased execution time) */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x003f, 0x46); /* Sets the light and dark gain (upper nibble). Dark gain should not be changed.*/
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0031, 0xFF); /* sets the # of range measurements after which auto calibration of system is performed */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0040, 0x63); /* Set ALS integration time to 100ms */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x002e, 0x01); /* perform a single temperature calibration of the ranging sensor */

	/* Optional: Public registers - See data sheet for more detail */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x001b, 0x09); /* Set default ranging inter-measurement period to 100ms */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x003e, 0x31); /* Set default ALS inter-measurement period to 500ms */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0014, 0x24); /* Configures interrupt on New sample ready */


	status = VL6180x_RangeSetMaxConvergenceTime(dev, 50); /*  Calculate ece value on initialization (use max conv) */
	return status;
}
//=============================================================================
#if VL6180x_UPSCALE_SUPPORT != 1
static int _UpscaleInitPatch0(VL6180xDev_t dev)
{
	int status;
	uint32_t CalValue = 0;
	CalValue = VL6180xDevDataGet(dev, Part2PartAmbNVM);
	status = i2c1_WriteReg16Word32(VL6180x_I2C_ADDRESS, 0xDA, CalValue);
	return status;
}
//=============================================================================
/* only include up-scaling register setting when up-scale support is configured in */
int VL6180x_UpscaleRegInit(VL6180xDev_t dev)
{
	/*  apply REGISTER_TUNING_ER02_100614_CustomerView.txt */
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0207, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0208, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0096, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0097, 0x54);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e3, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e4, 0x04);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e5, 0x02);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e6, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00e7, 0x03);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00f5, 0x02);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00d9, 0x05);

	_UpscaleInitPatch0(dev);

	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x009f, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00a3, 0x28);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00b7, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00bb, 0x28);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00b2, 0x09);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00ca, 0x09);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0198, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01b0, 0x17);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01ad, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x00ff, 0x05);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0100, 0x05);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0199, 0x05);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01a6, 0x1b);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01ac, 0x3e);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01a7, 0x1f);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0030, 0x00);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0011, 0x10);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x010a, 0x30);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x003f, 0x46);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0031, 0xFF);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0040, 0x63);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x002e, 0x01);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x002c, 0xff);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x001b, 0x09);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x003e, 0x31);
	i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0014, 0x24);
#if VL6180x_EXTENDED_RANGE
	VL6180x_RangeSetMaxConvergenceTime(dev, 63);
#else
	VL6180x_RangeSetMaxConvergenceTime(dev, 50);
#endif
	return 0;
}
#else
#define VL6180x_UpscaleRegInit(...) -1
#endif
//=============================================================================
int VL6180x_UpscaleSetScaling(VL6180xDev_t dev, uint8_t scaling)
{
	int status;
	uint16_t Scaler;
	uint16_t ValidHeight;
	int8_t  Offset;

#ifdef VL6180x_HAVE_UPSCALE_DATA
	#define min_scaling 1
	#define max_scaling (sizeof(ScalerLookUP) / sizeof(ScalerLookUP[0]))
#else
	/* we are in fixed config so only allow configured factor */
	#define min_scaling VL6180x_UPSCALE_SUPPORT
	#define max_scaling VL6180x_UPSCALE_SUPPORT
#endif

	if (scaling >= min_scaling  && scaling <= max_scaling) {

		Scaler = ScalerLookUP[scaling - 1];
		status = i2c1_WriteReg16Word16(VL6180x_I2C_ADDRESS, RANGE_SCALER, Scaler);
		_SetUpscale(dev, scaling);

		/* Apply scaling on  part-2-part offset */
		Offset = VL6180xDevDataGet(dev, Part2PartOffsetNVM) / scaling;
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_PART_TO_PART_RANGE_OFFSET, Offset);

		/* Apply scaling on CrossTalkValidHeight */
		if (status == 0) {
			status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_CROSSTALK_VALID_HEIGHT,
									DEF_CROSS_TALK_VALID_HEIGHT_VALUE /  scaling);
		}
		/* Apply scaling on RangeIgnore ValidHeight if enabled */
		if( status == 0){
			if(  VL6180xDevDataGet(dev, RangeIgnore.Enabled) !=0 ){
				ValidHeight = VL6180xDevDataGet(dev, RangeIgnore.ValidHeight);
				ValidHeight  /= _GetUpscale(dev);
				if( ValidHeight > 255 )
					ValidHeight = 255;

				status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_RANGE_IGNORE_VALID_HEIGHT,
							ValidHeight );
			}
		}

#if !VL6180x_EXTENDED_RANGE
		if (status == 0) {
			status = VL6180x_RangeSetEceState(dev, scaling == 1); /* enable ece only at 1x scaling */
		}
		if (status == 0 && !VL6180x_EXTENDED_RANGE && scaling != 1) {
			status = NOT_GUARANTEED ;
		}
#endif
	} else {
		status = INVALID_PARAMS;
	}
#undef min_scaling
#undef max_scaling
	return status;
}
//=============================================================================
int VL6180x_UpscaleGetScaling(VL6180xDev_t dev)
{
	int status;
	status = _GetUpscale(dev);
	return status;
}

//=============================================================================
static int  VL6180x_UpscaleStaticInit(VL6180xDev_t dev)
{
	/* todo make these a fail macro in case only 1x is suppoted */
	int status;
	do {
		status = VL6180x_UpscaleRegInit(dev);
		if (status) {
			////VL6180x_ErrLog("regInit fail");
			break;
		}
#if VL6180x_EXTENDED_RANGE
		status = VL6180x_RangeSetEceState(dev, 0);
		if (status) {
			////VL6180x_ErrLog("VL6180x_RangeSetEceState fail");
			break;
		}
#endif
	} while (0);
	if (!status) {
		/*  must write the scaler at least once to the device to ensure the scaler is in a known state. */
		status = VL6180x_UpscaleSetScaling(dev, _GetUpscale(dev));
		i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x016, 0x00); /* change fresh out of set status to 0 */
	}
	return status;
}
//=============================================================================
int VL6180x_SetGPIOxPolarity(VL6180xDev_t dev, int pin, int active_high)
{
	int status;
	if (pin == 0  || pin == 1) {
		uint16_t RegIndex;
		uint8_t  DataSet;
		if (pin == 0)
			RegIndex = SYSTEM_MODE_GPIO0;
		else
			RegIndex = SYSTEM_MODE_GPIO1;

		if (active_high)
		   DataSet = GPIOx_POLARITY_SELECT_MASK;
		else
		   DataSet = 0;

		status = VL6180x_UpdateByte(dev, RegIndex, (uint8_t)~GPIOx_POLARITY_SELECT_MASK, DataSet);
	} else {
		////VL6180x_ErrLog("Invalid pin param %d", (int)pin);
		status = INVALID_PARAMS;
	}
	return status;
}
//=============================================================================
int VL6180x_SetGPIOxFunctionality(VL6180xDev_t dev, int pin, uint8_t functionality)
{
	int status;
	if (((pin == 0)  || (pin == 1))  && IsValidGPIOFunction(functionality)) {
		uint16_t RegIndex;

		if (pin == 0)
			RegIndex = SYSTEM_MODE_GPIO0;
		else
			RegIndex = SYSTEM_MODE_GPIO1;

		status = VL6180x_UpdateByte(dev, RegIndex, (uint8_t)~GPIOx_FUNCTIONALITY_SELECT_MASK,
									functionality << GPIOx_FUNCTIONALITY_SELECT_SHIFT);
		if (status) {
			term_printf("Update SYSTEM_MODE_GPIO%d fail", (int)pin);
		}
	} else {
		term_printf("Invalid pin %d  or function %d", (int)pin, (int)functionality);
		status = INVALID_PARAMS;
	}
	return status;
}
//=============================================================================
int VL6180x_SetupGPIOx(VL6180xDev_t dev, int pin,  uint8_t IntFunction, int  ActiveHigh)
{
	int status;
	if (((pin == 0) || (pin == 1))  && IsValidGPIOFunction(IntFunction)) {
		uint16_t RegIndex;
		uint8_t value = 0;

		if (pin == 0)
		   RegIndex = SYSTEM_MODE_GPIO0;
		else
		   RegIndex = SYSTEM_MODE_GPIO1;

		if (ActiveHigh)
		   value |= GPIOx_POLARITY_SELECT_MASK;

		value |=  IntFunction << GPIOx_FUNCTIONALITY_SELECT_SHIFT;
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, RegIndex, value);
		if (status) {
			term_printf("SYSTEM_MODE_GPIO%d wr fail", (int)pin-SYSTEM_MODE_GPIO0);
		}
	} else {
		term_printf("Invalid pin %d or function %d", (int)pin, (int) IntFunction);
		status = INVALID_PARAMS;
	}
	return status;
}
//=============================================================================
int VL6180x_DisableGPIOxOut(VL6180xDev_t dev, int pin)
{
	int status;
	status = VL6180x_SetGPIOxFunctionality(dev, pin, GPIOx_SELECT_OFF);
	return status;
}
//=============================================================================
int VL6180x_SetupGPIO1(VL6180xDev_t dev, uint8_t IntFunction, int ActiveHigh)
{
	int status;
	status = VL6180x_SetupGPIOx(dev, 1, IntFunction, ActiveHigh);
	return status;
}
//=============================================================================
int VL6180x_RangeConfigInterrupt(VL6180xDev_t dev, uint8_t ConfigGpioInt)
{
	int status;
	if (ConfigGpioInt <= CONFIG_GPIO_INTERRUPT_NEW_SAMPLE_READY) {
		status = VL6180x_UpdateByte(dev, SYSTEM_INTERRUPT_CONFIG_GPIO,
									(uint8_t)(~CONFIG_GPIO_RANGE_MASK),
									ConfigGpioInt);
	} else {
		term_printf("Invalid config mode param %d", (int)ConfigGpioInt);
		status = INVALID_PARAMS;
	}
	return status;
}
//=============================================================================
int VL6180x_RangeSetEceFactor(VL6180xDev_t dev, uint16_t  FactorM, uint16_t FactorD)
{
	int status;
	uint8_t u8;

	do {
		/* D cannot be 0 M must be <=D and >= 0 */
		if (FactorM <= FactorD  && FactorD > 0) {
			VL6180xDevDataSet(dev, EceFactorM, FactorM);
			VL6180xDevDataSet(dev, EceFactorD, FactorD);
			/* read and re-apply max conv time to get new ece factor set */
			status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_MAX_CONVERGENCE_TIME, &u8);
			if (status) {
			//   //VL6180x_ErrLog("SYSRANGE_MAX_CONVERGENCE_TIME rd fail ");
			   break;
			}
			status = VL6180x_RangeSetMaxConvergenceTime(dev, u8);
			if (status < 0) {
			//	//VL6180x_ErrLog("fail to apply time after ece m/d change");
				break;
			}
		} else {
			////VL6180x_ErrLog("invalid factor %d/%d", (int)FactorM, (int)FactorD);
			status = INVALID_PARAMS;
		}
	} while (0);
	return status;
}
//=============================================================================
int VL6180x_RangeSetEceState(VL6180xDev_t dev, int enable)
{
	int status;
	uint8_t or_mask;
	if (enable)
		or_mask = RANGE_CHECK_ECE_ENABLE_MASK;
	else
		or_mask = 0;
	status = VL6180x_UpdateByte(dev, SYSRANGE_RANGE_CHECK_ENABLES, ~RANGE_CHECK_ECE_ENABLE_MASK, or_mask);
	return status;
}
//=============================================================================
int VL6180x_RangeSetMaxConvergenceTime(VL6180xDev_t dev, uint8_t  MaxConTime_msec)
{
	int status = 0;

	do {
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_MAX_CONVERGENCE_TIME, MaxConTime_msec);
		if (status) {
			break;
		}
		status = VL6180x_RangeSetEarlyConvergenceEestimateThreshold(dev);
		if (status) {
			break;
		}
		status = _DMax_InitData(dev);
	} while (0);

	return status;
}
//=============================================================================
int VL6180x_RangeSetInterMeasPeriod(VL6180xDev_t dev, uint32_t  InterMeasTime_msec)
{
	uint8_t SetTime;
	int status;
	do {
		if (InterMeasTime_msec > 2550) {
			status = INVALID_PARAMS;
			break;
		}
		/* doc in not 100% clear and confusing about the limit practically all value are OK but 0
		 * that can hang device in continuous mode */
		if (InterMeasTime_msec < 10) {
			InterMeasTime_msec = 10;
		}
		SetTime = (uint8_t)(InterMeasTime_msec / 10);
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_INTERMEASUREMENT_PERIOD, SetTime);
		if (status) {
			term_printf("SYSRANGE_INTERMEASUREMENT_PERIOD wr fail");
		} else if (SetTime != InterMeasTime_msec / 10) {
			status = MIN_CLIPED;  /* on success change status to clip if it did */
		}
	} while (0);
	return status;
}
//=============================================================================
int VL6180x_RangeGetDeviceReady(VL6180xDev_t dev, int *Ready)
{
	int status;
	uint8_t u8;
	status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, RESULT_RANGE_STATUS, &u8);
	if (!status)
		*Ready = u8&RANGE_DEVICE_READY_MASK;
	return status;
}
//=============================================================================
int VL6180x_RangeWaitDeviceReady(VL6180xDev_t dev, int MaxLoop)
{
	int status = 0; /* if user specify an invalid <=0 loop count we'll return error */
	int  n;
	uint8_t u8;
	if (MaxLoop < 1) {
		status = INVALID_PARAMS;
	} else {
		for (n = 0; n < MaxLoop ; n++) {
			status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, RESULT_RANGE_STATUS, &u8);
			if (status)
				break;
			u8 = u8 & RANGE_DEVICE_READY_MASK;
			if (u8)
				break;

		}
		if (!status && !u8) {
			status = TIME_OUT;
		}
	}
	return status;
}
//=============================================================================
int VL6180x_RangeSetSystemMode(VL6180xDev_t dev, uint8_t  mode)
{
	int status;
	/* FIXME we are not checking device is ready via @a VL6180x_RangeWaitDeviceReady
	 * so if called back to back real fast we are not checking
	 * if previous mode "set" got absorbed => bit 0 must be 0 so that it work
	 */
	if (mode <= 3) {
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_START, mode);
		if (status) {
		    term_printf("SYSRANGE_START wr fail");
		}
	} else {
		status = INVALID_PARAMS;
	}
	return status;
}
//=============================================================================
int VL6180x_RangeStartContinuousMode(VL6180xDev_t dev)
{
	int status;
	status = VL6180x_RangeSetSystemMode(dev, MODE_START_STOP | MODE_CONTINUOUS);
	return status;
}
//=============================================================================
int VL6180x_RangeStartSingleShot(VL6180xDev_t dev)
{
	int status;
	status = VL6180x_RangeSetSystemMode(dev, MODE_START_STOP | MODE_SINGLESHOT);
	return status;
}
//=============================================================================
static int VL6180x_RangeSetEarlyConvergenceEestimateThreshold(VL6180xDev_t dev)
{
	int status;

	const uint32_t cMicroSecPerMilliSec  = 1000;
	const uint32_t cEceSampleTime_us     = 500;
	uint32_t ece_factor_m          = VL6180xDevDataGet(dev, EceFactorM);
	uint32_t ece_factor_d          = VL6180xDevDataGet(dev, EceFactorD);
	uint32_t convergTime_us;
	uint32_t fineThresh;
	uint32_t eceThresh;
	uint8_t  u8;
	uint32_t maxConv_ms;
	int32_t AveTime;

	do {
		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_MAX_CONVERGENCE_TIME, &u8);
		if (status) {
			term_printf("SYSRANGE_MAX_CONVERGENCE_TIME rd fail");
			break;
		}
		maxConv_ms = u8;
		AveTime = _GetAveTotalTime(dev);
		if (AveTime < 0) {
			status = -1;
			break;
		}

		convergTime_us = maxConv_ms * cMicroSecPerMilliSec - AveTime;
		status = i2c1_ReadReg16Word32(VL6180x_I2C_ADDRESS, 0xB8, &fineThresh);
		if (status) {
			term_printf("reg 0xB8 rd fail");
			break;
		}
		fineThresh *= 256;
		eceThresh = ece_factor_m * cEceSampleTime_us * fineThresh / (convergTime_us * ece_factor_d);

		status = i2c1_WriteReg16Word16(VL6180x_I2C_ADDRESS, SYSRANGE_EARLY_CONVERGENCE_ESTIMATE, (uint16_t)eceThresh);
	} while (0);

	return status;
}
//=============================================================================
static int _RangeIgnore_UpdateDevice(VL6180xDev_t dev){
	int status;
	int enable;
	int threshold;
	int range;
	int or_mask;
	enable= VL6180xDevDataGet(dev, RangeIgnore.Enabled);
	if( enable ){
		// if to be nabled program first range value and threshold
		range = VL6180xDevDataGet(dev, RangeIgnore.ValidHeight);
		range /= _GetUpscale(dev);
		if( range > 255 )
			range = 255;

		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_RANGE_IGNORE_VALID_HEIGHT,  range);
		if( status ){
			goto done;
		}

		threshold = VL6180xDevDataGet(dev, RangeIgnore.IgnoreThreshold);
		status = i2c1_WriteReg16Word16(VL6180x_I2C_ADDRESS, SYSRANGE_RANGE_IGNORE_THRESHOLD,  threshold);
		if( status ){
			goto done;
		}
		or_mask = RANGE_CHECK_RANGE_ENABLE_MASK;
	}
	else{
		or_mask = 0;
	}
	status = VL6180x_UpdateByte(dev, SYSRANGE_RANGE_CHECK_ENABLES, ~RANGE_CHECK_RANGE_ENABLE_MASK, or_mask);
	_DMax_InitData(dev);
done:
	return status;
}
//=============================================================================
int VL6180x_RangeIgnoreSetEnable(VL6180xDev_t dev, int EnableState){
	int CurEnable;
	int status;

	if( EnableState )
		EnableState = 1;

	CurEnable = VL6180xDevDataGet(dev, RangeIgnore.Enabled);
	if( EnableState != CurEnable  ){
		VL6180xDevDataSet(dev, RangeIgnore.Enabled, EnableState);
		status = _RangeIgnore_UpdateDevice(dev);
	}
	return status;
}
//=============================================================================
int VL6180x_RangeIgnoreConfigure(VL6180xDev_t dev, uint16_t ValidHeight_mm, uint16_t IgnoreThreshold){
	int status;
	int enabled;

	enabled = VL6180xDevDataGet(dev, RangeIgnore.Enabled);
	VL6180xDevDataSet(dev, RangeIgnore.ValidHeight, ValidHeight_mm);
	VL6180xDevDataSet(dev, RangeIgnore.IgnoreThreshold, IgnoreThreshold);
	if(  enabled ){
		status = _RangeIgnore_UpdateDevice(dev);
	}
	else{
		status = 0;
	}

	return status;
}
//=============================================================================
/*
 * Return >0 = time
 *       <0 1 if fail to get read data from device to compute time
 */
static int32_t _GetAveTotalTime(VL6180xDev_t dev)
{
	uint32_t cFwOverhead_us = 24;
	uint32_t cVcpSetupTime_us = 70;
	uint32_t cPLL2_StartupDelay_us = 200;
	uint8_t cMeasMask = 0x07;
	uint32_t Samples;
	uint32_t SamplePeriod;
	uint32_t SingleTime_us;
	int32_t TotalAveTime_us;
	uint8_t u8;
	int status;
	status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, 0x109, &u8);
	if (status) {
		//VL6180x_ErrLog("rd 0x109 fail");
		return -1;
	}
	Samples = u8 & cMeasMask;
	status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, READOUT_AVERAGING_SAMPLE_PERIOD, &u8);
	if (status) {
		//VL6180x_ErrLog("i2c READOUT_AVERAGING_SAMPLE_PERIOD fail");
		return -1;
	}
	SamplePeriod = u8;
	SingleTime_us = cFwOverhead_us + cVcpSetupTime_us + (SamplePeriod * 10);
	TotalAveTime_us = (Samples + 1) * SingleTime_us + cPLL2_StartupDelay_us;
	return TotalAveTime_us;
}
//=============================================================================
#if VL6180x_HAVE_DMAX_RANGING
#define _GetDMaxDataRetSignalAt400mm(dev) VL6180xDevDataGet(dev, DMaxData.retSignalAt400mm)
#else
#define _GetDMaxDataRetSignalAt400mm(dev) 375 /* Use a default high value */
#endif


#if VL6180x_WRAP_AROUND_FILTER_SUPPORT

#define PRESERVE_DEVICE_ERROR_CODE		/* If uncommented, device error code will be preserved on top of wraparound error code, but this may lead to some error code instability like overflow error <==> RangingFilteringOnGoing error oscillations */
#define SENSITIVE_FILTERING_ON_GOING	/* If uncommented, filter will go back to RangingFilteringOnGoing if it must go through the std dev testing */

#define FILTER_STDDEV_SAMPLES           6
#define MIN_FILTER_STDDEV_SAMPLES       3
#define MIN_FILTER_STDDEV_SAMPLES_AFTER_FLUSH_OR_BYPASS 5
#define STDDEV_BASE_VALUE               150

#define FILTER_INVALID_DISTANCE     65535

#define _FilterData(field) VL6180xDevDataGet(dev, FilterData.field)
/*
 * One time init
 */
int _filter_Init(VL6180xDev_t dev)
{
	int i;
	_FilterData(MeasurementIndex) = 0;

	_FilterData(Default_ZeroVal) = 0;
	_FilterData(Default_VAVGVal) = 0;
	_FilterData(NoDelay_ZeroVal) = 0;
	_FilterData(NoDelay_VAVGVal) = 0;
	_FilterData(Previous_VAVGDiff) = 0;

	_FilterData(StdFilteredReads) = 0;
	_FilterData(FilteringOnGoingConsecutiveStates) = 0;

	for (i = 0; i < FILTER_NBOF_SAMPLES; i++) {
		_FilterData(LastTrueRange)[i] = FILTER_INVALID_DISTANCE;
		_FilterData(LastReturnRates)[i] = 0;
	}
	_FilterData(MeasurementsSinceLastFlush)=0;
	return 0;
}
//=============================================================================

static uint32_t _filter_StdDevDamper(uint32_t AmbientRate,
									uint32_t SignalRate,
									const uint32_t StdDevLimitLowLight,
									const uint32_t StdDevLimitLowLightSNR,
									const uint32_t StdDevLimitHighLight,
									const uint32_t StdDevLimitHighLightSNR)
{
	uint32_t newStdDev;
	uint16_t SNR;

	if (AmbientRate > 0)
		SNR = (uint16_t) ((100 * SignalRate) / AmbientRate);
	else
		SNR = 9999;

	if (SNR >= StdDevLimitLowLightSNR) {
		newStdDev = StdDevLimitLowLight;
	} else {
		if (SNR <= StdDevLimitHighLightSNR)
			newStdDev = StdDevLimitHighLight;
		else {
			newStdDev = (uint32_t)(StdDevLimitHighLight -
									(SNR - StdDevLimitHighLightSNR) *
									(StdDevLimitHighLight - StdDevLimitLowLight) /
									(StdDevLimitLowLightSNR - StdDevLimitHighLightSNR));
		}
	}

	return newStdDev;
}

//=============================================================================
/*
 * Return <0 on error
 */
static int32_t _filter_Start(VL6180xDev_t dev,
								uint16_t m_trueRange_mm,
								uint16_t m_rawRange_mm,
								uint32_t m_rtnSignalRate,
								uint32_t m_rtnAmbientRate,
								uint16_t errorCode)
{
	int status;
	uint16_t m_newTrueRange_mm = 0;
	#if VL6180x_HAVE_MULTI_READ
	uint8_t MultiReadBuf[8];
	#endif
	uint16_t i;
	uint16_t bypassFilter = 0;
	uint16_t resetVAVGData = 1;

	uint16_t filterErrorCode = NoError;
	uint16_t filterErrorCodeOnRangingErrorCode = NoError;

	uint16_t registerValue;

	uint32_t register32BitsValue1;
	uint32_t register32BitsValue2;

	uint16_t ValidDistance = 0;
	uint16_t SuspicuousRangingZone = 0;

	uint16_t WrapAroundFlag = 0;
	uint16_t NoWrapAroundFlag = 0;
	uint16_t NoWrapAroundHighConfidenceFlag = 0;

	uint16_t FlushFilter = 0;
	uint32_t RateChange = 0;

	uint16_t StdDevSamplesMinNeeded = 0;
	uint16_t StdDevSamples = 0;
	uint32_t StdDevDistanceSum = 0;
	uint32_t StdDevDistanceMean = 0;
	uint32_t StdDevDistance = 0;
	uint32_t StdDevRateSum = 0;
	uint32_t StdDevRateMean = 0;
	uint32_t StdDevRate = 0;
	uint32_t StdDevLimitWithTargetMove = 0;

	uint32_t VAVGDiff;
	uint32_t IdealVAVGDiff;
	uint32_t MinVAVGDiff;
	uint32_t MaxVAVGDiff;

	/* Filter Parameters */
	static const uint16_t ROMABLE_DATA WrapAroundLowRawRangeLimit = 60;
	static const uint32_t ROMABLE_DATA WrapAroundLowReturnRateLimit_ROM = 800;
	/* Shall be adapted depending on crossTalk */
	static const uint16_t ROMABLE_DATA WrapAroundLowRawRangeLimit2 = 165;
	static const uint32_t ROMABLE_DATA WrapAroundLowReturnRateLimit2_ROM = 180;
	/* Shall be adapted depending on crossTalk and device sensitivity*/
	static const uint32_t ROMABLE_DATA WrapAroundLowRawRangeLimit2SuspicuousAddedSignalRate = 150;


	static const uint32_t ROMABLE_DATA WrapAroundLowReturnRateFilterLimit_ROM = 850;
	/* Shall be adapted depending on crossTalk and device sensitivity*/
	static const uint16_t ROMABLE_DATA WrapAroundHighRawRangeFilterLimit = 350;
	static const uint32_t ROMABLE_DATA WrapAroundHighReturnRateFilterLimit_ROM = 1400;
	/* Shall be adapted depending on crossTalk and device sensitivity*/

	static const uint32_t ROMABLE_DATA WrapAroundMaximumAmbientRateFilterLimit = 15000;

	/*  Temporal filter data and flush values */
	static const uint32_t ROMABLE_DATA MinReturnRateFilterFlush = 75;
	static const uint32_t ROMABLE_DATA MaxReturnRateChangeFilterFlush = 50;

	/* STDDEV values and damper values */
	static const uint32_t ROMABLE_DATA StdDevLimitLowLight = STDDEV_BASE_VALUE;
	static const uint32_t ROMABLE_DATA StdDevLimitLowLightSNR = 30; /* 0.3 */
	static const uint32_t ROMABLE_DATA StdDevLimitHighLight = STDDEV_BASE_VALUE*6;
	static const uint32_t ROMABLE_DATA StdDevLimitHighLightSNR = 5; /* 0.05 */

	static const uint32_t ROMABLE_DATA StdDevHighConfidenceSNRLimit = 8;
	static const uint32_t ROMABLE_DATA StdDevNoWrapDetectedMultiplier = 4;

	static const uint32_t ROMABLE_DATA StdDevMovingTargetStdDevLimit = 90000;

	static const uint32_t ROMABLE_DATA StdDevMovingTargetReturnRateLimit = 3500;
	static const uint32_t ROMABLE_DATA StdDevMovingTargetStdDevForReturnRateLimit = STDDEV_BASE_VALUE*25;

	static const uint32_t ROMABLE_DATA MAX_VAVGDiff_ROM = 1800;
	static const uint32_t ROMABLE_DATA SuspicuousMAX_VAVGDiffRatio = 2;

	/* WrapAroundDetection variables */
	static const uint16_t ROMABLE_DATA WrapAroundNoDelayCheckPeriod = 2;
	static const uint16_t ROMABLE_DATA StdFilteredReadsIncrement = 2;
	static const uint16_t ROMABLE_DATA StdFilteredReadsDecrement = 1;
	static const uint16_t ROMABLE_DATA StdMaxFilteredReads = 4;

	uint32_t SignalRateDMax;
	uint32_t WrapAroundLowReturnRateLimit;
	uint32_t WrapAroundLowReturnRateLimit2;
	uint32_t WrapAroundLowReturnRateFilterLimit;
	uint32_t WrapAroundHighReturnRateFilterLimit;

	uint32_t MAX_VAVGDiff = 1800;

	uint8_t u8;//, u8_2;
	uint32_t XTalkCompRate_KCps;
	uint32_t StdDevLimit = 300;
	uint32_t MaxOrInvalidDistance =   255*_GetUpscale(dev);
	/* #define MaxOrInvalidDistance  (uint16_t) (255 * 3) */

	/* Check if distance is Valid or not */
	switch (errorCode) {
	case Raw_Ranging_Algo_Underflow:
	case Ranging_Algo_Underflow:
		filterErrorCodeOnRangingErrorCode = RangingFiltered; /* If we have to go through filter, mean we have here a wraparound case */
		ValidDistance = 0;
		break;
	case Raw_Ranging_Algo_Overflow:
	case Ranging_Algo_Overflow:
		filterErrorCodeOnRangingErrorCode = RangingFiltered; /* If we have to go through filter, mean we have here a wraparound case */
		//m_trueRange_mm = MaxOrInvalidDistance;
		m_trueRange_mm = 200*_GetUpscale(dev);
		ValidDistance = 1;
		break;
	default:
		if (m_rawRange_mm >= MaxOrInvalidDistance) {
			ValidDistance = 0;
			bypassFilter = 1; /* Bypass the filter in this case as produced distance is not usable (and also the VAVGVal and ZeroVal values) */
		} else {
			ValidDistance = 1;
		}
		break;
	}
	m_newTrueRange_mm = m_trueRange_mm;

	XTalkCompRate_KCps = VL6180xDevDataGet(dev, XTalkCompRate_KCps);

	/* Update signal rate limits depending on crosstalk */
	SignalRateDMax = (uint32_t)_GetDMaxDataRetSignalAt400mm(dev) ;
	WrapAroundLowReturnRateLimit = WrapAroundLowReturnRateLimit_ROM  + XTalkCompRate_KCps;
	WrapAroundLowReturnRateLimit2 = ((WrapAroundLowReturnRateLimit2_ROM *
									SignalRateDMax) / 312) +
									XTalkCompRate_KCps;
	WrapAroundLowReturnRateFilterLimit = ((WrapAroundLowReturnRateFilterLimit_ROM *
									SignalRateDMax) / 312) + XTalkCompRate_KCps;
	WrapAroundHighReturnRateFilterLimit = ((WrapAroundHighReturnRateFilterLimit_ROM *
									SignalRateDMax) / 312) + XTalkCompRate_KCps;


	/* Checks on low range data */
	if ((m_rawRange_mm < WrapAroundLowRawRangeLimit) && (m_rtnSignalRate < WrapAroundLowReturnRateLimit)) {
		filterErrorCode = RangingFiltered; /* On this condition, wraparound case is ensured */
		bypassFilter = 1;
	}
	if ((m_rawRange_mm < WrapAroundLowRawRangeLimit2) && (m_rtnSignalRate < WrapAroundLowReturnRateLimit2)) {
		filterErrorCode = RangingFiltered; /* On this condition, wraparound case is ensured */
		bypassFilter = 1;
	}
	if ((m_rawRange_mm < WrapAroundLowRawRangeLimit2) && (m_rtnSignalRate < (WrapAroundLowReturnRateLimit2 + WrapAroundLowRawRangeLimit2SuspicuousAddedSignalRate))) {
		SuspicuousRangingZone = 1; /* On this area, we are in an highly suspicuous wraparound ares, filter parameter will be stengthen */
	}


	/* Checks on Ambient rate level */
	if (m_rtnAmbientRate > WrapAroundMaximumAmbientRateFilterLimit) {
		/* Too high ambient rate */
		FlushFilter = 1;
		bypassFilter = 1;
	}
    
	/*  Checks on Filter flush */
	if (m_rtnSignalRate < MinReturnRateFilterFlush) {
		/* Completely lost target, so flush the filter */
		FlushFilter = 1;
		bypassFilter = 1;
	}
	if (_FilterData(LastReturnRates)[0] != 0) {
		if (m_rtnSignalRate > _FilterData(LastReturnRates)[0])
			RateChange = (100 *
						(m_rtnSignalRate - _FilterData(LastReturnRates)[0])) /
						_FilterData(LastReturnRates)[0];
		else
			RateChange = (100 *
						(_FilterData(LastReturnRates)[0] - m_rtnSignalRate)) /
						_FilterData(LastReturnRates)[0];
	} else
		RateChange = 0;
	if (RateChange > MaxReturnRateChangeFilterFlush) {
		FlushFilter = 1;
	}
	/* TODO optimize filter  using circular buffer */
	if (FlushFilter == 1) {
		_FilterData(MeasurementIndex) = 0;
		for (i = 0; i < FILTER_NBOF_SAMPLES; i++) {
			_FilterData(LastTrueRange)[i] = FILTER_INVALID_DISTANCE;
			_FilterData(LastReturnRates)[i] = 0;
		}
		_FilterData(MeasurementsSinceLastFlush)=0;
	} else {
		for (i = (uint16_t) (FILTER_NBOF_SAMPLES - 1); i > 0; i--) {
			_FilterData(LastTrueRange)[i] = _FilterData(LastTrueRange)[i - 1];
			_FilterData(LastReturnRates)[i] = _FilterData(LastReturnRates)[i - 1];
		}
	}

	if (ValidDistance == 1)
		_FilterData(LastTrueRange)[0] = m_trueRange_mm;
	else
		_FilterData(LastTrueRange)[0] = FILTER_INVALID_DISTANCE;
	_FilterData(LastReturnRates)[0] = m_rtnSignalRate;
	_FilterData(MeasurementsSinceLastFlush)++;

	/* Check if we need to go through the filter or not */
	if (!(((m_rawRange_mm < WrapAroundHighRawRangeFilterLimit) &&
		(m_rtnSignalRate < WrapAroundLowReturnRateFilterLimit)) ||
		((m_rawRange_mm >= WrapAroundHighRawRangeFilterLimit) &&
		(m_rtnSignalRate < WrapAroundHighReturnRateFilterLimit))))
		bypassFilter = 1;
	else {
		/* if some wraparound filtering due to some ranging error code has been detected, update the filter status and bypass the filter */
		if(filterErrorCodeOnRangingErrorCode!=NoError){
#ifndef PRESERVE_DEVICE_ERROR_CODE
			filterErrorCode = filterErrorCodeOnRangingErrorCode;
#else
			if((errorCode==Raw_Ranging_Algo_Underflow) || (errorCode==Ranging_Algo_Underflow)) {
				/* Preserves the error codes except for Raw_Ranging_Algo_Underflow and Ranging_Algo_Underflow */
				filterErrorCode = filterErrorCodeOnRangingErrorCode;
			}
#endif
			bypassFilter = 1;
			resetVAVGData = 0;
		}
	}

	/* Check which kind of measurement has been made */
	status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, 0x01AC, &u8);
	if (status) {
		//VL6180x_ErrLog("0x01AC rd fail");
		goto done_err;
	}
	registerValue = u8;

	/* Read data for filtering */
#if VL6180x_HAVE_MULTI_READ
	status = i2c1_ReadReg16Buffer(VL6180x_I2C_ADDRESS, 0x10C, MultiReadBuf, 8); /* read only 8 lsb bits */
	if (status) {
		//VL6180x_ErrLog("0x10C multi rd fail");
		goto done_err;
	}
	register32BitsValue1 = ((uint32_t) MultiReadBuf[0] << 24)
			+ ((uint32_t) MultiReadBuf[1] << 16)
			+ ((uint32_t) MultiReadBuf[2] << 8)
			+ ((uint32_t) MultiReadBuf[3] << 0);
	register32BitsValue2 = ((uint32_t) MultiReadBuf[4] << 24)
			+ ((uint32_t) MultiReadBuf[5] << 16)
			+ ((uint32_t) MultiReadBuf[6] << 8)
			+ ((uint32_t) MultiReadBuf[7] << 0);
#else
	status = i2c1_ReadReg16Word32(VL6180x_I2C_ADDRESS, 0x10C, &register32BitsValue1); /* read 32 bits, lower 17 bits are the one useful */
	if (status) {
		//VL6180x_ErrLog("0x010C rd fail");
		goto done_err;
	}
	status = i2c1_ReadReg16Word32(VL6180x_I2C_ADDRESS, 0x0110, &	register32BitsValue2); /* read 32 bits, lower 17 bits are the one useful */
	if (status) {
		//VL6180x_ErrLog("0x0110 rd fail");
		goto done_err;
	}
#endif


	if ((FlushFilter == 1) || ((bypassFilter == 1) && (resetVAVGData == 1))) {
		if (registerValue != 0x3E) {
			status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x1AC, 0x3E);
			if (status) {
				//VL6180x_ErrLog("0x01AC bypass wr fail");
				goto done_err;
			}
			//status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0F2, 0x01);
			//if (status) {
			//	//VL6180x_ErrLog("0x0F2 bypass wr fail");
			//	goto done_err;
			//}
		}
		/* Set both Default and NoDelay To same value */
		_FilterData(Default_ZeroVal) = register32BitsValue1;
		_FilterData(Default_VAVGVal) = register32BitsValue2;
		_FilterData(NoDelay_ZeroVal) = register32BitsValue1;
		_FilterData(NoDelay_VAVGVal) = register32BitsValue2;

		_FilterData(MeasurementIndex) = 0;
	} else {
		if (registerValue == 0x3E) {
			_FilterData(Default_ZeroVal) = register32BitsValue1;
			_FilterData(Default_VAVGVal) = register32BitsValue2;
		} else {
			_FilterData(NoDelay_ZeroVal) = register32BitsValue1;
			_FilterData(NoDelay_VAVGVal) = register32BitsValue2;
		}

		if (_FilterData(MeasurementIndex) % WrapAroundNoDelayCheckPeriod == 0) {
			u8 = 0x3C;
			//u8_2 = 0x05;
		} else {
			u8 = 0x3E;
			//u8_2 = 0x01;
		}
		status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x01AC, u8);
		if (status) {
			//VL6180x_ErrLog("0x01AC wr fail");
			goto done_err;
		}
		//status = i2c1_WriteReg16Byte(VL6180x_I2C_ADDRESS, 0x0F2, u8_2);
		//if (status) {
		//	//VL6180x_ErrLog("0x0F2  wr fail");
		//	goto done_err;
		//}
		_FilterData(MeasurementIndex)++;
	}

	if (bypassFilter == 1) {
		/* Do not go through the filter */

		/* Update filter error code */
		_FilterData(filterError) = filterErrorCode;

		/* Update reported range */
		if(filterErrorCode==RangingFiltered)
			m_newTrueRange_mm = MaxOrInvalidDistance; /* Set to invalid distance */

		return m_newTrueRange_mm;
	}

	/* Computes current VAVGDiff */
	if (_FilterData(Default_VAVGVal) > _FilterData(NoDelay_VAVGVal))
		VAVGDiff = _FilterData(Default_VAVGVal) - _FilterData(NoDelay_VAVGVal);
	else
		VAVGDiff = 0;
	_FilterData(Previous_VAVGDiff) = VAVGDiff;

	if(SuspicuousRangingZone==0)
		MAX_VAVGDiff = MAX_VAVGDiff_ROM;
	else
		/* In suspicuous area, strengthen the filter */
		MAX_VAVGDiff = MAX_VAVGDiff_ROM / SuspicuousMAX_VAVGDiffRatio;

	/* Check the VAVGDiff */
	if (_FilterData(Default_ZeroVal) > _FilterData(NoDelay_ZeroVal))
		IdealVAVGDiff = _FilterData(Default_ZeroVal) - _FilterData(NoDelay_ZeroVal);
	else
		IdealVAVGDiff = _FilterData(NoDelay_ZeroVal) - _FilterData(Default_ZeroVal);
	if (IdealVAVGDiff > MAX_VAVGDiff)
		MinVAVGDiff = IdealVAVGDiff - MAX_VAVGDiff;
	else
		MinVAVGDiff = 0;
	MaxVAVGDiff = IdealVAVGDiff + MAX_VAVGDiff;
	if (VAVGDiff < MinVAVGDiff || VAVGDiff > MaxVAVGDiff) {
		WrapAroundFlag = 1;
		filterErrorCode = RangingFiltered;
	} else {
		/* Go through filtering check */

		if(_FilterData(MeasurementIndex)<=1)
			/* On measurement after a bypass, uses an increase number of samples */
			StdDevSamplesMinNeeded = MIN_FILTER_STDDEV_SAMPLES_AFTER_FLUSH_OR_BYPASS;
		else
			StdDevSamplesMinNeeded = MIN_FILTER_STDDEV_SAMPLES;

		/* StdDevLimit Damper on SNR */
		StdDevLimit = _filter_StdDevDamper(m_rtnAmbientRate, m_rtnSignalRate, StdDevLimitLowLight, StdDevLimitLowLightSNR, StdDevLimitHighLight, StdDevLimitHighLightSNR);

		/* Standard deviations computations */
		StdDevSamples = 0;
		StdDevDistanceSum = 0;
		StdDevDistanceMean = 0;
		StdDevDistance = 0;
		StdDevRateSum = 0;
		StdDevRateMean = 0;
		StdDevRate = 0;
		for (i = 0; (i < FILTER_NBOF_SAMPLES) && (StdDevSamples < FILTER_STDDEV_SAMPLES); i++) {
			if (_FilterData(LastTrueRange)[i] != FILTER_INVALID_DISTANCE) {
				StdDevSamples = (uint16_t) (StdDevSamples + 1);
				StdDevDistanceSum = (uint32_t) (StdDevDistanceSum + _FilterData(LastTrueRange)[i]);
				StdDevRateSum = (uint32_t) (StdDevRateSum + _FilterData(LastReturnRates)[i]);
			}
		}
		if (StdDevSamples > 0) {
			StdDevDistanceMean = (uint32_t) (StdDevDistanceSum / StdDevSamples);
			StdDevRateMean = (uint32_t) (StdDevRateSum / StdDevSamples);
		}
		/* TODO optimize shorten Std dev in aisngle loop computation using sum of x2 - (sum of x)2 */
		StdDevSamples = 0;
		StdDevDistanceSum = 0;
		StdDevRateSum = 0;
		for (i = 0; (i < FILTER_NBOF_SAMPLES) && (StdDevSamples < FILTER_STDDEV_SAMPLES); i++) {
			if (_FilterData(LastTrueRange)[i] != FILTER_INVALID_DISTANCE) {
				StdDevSamples = (uint16_t) (StdDevSamples + 1);
				StdDevDistanceSum = (uint32_t) (StdDevDistanceSum +
									(int)(_FilterData(LastTrueRange)[i] -
											StdDevDistanceMean) *
											(int) (_FilterData(LastTrueRange)[i] -
													StdDevDistanceMean));
				StdDevRateSum = (uint32_t) (StdDevRateSum +
									(int) (_FilterData(LastReturnRates)[i] -
											StdDevRateMean) *
											(int) (_FilterData(LastReturnRates)[i] -
													StdDevRateMean));
			}
		}
		if (StdDevSamples >= StdDevSamplesMinNeeded) {
			StdDevDistance = (uint16_t) (StdDevDistanceSum / StdDevSamples);
			StdDevRate = (uint16_t) (StdDevRateSum / StdDevSamples);
		} else {
			StdDevDistance = 0;
			StdDevRate = 0;
		}

		/* Check Return rate standard deviation */
		if (StdDevRate < StdDevMovingTargetStdDevLimit) {
			if (StdDevSamples < StdDevSamplesMinNeeded) {
				//m_newTrueRange_mm = MaxOrInvalidDistance;
				filterErrorCode = RangingFiltered;
			} else {
				/* Check distance standard deviation */
				if (StdDevRate < StdDevMovingTargetReturnRateLimit)
					StdDevLimitWithTargetMove = StdDevLimit +
						(((StdDevMovingTargetStdDevForReturnRateLimit -
							StdDevLimit) * StdDevRate) /
							StdDevMovingTargetReturnRateLimit);
				else
					StdDevLimitWithTargetMove = StdDevMovingTargetStdDevForReturnRateLimit;

				if(_FilterData(filterError)==NoError){
					/* No wrapAround detected yet, so relax constraints on the std dev */
					StdDevLimitWithTargetMove = StdDevLimitWithTargetMove * StdDevNoWrapDetectedMultiplier;
				}

				if (((StdDevDistance * StdDevHighConfidenceSNRLimit) < StdDevLimit) && (StdDevSamples>=FILTER_STDDEV_SAMPLES)) {
					NoWrapAroundHighConfidenceFlag = 1;
				} else {
					if (StdDevDistance < StdDevLimitWithTargetMove) {
							NoWrapAroundFlag = 1;
						} else {
						WrapAroundFlag = 1;
						filterErrorCode = RangingFiltered;
					}
				}
			}
		} else {
			/* Target moving too fast */
			WrapAroundFlag = 1;
			filterErrorCode = RangingFiltered;
		}
	}

	if (ValidDistance == 0) {
		/* In case of invalid distance */
		if (_FilterData(StdFilteredReads) > 0)
			_FilterData(StdFilteredReads) = (uint16_t) (_FilterData(StdFilteredReads) - 1);
	} else {
		if (WrapAroundFlag == 1) {
			_FilterData(StdFilteredReads) = (uint16_t) (_FilterData(StdFilteredReads) +
											StdFilteredReadsIncrement);
			if (_FilterData(StdFilteredReads) > StdMaxFilteredReads)
				_FilterData(StdFilteredReads) = StdMaxFilteredReads;
		} else {
			if (NoWrapAroundFlag == 1) {
				if (_FilterData(StdFilteredReads) > 0) {
					filterErrorCode = RangingFiltered;
					if (_FilterData(StdFilteredReads) > StdFilteredReadsDecrement)
						_FilterData(StdFilteredReads) = (uint16_t) (_FilterData(StdFilteredReads) -
														StdFilteredReadsDecrement);
					else
						_FilterData(StdFilteredReads) = 0;
				}
			} else {
				if (NoWrapAroundHighConfidenceFlag == 1) {
					_FilterData(StdFilteredReads) = 0;
				}
			}
		}
	}

	/* If we detect a change from no Error to RangingFilteringOnGoing, then it means that
	 * the filter detected a change in te scene, so discard all previous measurements.
	 */
	if((_FilterData(filterError) == NoError) && (filterErrorCode!=NoError)) {
		for (i = 1; i < FILTER_NBOF_SAMPLES; i++) {
			_FilterData(LastTrueRange)[i] = FILTER_INVALID_DISTANCE;
			_FilterData(LastReturnRates)[i] = 0;
		}
	}

	/* Update filter error code */
	_FilterData(filterError) = filterErrorCode;

	/* Update reported range */
	if(filterErrorCode==RangingFiltered)
		m_newTrueRange_mm = MaxOrInvalidDistance; /* Set to invalid distance */

	return m_newTrueRange_mm;
done_err:
	return -1;

#undef MaxOrInvalidDistance
}

//=============================================================================
static int _filter_GetResult(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData)
{
	uint32_t m_rawRange_mm = 0;
	int32_t  FilteredRange;
	const uint8_t scaler = _GetUpscale(dev);
	uint8_t u8;
	int status;

	do {
		status = VL6180x_GetCachedByte(dev, RESULT_RANGE_RAW, &u8);
		if (status) {
		    //VL6180x_ErrLog("RESULT_RANGE_RAW rd fail");
		    break;
		}
		m_rawRange_mm = u8;

		FilteredRange = _filter_Start(dev, pRangeData->range_mm, (m_rawRange_mm * scaler), pRangeData->rtnRate, pRangeData->rtnAmbRate, pRangeData->errorStatus);
		if (FilteredRange < 0) {
		    status = -1;
		    break;
		}
		pRangeData->FilteredData.range_mm = FilteredRange;
		pRangeData->FilteredData.rawRange_mm = m_rawRange_mm * scaler;
		pRangeData->FilteredData.filterError= _FilterData(filterError);
	} while (0);
	return status;
}

#undef _FilterData
#ifdef PRESERVE_DEVICE_ERROR_CODE
#undef PRESERVE_DEVICE_ERROR_CODE
#endif
#ifdef SENSITIVE_FILTERING_ON_GOING
#undef SENSITIVE_FILTERING_ON_GOING
#endif
#undef FILTER_STDDEV_SAMPLES
#undef MIN_FILTER_STDDEV_SAMPLES
#undef MIN_FILTER_STDDEV_SAMPLES_AFTER_FLUSH_OR_BYPASS
#undef STDDEV_BASE_VALUE
#undef FILTER_INVALID_DISTANCE

#endif /* VL6180x_WRAP_AROUND_FILTER_SUPPORT */

#ifdef VL6180x_HAVE_RATE_DATA
//=============================================================================
static int _GetRateResult(VL6180xDev_t dev, VL6180x_RangeData_t *pRangeData)
{
	uint32_t m_rtnConvTime = 0;
	uint32_t m_rtnSignalRate = 0;
	uint32_t m_rtnAmbientRate = 0;
	uint32_t m_rtnSignalCount = 0;
	uint32_t m_rtnAmbientCount = 0;
	uint32_t m_refConvTime = 0;
	uint32_t cRtnSignalCountMax = 0x7FFFFFFF;
	uint32_t cDllPeriods = 6;
	uint32_t calcConvTime = 0;

	int status;

	do {
		status = VL6180x_GetCachedDWord(dev, RESULT_RANGE_RETURN_SIGNAL_COUNT, &m_rtnSignalCount);
		if (status) {
			//VL6180x_ErrLog("RESULT_RANGE_RETURN_SIGNAL_COUNT rd fail");
			break;
		}
		if (m_rtnSignalCount > cRtnSignalCountMax) {
			m_rtnSignalCount = 0;
		}

		status = VL6180x_GetCachedDWord(dev, RESULT_RANGE_RETURN_AMB_COUNT, &m_rtnAmbientCount);
		if (status) {
			//VL6180x_ErrLog("RESULT_RANGE_RETURN_AMB_COUNTrd fail");
			break;
		}


		status = VL6180x_GetCachedDWord(dev, RESULT_RANGE_RETURN_CONV_TIME, &m_rtnConvTime);
		if (status) {
			//VL6180x_ErrLog("RESULT_RANGE_RETURN_CONV_TIME rd fail");
			break;
		}

		status = VL6180x_GetCachedDWord(dev, RESULT_RANGE_REFERENCE_CONV_TIME, &m_refConvTime);
		if (status) {
			//VL6180x_ErrLog("RESULT_RANGE_REFERENCE_CONV_TIME rd fail");
			break;
		}

		pRangeData->rtnConvTime = m_rtnConvTime;
		pRangeData->refConvTime = m_refConvTime;

		calcConvTime = m_refConvTime;
		if (m_rtnConvTime > m_refConvTime) {
			calcConvTime = m_rtnConvTime;
		}
		if (calcConvTime == 0)
			calcConvTime = 63000;

		m_rtnSignalRate = (m_rtnSignalCount * 1000) / calcConvTime;
		m_rtnAmbientRate = (m_rtnAmbientCount * cDllPeriods * 1000) / calcConvTime;

		pRangeData->rtnRate = m_rtnSignalRate;
		pRangeData->rtnAmbRate = m_rtnAmbientRate;


	} while (0);
	return status;
}
#endif /* VL6180x_HAVE_RATE_DATA */

//=============================================================================
int VL6180x_DMaxSetState(VL6180xDev_t dev, int state)
{
	int status;
	LOG_FUNCTION_START("%d", state);
#if VL6180x_HAVE_DMAX_RANGING
	VL6180xDevDataSet(dev, DMaxEnable, state);
	if (state) {
		status = _DMax_InitData(dev);
	} else {
		status = 0;
	}
#else
	status =  NOT_SUPPORTED;
#endif
	LOG_FUNCTION_END(status);
	return status;
}
//=============================================================================
int VL6180x_DMaxGetState(VL6180xDev_t dev)
{
	int status;
	LOG_FUNCTION_START("");
#if VL6180x_HAVE_DMAX_RANGING
	status = VL6180xDevDataGet(dev, DMaxEnable);
#else
	status = 0;
#endif
	LOG_FUNCTION_END(status);
	return status;
}


#if VL6180x_HAVE_DMAX_RANGING

#define _DMaxData(field) VL6180xDevDataGet(dev, DMaxData.field)
/*
 * Convert fix point  x.7 to KCpount per sec
 */
//=============================================================================
#ifndef VL6180x_PLATFORM_PROVIDE_SQRT

/*
 * 32 bit integer square root with not so bad precision (integer result) and is quite fast
 * see http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
 */
uint32_t VL6180x_SqrtUint32(uint32_t num)
{
	uint32_t res = 0;
	uint32_t bit = 1 << 30; /* The second-to-top bit is set: 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;
}
#endif

//=============================================================================
/* DMax one time init */
void _DMax_OneTimeInit(VL6180xDev_t dev)
{
	_DMaxData(ambTuningWindowFactor_K) = DEF_AMBIENT_TUNING;
}

//=============================================================================
static uint32_t _DMax_RawValueAtRateKCps(VL6180xDev_t dev, int32_t rate)
{
	uint32_t snrLimit_K;
	int32_t DMaxSq;
	uint32_t RawDMax;
	DMaxFix_t retSignalAt400mm;
	uint32_t ambTuningWindowFactor_K;


	ambTuningWindowFactor_K = _DMaxData(ambTuningWindowFactor_K);
	snrLimit_K              = _DMaxData(snrLimit_K);
	retSignalAt400mm        = _DMaxData(retSignalAt400mm);
	/* 12 to 18 bits Kcps */
	if (rate > 0) {
		DMaxSq = 400 * 400 * 1000 / rate - (400 * 400 / 330);
		/* K of (1/RtnAmb -1/330 )=> 30bit- (12-18)bit  => 12-18 bits*/
		if (DMaxSq <= 0) {
		    RawDMax = 0;
		} else {
		    /* value can be more 32 bit so base on raneg apply
			 * retSignalAt400mm before or after division to presevr accuracy */
		    if (DMaxSq < (2 << 12)) {
				DMaxSq = DMaxSq * retSignalAt400mm /
							(snrLimit_K + ambTuningWindowFactor_K);
				/* max 12 + 12 to 18 -10 => 12-26 bit */
		    } else {
				DMaxSq = DMaxSq / (snrLimit_K + ambTuningWindowFactor_K) * retSignalAt400mm;
				/* 12 to 18 -10 + 12 to 18 *=> 12-26 bit */
		    }
		    RawDMax = VL6180x_SqrtUint32(DMaxSq);
		}
	} else {
		RawDMax = 0x7FFFFFFF; /* bigest possibmle 32bit signed value */
	}
	return RawDMax;
}
//=============================================================================
/*
 * fetch static data from register to avoid re-read
 * precompute all intermediate constant and cliipings
 *
 * to be re-used/call on  changes of :
 *  0x2A
 *  SYSRANGE_MAX_AMBIENT_LEVEL_MULT
 *  Dev Data XtalkComRate_KCPs
 *  SYSRANGE_MAX_CONVERGENCE_TIME
 *  SYSRANGE_RANGE_CHECK_ENABLES    mask RANGE_CHECK_RANGE_ENABLE_MASK
 *  range 0xb8-0xbb (0xbb)
 */
static int _DMax_InitData(VL6180xDev_t dev)
{
	int status, warning;
	uint8_t u8;
	uint16_t u16;
	uint32_t u32;
	uint32_t Reg2A_KCps;
	uint32_t RegB8;
	uint8_t  MaxConvTime;
	uint32_t XTalkCompRate_KCps;
	uint32_t RangeIgnoreThreshold;
	int32_t minSignalNeeded;
	uint8_t SysRangeCheckEn;
	uint8_t snrLimit;
	static const int ROMABLE_DATA MaxConvTimeAdjust = -4;

	warning = 0;

	LOG_FUNCTION_START("");
	do {
		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, 0x02A, &u8);
		if (status) {
		    //VL6180x_ErrLog("Reg 0x02A rd fail");
		    break;
		}

		if (u8 == 0) {
		    warning = CALIBRATION_WARNING;
		    u8 = 40; /* use a default average value */
		}
		Reg2A_KCps = Fix7_2_KCPs(u8); /* convert to KCPs */

		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_RANGE_CHECK_ENABLES, &SysRangeCheckEn);
		if (status) {
		    //VL6180x_ErrLog("SYSRANGE_RANGE_CHECK_ENABLES rd fail ");
		    break;
		}

		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_MAX_CONVERGENCE_TIME, &MaxConvTime);
		if (status) {
		    //VL6180x_ErrLog("SYSRANGE_MAX_CONVERGENCE_TIME rd fail ");
			break;
		}

		status = i2c1_ReadReg16Word32(VL6180x_I2C_ADDRESS, 0x0B8, &RegB8);
		if (status) {
		    //VL6180x_ErrLog("reg 0x0B8 rd fail ");
		    break;
		}

		status = i2c1_ReadReg16Byte(VL6180x_I2C_ADDRESS, SYSRANGE_MAX_AMBIENT_LEVEL_MULT, &snrLimit);
		if (status) {
		    //VL6180x_ErrLog("SYSRANGE_MAX_AMBIENT_LEVEL_MULT rd fail ");
		    break;
		}
		_DMaxData(snrLimit_K) = (int32_t)16 * 1000 / snrLimit;
		XTalkCompRate_KCps =   VL6180xDevDataGet(dev, XTalkCompRate_KCps);

		if (Reg2A_KCps >= XTalkCompRate_KCps) {
		    _DMaxData(retSignalAt400mm) = Reg2A_KCps;
		} else{
		    _DMaxData(retSignalAt400mm) = 0;
			/* Reg2A_K - XTalkCompRate_KCp <0 is invalid */
		}

		/* if xtalk range check is off omit it in snr clipping */
		if (SysRangeCheckEn&RANGE_CHECK_RANGE_ENABLE_MASK) {
		    status = i2c1_ReadReg16Word16(VL6180x_I2C_ADDRESS, SYSRANGE_RANGE_IGNORE_THRESHOLD, &u16);
		    if (status) {
				//VL6180x_ErrLog("SYSRANGE_RANGE_IGNORE_THRESHOLD rd fail ");
				break;
		    }
		    RangeIgnoreThreshold = Fix7_2_KCPs(u16);
		} else{
		    RangeIgnoreThreshold  = 0;
		}

		minSignalNeeded = (RegB8 * 256) / ((int32_t)MaxConvTime + (int32_t)MaxConvTimeAdjust);
		/* KCps 8+8 bit -(1 to 6 bit) => 15-10 bit */
		/* minSignalNeeded = max ( minSignalNeeded,  RangeIgnoreThreshold - XTalkCompRate_KCps) */
		if (minSignalNeeded  <= (int32_t)RangeIgnoreThreshold - (int32_t)XTalkCompRate_KCps)
		    minSignalNeeded  =  RangeIgnoreThreshold - XTalkCompRate_KCps;

		u32 = (minSignalNeeded*(uint32_t)snrLimit) / 16;
		_DMaxData(ClipSnrLimit) = _DMax_RawValueAtRateKCps(dev, u32);
		/* clip to dmax to min signal snr limit rate*/
	} while (0);
	if (!status)
		status = warning;
	LOG_FUNCTION_END(status);
	return status;
}
//=============================================================================
static int _DMax_Compute(VL6180xDev_t dev, VL6180x_RangeData_t *pRange)
{
	uint32_t rtnAmbRate;
	int32_t DMax;
	int scaling;
	uint16_t HwLimitAtScale;
	static const int ROMABLE_DATA rtnAmbLowLimit_KCps = 330 * 1000;

	rtnAmbRate = pRange->rtnAmbRate;
	if (rtnAmbRate  < rtnAmbLowLimit_KCps) {
		DMax = _DMax_RawValueAtRateKCps(dev, rtnAmbRate);
		scaling = _GetUpscale(dev);
		HwLimitAtScale = UpperLimitLookUP[scaling - 1];

		if (DMax > _DMaxData(ClipSnrLimit)) {
		    DMax = _DMaxData(ClipSnrLimit);
		}
		if (DMax > HwLimitAtScale) {
		    DMax = HwLimitAtScale;
		}
		pRange->DMax = DMax;
	} else {
		pRange->DMax = 0;
	}
	return 0;
}

#undef _DMaxData
#undef Fix7_2_KCPs

#endif /* VL6180x_HAVE_DMAX_RANGING */



vl6180x_lib.h

/*
 * vl6180x_lib.h
 *
 *  Created on: 5 avr. 2016
 *      Author: kerhoas
 */

#ifndef SRC_VL6180X_VL6180X_LIB_H_
#define SRC_VL6180X_VL6180X_LIB_H_

#include "main.h"
#include "vl6180x_api.h"
#include "x-nucleo-6180xa1.h"

#define ScaleDispTime       800
#define AlrmDispTime        800

#define PressBPSwicthTime   1000 /* if user keep bp press more that this mean swicth mode else rooll over use c&se in mode */

#define AlarmKeepDispTime   250  /*  alarm message retain time after it fires */

#define ALLOW_DISABLE_WAF_FROM_BLUE_BUTTON 0 /* set to 1 to add 3 extra modes to the demo where WAF is disabled (to see impact of WAF) */

#define theVL6180xDev   0x52    // what we use as "API device

#define i2c_bus      (&hi2c1)
#define def_i2c_time_out 100


#define ErrRangeDispTime    0 /* Set to 800 ms to display error code when no target os detected */
#if ErrRangeDispTime == 0
/*   supress Warning[Pe186]: pointless comparison of unsigned integer with zero */
#   ifdef __ARMCC_VERSION /* ARM/KEIL */
#   pragma diag_suppress 186
#   endif  /* _ARMCC_VERSION */
#   ifdef __ICCARM__ /* IAR */
#       pragma diag_suppress=Pe186
#   endif  /* _ARMCC_VERSION */
#endif

#define DigitDisplay_ms     1 /* ms each digit is kept on */
#if VL6180x_HAVE_DMAX_RANGING
#define DMaxDispTime     0 /* Set to 1000 to display Dmax during 1 sec when no target is detected */
#else
#define DMaxDispTime     0
#endif

#define OutORangeDispfTime  800

enum runmode_t{
    RunRangePoll=0,
    RunAlsPoll,
    InitErr,
    ScaleSwap,
    WaitForReset,
    AlrmStart,
    AlrmRun,
    FromSwitch,
};

char buffer[10];

struct state_t {
    int OutofRAnge:1;
    int AutoScale:1;
    int FilterEn:1;
    uint8_t mode;
    int8_t ScaleSwapCnt;
    uint8_t InitScale;

    uint8_t CurAlrm;
    uint8_t AlrmFired; /* just used to keep display at least min time */
}State;

uint32_t TimeStarted;       /* various display and mode delay starting time */
VL6180x_AlsData_t   Als;    /* ALS measurement */
VL6180x_RangeData_t Range;  /* Range measurmeent  */


uint16_t range;             /* range average distance */

#define AutoThreshHigh  80  /*auto scale high thresh => AutoThreshHigh *  max_raneg => scale ++  */
#define AutoThreshLow   33  /*auto scale low thresh  => AutoThreshHigh *  max_raneg => scale ++  */

volatile uint32_t g_TickCnt;

void HAL_SYSTICK_Callback(void);
void WaitMilliSec(int ms);
int BSP_GetPushButton(void);
void XNUCLEO6180XA1_UserIntHandler(void);
int VL6180x_I2CWrite(VL6180xDev_t addr, uint8_t  *buff, uint8_t len);
int VL6180x_I2CRead(VL6180xDev_t addr, uint8_t  *buff, uint8_t len);
void AbortErr( const char * msg );
void AlsState(void);
void InitAlsMode(void);
void DoScalingSwap(int scaling);
int PusbButton_WaitUnPress(void);
void AlarmShowMode(const char *msg);
void AlarmLowThreshUseCase(void);
void AlarmHighThreshUseCase(void);
void AlarmWindowThreshUseCase(void);
void AlarmUpdateUseCase(void);
void AlarmStop(void);
void AlarmInit(void);
void AlarmState(void);
void GoToAlaramState(void);
void RangeState(void);













#endif /* SRC_VL6180X_VL6180X_LIB_H_ */

vl6180x_lib.c

#include "vl6180x_lib.h"

#define BSP_BP_PORT GPIOC
#define BSP_BP_PIN  GPIO_PIN_13

char Buff[10]="---.--";
float V=0000.1;
int Alpha =(int)(0.85*(1<<16));    /* range distance running average cofs */

/***************  DISPLAY PUBLIC *********************/
const char *DISP_NextString;
/***************  DISPLAY PRIVATE *********************/
static char DISP_CurString[10];
static int DISP_Loop=0;

void DISP_ExecLoopBody(void){
    if (DISP_NextString != NULL) {
        strncpy(DISP_CurString, DISP_NextString, sizeof(DISP_CurString) - 1);
        DISP_CurString[sizeof(DISP_CurString) - 1] = 0;
        DISP_NextString = NULL;
    }
    XNUCLEO6180XA1_DisplayString(DISP_CurString, DigitDisplay_ms);
    DISP_Loop++;
}
//============================================================
void DISP_Task(const void *arg) {
    do {
        DISP_ExecLoopBody();
    } while (1);
}
//============================================================

void SetDisplayString(const char *msg) {
    DISP_NextString=msg;
}
//============================================================
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if (GPIO_Pin==GPIO_PIN_0)
	{
		XNUCLEO6180XA1_UserIntHandler();
	}
}
//============================================================

void HAL_SYSTICK_Callback(void){
    g_TickCnt++;
}
//============================================================
void XNUCLEO6180XA1_WaitMilliSec(int n){
    WaitMilliSec(n);
}
//============================================================
void WaitMilliSec(int ms){
    uint32_t start, now;
    int dif;
    start=g_TickCnt;
    do{
        now=g_TickCnt;
        dif= now -start;
    }
    while(dif<ms);
}
//============================================================
int BSP_GetPushButton(void){
    GPIO_PinState state ;
    state = HAL_GPIO_ReadPin(BSP_BP_PORT, BSP_BP_PIN);
    return state;
}
//============================================================
volatile int IntrFired=0;
/* VL6180x shield user interrupt handler */
void XNUCLEO6180XA1_UserIntHandler(void){
    IntrFired ++;
}
//=================================================================================
int VL6180x_I2CWrite(VL6180xDev_t addr, uint8_t  *buff, uint8_t len){
    int status;
    //status = HAL_I2C_Master_Transmit(i2c_bus,  addr, buff, len , def_i2c_time_out);
    status = i2c1_WriteBuffer(addr,  buff, len);
    return status;
}
//=================================================================================
int VL6180x_I2CRead(VL6180xDev_t addr, uint8_t  *buff, uint8_t len){
    int status;
    //status = HAL_I2C_Master_Receive(i2c_bus,  addr, buff, len , def_i2c_time_out);
    status = i2c1_ReadBuffer(addr,  buff, len);
    return status;
}
//=================================================================================
void AbortErr( const char * msg ){
    State.mode=  WaitForReset;
}
//=================================================================================
/**
 * ALS mode idle run loops
 */
void AlsState(void)
{
    int status;
    status = VL6180x_AlsPollMeasurement(theVL6180xDev, &Als);
    if (status) {
       // SetDisplayString("Er 4");
    } else {
        if (Als.lux > 9999) {
        	term_printf("L----\n\r" );
        }
        else if (Als.lux > 999) {
        	term_printf("LUM:%d.%d\n\r", (int) Als.lux / 1000, (int) (Als.lux % 1000) / 10); /* show LX.YY  X k Lux 2 digit*/
        	sprintf(buffer, "L%d.%02d", (int) Als.lux / 1000, (int) (Als.lux % 1000) / 10); /* show LX.YY  X k Lux 2 digit*/
        } else {
        	term_printf( "lum:%d\n\r", (int) Als.lux);
        	sprintf(buffer, "l%3d", (int) Als.lux);
        }

        SetDisplayString( buffer );
    }
}
//=================================================================================

void InitAlsMode(void){
    //anything after prepare and prior to go into AlsState
    int time = 100;
    VL6180x_AlsSetIntegrationPeriod(theVL6180xDev, time);
}
//=================================================================================
/**
 * Manage UI and state for scale change
 *
 * @param scaling the next scaling factor
 */
void DoScalingSwap(int scaling){
    if( State.AutoScale){
        if( State.FilterEn ){
        					SetDisplayString("Sf A");
        					term_printf("Sf A");
        					}

		else 				{
							SetDisplayString("Sc A");
							term_printf("Sc A");
							}
    }
    else{
        if( State.FilterEn )
        {
			term_printf("Sf %d\n\r", (int)scaling);
        	sprintf(buffer, "Sf %d", (int)scaling);
        }
        	else
        {
        	term_printf("Sc %d\n\r", (int)scaling);
    		sprintf(buffer, "Sc %d", (int)scaling);
        }
        SetDisplayString(buffer);

    }
    State.mode = ScaleSwap;
    TimeStarted=g_TickCnt;
}
//=================================================================================
/**
 * When button is already pressed it Wait for user to release it
 * if button remain pressed for given time it return true
 * These is used to detect mode switch by long press on blue Push Button
 *
 * As soon as time is elapsed -rb- is displayed  to let user know order
 * the  request to switch mode is taken into account
 *
 * @return True if button remain pressed more than specified time
 */
int PusbButton_WaitUnPress(void){
    TimeStarted = g_TickCnt;
    while( !BSP_GetPushButton() ){ ; //
        DISP_ExecLoopBody();
        if( g_TickCnt - TimeStarted> PressBPSwicthTime){
        	term_printf(" rb \n\r");
        }
    }
    return  g_TickCnt - TimeStarted>PressBPSwicthTime;

}
//=================================================================================
void AlarmShowMode(const char *msg)
{
   // SetDisplayString( msg);
    TimeStarted=g_TickCnt;
    do {
       // DISP_ExecLoopBody();
    } while (g_TickCnt - TimeStarted < AlrmDispTime);
}
//=================================================================================
void AlarmLowThreshUseCase(void){
    AlarmShowMode("A-Lo");

    /* make sure from now on all register in group are not fetched by device */
    VL6180x_SetGroupParamHold(theVL6180xDev, 1);

    /* get interrupt whenever we go below 200mm */
    VL6180x_RangeSetThresholds(theVL6180xDev, 200, 0, 0 );
    /* set range interrupt reporting low threshold*/
    VL6180x_RangeConfigInterrupt(theVL6180xDev, CONFIG_GPIO_INTERRUPT_LEVEL_LOW);

    /* leave device peak up all new register in group */
    VL6180x_SetGroupParamHold(theVL6180xDev, 0);

    /* clear any interrupt that should ensure a new edge get generated even if we missed it */
    VL6180x_RangeClearInterrupt(theVL6180xDev);
}
//=================================================================================
void AlarmHighThreshUseCase(void){
    AlarmShowMode("A-hi");
    /* make sure from now on all register in group are not fetched by device */
    VL6180x_SetGroupParamHold(theVL6180xDev, 1);

    /* get interrupt whenever  higher than 200mm (low threshold don't care) */
    VL6180x_RangeSetThresholds(theVL6180xDev, 0, 200, 0 );

    /* set range interrupt reporting high threshold*/
    VL6180x_RangeConfigInterrupt(theVL6180xDev, CONFIG_GPIO_INTERRUPT_LEVEL_HIGH);

    /* leave device peak up all new register in group */
    VL6180x_SetGroupParamHold(theVL6180xDev, 0);

    /* clear any interrupt that should ensure a new edge get generated even if we missed it */
    VL6180x_RangeClearInterrupt(theVL6180xDev);
}
//=================================================================================
void AlarmWindowThreshUseCase(void){

    AlarmShowMode("A-0o");

    /* make sure from now on all register in group are not fetched by device */
    VL6180x_SetGroupParamHold(theVL6180xDev, 1);

    /* get interrupt whenever  out of  100mm  250mm  range */
    VL6180x_RangeSetThresholds(theVL6180xDev, 100, 200, 0 );

    /* set range interrupt reporting out of window  */
    VL6180x_RangeConfigInterrupt(theVL6180xDev, CONFIG_GPIO_INTERRUPT_OUT_OF_WINDOW);

    /* leave device peak up all new register in group */
    VL6180x_SetGroupParamHold(theVL6180xDev, 0);

    /* clear any interrupt that should ensure a new edge get generated even if we missed it */
    VL6180x_RangeClearInterrupt(theVL6180xDev);
}
//=================================================================================
void AlarmUpdateUseCase(void)
{
    State.CurAlrm =(State.CurAlrm%3);

    switch ( State.CurAlrm) {
    case 0: /* low thresh */
        AlarmLowThreshUseCase();
        break;
    case 1: /* high thresh */
        AlarmHighThreshUseCase();;
        break;
    case 2: /* out of window */
        AlarmWindowThreshUseCase();
    }
    VL6180x_RangeClearInterrupt(theVL6180xDev); /* clear any active interrupt it will ensure we get a new active edge is raised */
}
//=================================================================================

void AlarmStop(void){
    VL6180x_RangeSetSystemMode(theVL6180xDev, MODE_CONTINUOUS|MODE_START_STOP);
    /* Wait some time for last potential measure to stop ?
     * TODO can we poll check something to avoid that delay? */
    HAL_Delay(100);
    /* Clear any left pending interrupt
     * these is not mandatory or a left uncleared status can mess-up next intr mode change and status check  without a prior intr clear */
    VL6180x_ClearAllInterrupt(theVL6180xDev);

    /* Anover way to stop is to switch and trigger a single shot measure (in a safe way)
     * set interrupt report mode new sample ready
     * clear interrupt
     * kick of a measure
     * poll for measure ready
     * all that can take up to arround 2x max convergence time typically set to 50ms  */

}

//=================================================================================
/**
 * Initiate alarm (interrupt mode on distance threshold)
 */
void AlarmInit(void){
    State.mode = AlrmRun;
    TimeStarted=g_TickCnt;
    uint16_t InterMeasPeriod=50; /* 10 ms is the minimal */
    /* We assume device is stopped  */

    VL6180x_Prepare(theVL6180xDev);
    /* Increase convergence time to the max (this is because proximity config of API is used) */
    VL6180x_RangeSetMaxConvergenceTime(theVL6180xDev, 63);
    /* set max upscale so we can work up to some  50cm */
    VL6180x_UpscaleSetScaling(theVL6180xDev, 3);

    /* set inter measurement period (that is in fact inter measure time)
     * note that when low refresh rate  is need time like 100ms is best to keep power low  */
    VL6180x_RangeSetInterMeasPeriod(theVL6180xDev, InterMeasPeriod);
    /* if fast reaction is required then set a time of 0 (will set minimal possible) */
    /* VL6180x_RangeSetInterMeasPeriod(theVL6180xDev, 0); */

    /* setup gpio1 pin to range interrupt output with high polarity (rising edge) */
    VL6180x_SetupGPIO1(theVL6180xDev, GPIOx_SELECT_GPIO_INTERRUPT_OUTPUT, INTR_POL_HIGH);
    /* set threshold for current used case and update the display */
    AlarmUpdateUseCase();
    /* enable interrupt at CPU level */
    //XNUCLEO6180XA1_EnableInterrupt();
    /*Clear any pending device interrupt even if already active it should force a new edge so we can pick up*/
    VL6180x_ClearAllInterrupt(theVL6180xDev);

    /* start continuous mode */
    VL6180x_RangeSetSystemMode(theVL6180xDev, MODE_START_STOP|MODE_CONTINUOUS);
    /* from now vl6180x is running on it's own and will interrupt us when condition is met
     * the interrupt set a flag peek-up in AlarmState run loop*/
}
//=================================================================================
/**
 * Alarm mode idle run
 *
 * We only here look at the volatile interrupt flags set that from isr
 * the isr manage to clear interrupt at cpu level
 * we Here clear and re-arm/clear interrupt at the the device level and do the UI and display
 */
void AlarmState(void){
    IntrStatus_t IntStatus;
    int status;

    if (IntrFired != 0) {
    /* Interrupt did fired Get interrupt  causes */
        status = VL6180x_RangeGetInterruptStatus(theVL6180xDev, &IntStatus.val);
        if (status) {
            AbortErr("Al 1");
            goto done;
        }
        switch( IntStatus.status.Range ) {
        case RES_INT_STAT_GPIO_LOW_LEVEL_THRESHOLD :
          term_printf("L---");
            break;
        case RES_INT_STAT_GPIO_HIGH_LEVEL_THRESHOLD :
        	term_printf("H---");
            break;
        case RES_INT_STAT_GPIO_OUT_OF_WINDOW :
            term_printf("O---");
            break;
        case RES_INT_STAT_GPIO_NEW_SAMPLE_READY:
        	term_printf("n---");
            break;
        }
        VL6180x_RangeClearInterrupt(theVL6180xDev); /* clear it */
        IntrFired = 0;
        TimeStarted=g_TickCnt;
        State.AlrmFired = 1;
    }
    else{
        int flush=0;
        //sanity check we are not in a state where i/o is active without an edge
        if( g_TickCnt-TimeStarted> 5000 ){
            if( flush )
                VL6180x_RangeClearInterrupt(theVL6180xDev); /* clear it */
            TimeStarted=g_TickCnt;
        }
    }
    if( State.AlrmFired ){
        /* After an interrupt fire keep the display message for some minimal time
         * over wise it could not be visible at all */
        if( g_TickCnt-TimeStarted > AlarmKeepDispTime )
            State.AlrmFired = 0;
    }
    else{
        switch( State.CurAlrm ){
            case 0 :
            	term_printf("alarm = Low\n\r");
                break;
            case 1 :
               	term_printf("alarm = High\n\r");
                break;
            case 2:
             	term_printf("alarm = Window\n\r");
                break;
        }
    }
    /* keep On refreshing display at every idle loop */
    DISP_ExecLoopBody();

    if( !BSP_GetPushButton() ){
        // when button get presses wait it get release (keep doing display)
        status = PusbButton_WaitUnPress();
        if( status ){
            // BP stay pressed very long time switch back to range/als
            AlarmStop();
            State.mode=FromSwitch;
        }
        else{
            //BP short pressed switch use case
            State.CurAlrm=(State.CurAlrm+1)%3;
            AlarmUpdateUseCase();
        }
    }

done:
    ;
}

//=================================================================================
void GoToAlaramState(void) {
    AlarmInit();
}
//=================================================================================
/**
 * Ranging mode idle loop
 */
void RangeState(void) {
    int status;
    uint16_t hlimit;
    uint8_t scaling;

    scaling = VL6180x_UpscaleGetScaling(theVL6180xDev);
    status = VL6180x_RangePollMeasurement(theVL6180xDev, &Range); /* these invoke dipslay for  polling */
    if (status) {
        AbortErr("Er r");
        return;
    }

    hlimit = VL6180x_GetUpperLimit(theVL6180xDev);
    if (Range.range_mm >= (hlimit * AutoThreshHigh) / 100 && scaling < 3 && State.AutoScale) {
        VL6180x_UpscaleSetScaling(theVL6180xDev, scaling + 1);
    }
    if (Range.range_mm < (hlimit * AutoThreshLow) / 100 && scaling > 1 && State.AutoScale) {
        VL6180x_UpscaleSetScaling(theVL6180xDev, scaling - 1);
    }

    if (Range.errorStatus) {
        /* no valid ranging*/
        if (State.OutofRAnge) {
#if VL6180x_HAVE_DMAX_RANGING
            if (g_TickCnt - TimeStarted >= ErrRangeDispTime &&  g_TickCnt - TimeStarted <  ErrRangeDispTime + DMaxDispTime ){
                    term_printf("d%d", (int)Range.DMax);
                    //SetDisplayString(buffer);
            }
            else

#endif
            if(g_TickCnt - TimeStarted < ErrRangeDispTime  )
            {

                term_printf("rE%d\n\r", (int) Range.errorStatus);
               // SetDisplayString(buffer);
            }
            else{
                State.OutofRAnge=0; /* back to out of range display */
                TimeStarted=g_TickCnt;
            }
        }
        else {
            int FilterEn;
#if VL6180x_WRAP_AROUND_FILTER_SUPPORT
            FilterEn = VL6180x_FilterGetState(theVL6180xDev);
            if (FilterEn && VL6180x_RangeIsFilteredMeasurement(&Range) ){
                SetDisplayString("F---");
            }
            else
                SetDisplayString("r---");
#else
            SetDisplayString("r---");
#endif
            if( g_TickCnt - TimeStarted > OutORangeDispfTime ) {
                State.OutofRAnge = 1;
                TimeStarted = g_TickCnt;
            }
        }
    }
    else {
        State.OutofRAnge = 0;
        TimeStarted = g_TickCnt;
        range = (range * Alpha + Range.range_mm * ((1 << 16) - Alpha)) >> 16;
    	term_printf("range:%d\n\r", (int) range);
    	sprintf(buffer,"r%d",(int)range);
        if (State.AutoScale) {
            if (scaling == 1) {
                buffer[0] = '_';
            }
            else
                if (scaling == 2)
                    buffer[0] = '=';
                else
                    buffer[0] = '~';
        }

        SetDisplayString(buffer);
    }

#define max_scale 3
    if (!BSP_GetPushButton()) {
        TimeStarted = g_TickCnt;
        status = PusbButton_WaitUnPress();
        if (status) {
            GoToAlaramState();
            return;
        }
        State.ScaleSwapCnt++;
        if (State.ScaleSwapCnt % (max_scale + 1) == max_scale) {
            State.AutoScale = 1;
            scaling = max_scale;
        }
        else {
#if ALLOW_DISABLE_WAF_FROM_BLUE_BUTTON
            /* togle filtering every time we roll over all scaling(pass by autoscale) */
            if (State.AutoScale)
                State.FilterEn = !State.FilterEn;
#endif
            State.AutoScale = 0;
            scaling = State.InitScale + (State.ScaleSwapCnt % max_scale);
            if (scaling > max_scale)
                scaling = scaling - (max_scale);
        }

        status = VL6180x_UpscaleSetScaling(theVL6180xDev, scaling);
        if (status<0) {
            AbortErr("ErUp");
            State.mode = InitErr;
        }
        else {
            /* do not check status may fail when filter support not active */
            VL6180x_FilterSetState(theVL6180xDev, State.FilterEn);
            DoScalingSwap(scaling);
        }
    }
}



x-nucleo-6180xa1.h

/*
 * x-nucleo-6180xa1.h
 *
 *  Created on: 5 avr. 2016
 *      Author: kerhoas
 */

#ifndef SRC_VL6180X_X_NUCLEO_6180XA1_H_
#define SRC_VL6180X_X_NUCLEO_6180XA1_H_

#include "types.h"
#include "main.h"



#define SWITCH_VAL_RANGING  0



/* function below must be provided  */
void XNUCLEO6180XA1_WaitMilliSec(int SegDelayMs);
/* optional list */
void XNUCLEO6180XA1_UserIntHandler(void);

/* provided */
void XNUCLEO6180XA1_Init();
void XNUCLEO6180XA1_DisplayString(const char *str, int SegDelayMs);

void XNUCLEO6180XA1_ClearInterrupt(void);

int XNUCLEO6180XA1_GetSwitch(void);
void XNUCLEO6180XA1_Reset(int state);


/**
 * @brief  tio be called by HAL EXTI handler dispatecher
 * @warning to be called only aftrer @a XNUCLEO6180XA1_I2C1_Init() get called
 * @param pin
 * @return  non 0 if the GPIO_pin is the GPIO pin for active VL6180x GPIO int line
 */
int XNUCLEO6180XA1_EXTI_CallBackHandle(uint16_t GPIO_Pin);


/*all function below only valid for v2 */
#define XNUCLEO6180XA1_ID_TOP   0
#define XNUCLEO6180XA1_ID_BOT   1
#define XNUCLEO6180XA1_ID_LEFT  2
#define XNUCLEO6180XA1_ID_RIGHT 3
int XNUCLEO6180XA1_ResetId(int state, int id);

#define GPMR    0x10 		// Monitor Pin State Register
#define GPSR    0x12 		// Set Pin State Register
#define GPDR    0x14 		// Set Pin Direction Register

#define V2_D1       (1<<7)
// second byte or word MSB
#define V2_D2       (1<<8)
#define V2_D3       (1<<9)
#define V2_D4       (1<<10)
#define V2_DISP_SEL (1<<11)
#define V2_CHIPEN   (1<<12)
#define V2_CHIPEN_B (1<<13)
#define V2_CHIPEN_L (1<<14)
#define V2_CHIPEN_R (1<<15)


//====================================================================
/**
 * Display digit enable pad/pin LUT
 * D1 is left most digit  (ms nibble) on the display
 * D3 is right most digit (ls nibble) on the display
 */
#define PA  0
#define PB  1
#define PC  2
#define MAKE_PAD(port, pin)  (((port)<<4)|pin)


#undef MAKE_PAD
#undef PA
#undef PB
#undef PC

#define pad_write(pad, state)   HAL_GPIO_WritePin( (void*)((char*)GPIOA + (pad>>4)*((char*)GPIOB-(char*)GPIOA)), 1<<(pad&0x0F), state);

/*
   --s0--
   s    s
   5    1
   --s6--
   s    s
   4    2
   --s3-- s7

 */

#define DP  (1<<7)
#define NOT_7_NO_DP( ... ) (uint8_t) ~( __VA_ARGS__ + DP )
#define S0 (1<<0)
#define S1 (1<<1)
#define S2 (1<<2)
#define S3 (1<<3)
#define S4 (1<<4)
#define S5 (1<<5)
#define S6 (1<<6)

/* refer to http://www.twyman.org.uk/Fonts/ */
static const uint8_t ascii_to_display_lut[256]={
      [' ']=           0,
      ['-']=           S6,
      ['_']=           S3,
      ['=']=           S3+S6,
      ['~']=           S0+S3+S6, /* 3 h bar */
      ['^']=           S0, /* use as top bar */

      ['?']=           NOT_7_NO_DP(S5+S3+S2),
      ['*']=           NOT_7_NO_DP(),
      ['[']=           S0+S3+S4+S5,
      [']']=           S0+S3+S2+S1,
      ['@']=           S0+S3,

      ['0']=           NOT_7_NO_DP(S6),
      ['1']=           S1+S2,
      ['2']=           S0+S1+S6+S4+S3,
      ['3']=           NOT_7_NO_DP(S4+S5),
      ['4']=           S5+S1+S6+S2,
      ['5']=           NOT_7_NO_DP(S1+S4),
      ['6']=           NOT_7_NO_DP(S1),
      ['7']=           S0+S1+S2,
      ['8']=           NOT_7_NO_DP(0),
      ['9']=           NOT_7_NO_DP(S4),

      ['a']=           S2+ S3+ S4+ S6 ,
      ['b']=           NOT_7_NO_DP(S0+S1),
      ['c']=           S6+S4+S3,
      ['d']=           NOT_7_NO_DP(S0+S5),
      ['e']=           NOT_7_NO_DP(S2),
      ['f']=           S6+S5+S4+S0, /* same as F */
      ['g']=           NOT_7_NO_DP(S4), /* same as 9 */
      ['h']=           S6+S5+S4+S2,
      ['i']=           S4,
      ['j']=           S1+S2+S3+S4,
      ['k']=           S6+S5+S4+S2, /* a h */
      ['l']=           S3+S4,
      ['m']=           S0+S4+S2, /* same as  */
      ['n']=           S2+S4+S6,
      ['o']=           S6+S4+S3+S2,
      ['p']=           NOT_7_NO_DP(S3+S2), // same as P
      ['q']=           S0+S1+S2+S5+S6,
      ['r']=           S4+S6,
      ['s']=           NOT_7_NO_DP(S1+S4),
      ['t']=           NOT_7_NO_DP(S0+S1+S2),
      ['u']=           S4+S3+S2+S5+S1, // U
      ['v']=           S4+S3+S2, // is u but u use U
      ['w']=           S1+S3+S5,
      ['x']=           NOT_7_NO_DP(S0+S3), // similar to H
      ['y']=           NOT_7_NO_DP(S0+S4),
      ['z']=           S0+S1+S6+S4+S3, // same as 2

      ['A']=           NOT_7_NO_DP(S3),
      ['B']=           NOT_7_NO_DP(S0+S1), /* as b  */
      ['C']=           S0+S3+S4+S5, // same as [
      ['E']=           NOT_7_NO_DP(S1+S2),
      ['F']=           S6+S5+S4+S0,
      ['G']=           NOT_7_NO_DP(S4), /* same as 9 */
      ['H']=           NOT_7_NO_DP(S0+S3),
      ['I']=           S1+S2,
      ['J']=           S1+S2+S3+S4,
      ['K']=           NOT_7_NO_DP(S0+S3), /* same as H */
      ['L']=           S3+S4+S5,
      ['M']=           S0+S4+S2, /* same as  m*/
      ['N']=           S2+S4+S6, /* same as n*/
      ['O']=           NOT_7_NO_DP(S6),
      ['P']=           S0+S1+S2+S5+S6, // sames as 'q'
      ['Q']=           NOT_7_NO_DP(S3+S2),
      ['R']=           S4+S6,
      ['S']=           NOT_7_NO_DP(S1+S4), /* sasme as 5 */
      ['T']=           NOT_7_NO_DP(S0+S1+S2), /* sasme as t */
      ['U']=           NOT_7_NO_DP(S6+S0),
      ['V']=           S4+S3+S2, // is u but u use U
      ['W']=           S1+S3+S5,
      ['X']=           NOT_7_NO_DP(S0+S3), // similar to H
      ['Y']=           NOT_7_NO_DP(S0+S4),
      ['Z']=           S0+S1+S6+S4+S3, // same as 2


};

#undef S0
#undef S1
#undef S2
#undef S3
#undef S4
#undef S5
#undef S6
#undef DP

#endif /* SRC_VL6180X_X_NUCLEO_6180XA1_H_ */

x-nucleo-6180xa1.c


#include "x-nucleo-6180xa1.h"
#include "main.h"
#include "drv_i2c.h"

#define V2_IRQ_PIN          GPIO_PIN_0
#define V2_IRQ EXTI0_IRQn

uint16_t _V2PadVal; // gpio SR value caching to avoid reading on each new bit set

static int _err=0;

static void _V2_DisplayOff(void);
static void _V2_SetChipEn( int No, int state );
static int _V2_GetSwicth(void);
static  void _V2_Set7Segment( int Leds, int digit );

//====================================================================
// @brief Default  do nothing interrupt callback
//====================================================================
#pragma weak XNUCLEO6180XA1_UserIntHandler
void  XNUCLEO6180XA1_UserIntHandler(void)
{
}
//====================================================================
// Init XNUCLEO6180XA1 Expander
//====================================================================
void XNUCLEO6180XA1_Init(I2C_HandleTypeDef *hi2c1) {

    uint8_t ExpanderID[2];
    uint16_t PadDir;

    i2c1_ReadRegBuffer(EXPANDER_I2C_ADDRESS,0, ExpanderID,2);

    PadDir=~V2_DISP_SEL;	    // expander config
    i2c1_WriteRegBuffer(EXPANDER_I2C_ADDRESS, GPDR,  (uint8_t*)&PadDir, 2);
    _V2_DisplayOff();

}
//====================================================================
int XNUCLEO6180XA1_EXTI_CallBackHandle(uint16_t GPIO_Pin)
{
        XNUCLEO6180XA1_UserIntHandler();
        return 0;
}

//====================================================================
/**
 *
 * @param No    0= top , 1= Left, 2=Bottom 3=Right
 * @param state
 */
static void _V2_SetChipEn( int No, int state ){

	int mask = (No==3) ? V2_CHIPEN_R : ((No==2) ? V2_CHIPEN_B : ((No==1) ? V2_CHIPEN_L : V2_CHIPEN));
    if( state)
        _V2PadVal|=mask ;
    else
        _V2PadVal&=~mask;

    i2c1_WriteRegBuffer(EXPANDER_I2C_ADDRESS, GPSR, (uint8_t*)&_V2PadVal, 2); // Set Pin State Register

}
//====================================================================
void XNUCLEO6180XA1_Reset(int state)
{
        _V2_SetChipEn(0, state);
}
//====================================================================
int XNUCLEO6180XA1_ResetId(int state, int id)
{
        _V2_SetChipEn(id, state);
        return 0;
}
//====================================================================
// Get Switch Button (red one) to choose between 'ALS' and 'range'
//====================================================================
int XNUCLEO6180XA1_GetSwitch(void){
    GPIO_PinState state ;
    state= _V2_GetSwicth() ? GPIO_PIN_SET : GPIO_PIN_RESET ;
    return state;
}
//====================================================================
int _V2_GetSwicth(){
    int status;
    uint16_t Value;
    status = i2c1_ReadRegBuffer(EXPANDER_I2C_ADDRESS,GPMR, (uint8_t*)&Value,2);
    if(status ==0 ){
        Value&=V2_DISP_SEL;
    }
    else{
        _err++;
        Value=0;
    }
    return Value;
}

//====================================================================
// Display string on 7 segments
//====================================================================
void XNUCLEO6180XA1_DisplayString(const char *str, int SegDelayMs){
    int i;
    const char *pc;

    for( i=0, pc=str; i<4 && *pc!=0 ; i++, pc++){
        _V2_Set7Segment( ascii_to_display_lut[(uint8_t)*pc], i);
        if( *(pc+1)== '.'){
            pc++;
        }
    }
    XNUCLEO6180XA1_WaitMilliSec(SegDelayMs);
    _V2_DisplayOff();
 }
//====================================================================
// Update 7 segment display
//====================================================================
static  void _V2_Set7Segment( int Leds, int digit ){
    _V2PadVal |= 0x7F; /* clear 7 seg bits */
    _V2PadVal |= V2_D1|V2_D2|V2_D3|V2_D4; /* all segment off */
    _V2PadVal &= ~(V2_D1<<digit);         /* digit on */
    _V2PadVal &= ~(Leds&0x7F);

    i2c1_WriteRegBuffer(EXPANDER_I2C_ADDRESS, GPSR, (uint8_t*)&_V2PadVal, 2);
}

//====================================================================
// Clear 7 segments
//====================================================================
static void _V2_DisplayOff() {
    _V2PadVal |= (V2_D1|V2_D2|V2_D3| V2_D4); /* segment en off */
    i2c1_WriteRegBuffer(EXPANDER_I2C_ADDRESS, GPSR, (uint8_t*)&_V2PadVal, 2);
}
//====================================================================


Carte IKS01A2 : capteur de pression LPS22HB et d’humidité HTS221

schematic IKS01A2

Datasheet LPS22HB

Technical Note LPS22HB

Datasheet HTS221

Technical Note HTS221