/**
  ******************************************************************************
  * @file          : app_tof.c
  * @author        : IMG SW Application Team
  * @brief         : This file provides code for the configuration
  *                  of the STMicroelectronics.X-CUBE-TOF1.3.2.0 instances.
  ******************************************************************************
  *
  * @attention
  *
  * Copyright (c) 2022 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "app_tof.h"
#include "main.h"
#include "sys_app.h"
#include <stdio.h>

//#include "VL53L1X_ULP_api.h"
//#include "53l1a2_ranging_sensor.h"
#include "stm32wlxx_nucleo.h"
#ifdef STS_P2
#include "VL53L1X_api.h"
#endif
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
#define TIMING_BUDGET (30U) /* 16 ms < TimingBudget < 500 ms */
#define POLLING_PERIOD (250U) /* refresh rate for polling mode (milliseconds, shall be consistent with TimingBudget value) */

/* Private variables ---------------------------------------------------------*/
//static RANGING_SENSOR_Capabilities_t Cap;
//static RANGING_SENSOR_ProfileConfig_t Profile;
//static int32_t status = 0;

volatile uint8_t ToF_EventDetected = 0;
uint16_t sensor_id=0;

/* Private function prototypes -----------------------------------------------*/
#ifdef	STS_P2
uint8_t sts_vl53lx_ranging(uint16_t *ranged_distance, uint8_t range_mode, uint16_t distance_threshold_mm,
		uint16_t inter_measurement_ms, uint16_t macro_timing,uint16_t roi_width, uint16_t sigma_mm, uint16_t signal_kcps);
#endif
uint8_t IsInterruptDetected(uint16_t dev);
#ifdef	STS_P2
void STS_TOF_VL53LX_Range_Process(uint8_t range_mode, uint16_t *range_distance);
#endif
void MX_TOF_Init(void)
{
  /* USER CODE BEGIN SV */

  /* USER CODE END SV */

  /* USER CODE BEGIN TOF_Init_PreTreatment */

  /* USER CODE END TOF_Init_PreTreatment */

  /* Initialize the peripherals and the TOF components */
  APP_LOG(TS_OFF,VLEVEL_L,"\r\n######################    MX TOF Init... \r\n");

  //MX_53L1A2_SimpleRanging_Init();
  //STS_TOF_VL53LX_PeopleCounting_Process();
  /* USER CODE BEGIN TOF_Init_PostTreatment */

  /* USER CODE END TOF_Init_PostTreatment */
}


/*
 * LM background task
 */
uint16_t MX_TOF_Ranging_Process(void)
{	uint16_t range_distance=0;
	uint8_t range_mode = 2; //STS_TOF_LONG_RANGE;
#ifdef	STS_P2
	STS_TOF_VL53LX_Range_Process(range_mode, &range_distance);
	APP_LOG(TS_OFF, VLEVEL_M, "\n VL53L1 Range distance =%u mm \n\r", (uint16_t)range_distance);
#endif
	return (uint16_t) range_distance;
}
void MX_TOF_Process(void)
{
  /* USER CODE BEGIN TOF_Process_PreTreatment */

  /* USER CODE END TOF_Process_PreTreatment */


	//APP_LOG(TS_OFF,VLEVEL_L,"\r\n######################    MX TOF Process... \r\n");
	//STS_TOF_VL53LX_Range_Process();
	//STS_TOF_VL53LX_PeopleCounting_Process();

	//sts_tof_vl53lx_peoplecount_subprocess();

  /* USER CODE BEGIN TOF_Process_PostTreatment */

  /* USER CODE END TOF_Process_PostTreatment */
}

uint8_t IsInterruptDetected(uint16_t dev)
{
	// To be filled with customer HW. This function should
	// return 1 when an interrupt is raised by the ToF on GPIO1 pin (pin7)
	if (ToF_EventDetected )
	{
		APP_LOG(TS_OFF, VLEVEL_L,"###############   TOF EVENT DETECTED \r\n");
		ToF_EventDetected =0;
		return 1;
	} else {
		return 0;
	}
}
#ifdef 	STS_P2
void STS_TOF_VL53LX_Range_Process(uint8_t range_mode, uint16_t *range_distance)
{
	//uint8_t vl53lx_model = STS_TOF_VL53L1X;
	//uint8_t range_mode = STS_TOF_SHORT_RANGE;
	uint16_t	i_distance_measured = 0;
	uint16_t	i_distance_threshold_mm = 800;
	uint16_t	i_inter_measurement_ms=100, i_macro_timing=33;
	uint16_t	i_roi_width=16, i_sigma_mm=30, i_signal_kcps=2000;

	switch (range_mode)
	{
		case STS_TOF_SHORT_RANGE:
			// STS ---002  for short distance
			/* Example for robust and short distance measurements. Max distance reduced
				 * but very low number of false-positives */
				 //status |= VL53L1X_ULP_SetSigmaThreshold(dev, 30);
				//status |= VL53L1X_ULP_SetSignalThreshold(dev, 2000);
			i_sigma_mm = 30;		//increase this for longer distance, reduce for shorter distance
			i_signal_kcps = 2000;		// 1000-  6000 kcps
			i_distance_threshold_mm = 900;
			i_inter_measurement_ms = 100;		// 100 - 1000 ms
			i_macro_timing = 100;
			//i_roi_width = 16;

		break;

		case STS_TOF_LONG_RANGE:
			// STS --- 003 for long range
			/* Relax some limits. Be careful, it can create false-positives !*/
			//status |= VL53L1X_ULP_SetSigmaThreshold(dev, 60);
			//status |= VL53L1X_ULP_SetSignalThreshold(dev, 1200);
			i_sigma_mm = 85;		// increase this for longer distance, reduce for short distance
			i_signal_kcps = 1000;		// 1000-  6000 kcps
			i_distance_threshold_mm = 4000;	//4000;
			i_inter_measurement_ms = 200;			// 100 - 1000 ms
			i_macro_timing = 30;				// 1 - 100 ms
			i_roi_width = 8;


		break;

		case STS_TOF_LOW_POWER_RANGE:
			// STS---001   for ultra low power
			/* Reduce the macro timing to minimum. This is equivalent as reducing the integration time */
			//status = VL53L1X_ULP_SetMacroTiming(dev, 1);
			i_distance_threshold_mm = 4000;
			i_inter_measurement_ms = 100;			// 100 - 1000 ms
			i_macro_timing = 1;
			/* Reduce at maximum the SPADS */
			//status = VL53L1X_ULP_SetROI(dev, 4);
			i_roi_width = 4;

		break;
		default:
		break;
	}

	sts_vl53lx_ranging(&i_distance_measured, range_mode, i_distance_threshold_mm, i_inter_measurement_ms,i_macro_timing, i_roi_width, i_sigma_mm, i_signal_kcps);
	APP_LOG(TS_OFF, VLEVEL_M, "I_DISTANCE_MEASURED = %d \n", i_distance_measured);
	*range_distance = i_distance_measured;

}

void BSP_PB_Callback(Button_TypeDef Button)
{
  //PushButtonDetected = 1;
}


uint8_t sts_vl53lx_ranging(uint16_t *ranged_distance, uint8_t range_mode, uint16_t distance_threshold_mm, uint16_t inter_measurement_ms, uint16_t macro_timing,
uint16_t roi_width, uint16_t sigma_mm, uint16_t signal_kcps)
{
	  uint8_t status=0, dev=0x52;
	  uint16_t estimated_distance_mm=0;
	  status = VL53L1X_SensorInit(dev);
	  status += VL53L1X_SetDistanceMode(dev, 2);  /* 1=short, 2=long, DISTANCE_MODE */
	  status += VL53L1X_SetTimingBudgetInMs(dev, 100);  /* TIMING_BUDGET, in ms possible values [15, 20, 50, 100, 200, 500] */
	  status += VL53L1X_SetInterMeasurementInMs(dev, 50);
	  status += VL53L1X_SetROI(dev, 8, 8); /* minimum ROI 4,4 */
	  if (status != 0) {
		  APP_LOG(TS_OFF, VLEVEL_L,"Initialization or configuration of the device\n");
	    return (-1);
	  }
	  status = VL53L1X_StartRanging(dev);   /* This function has to be called to enable the ranging */
	  if (status != 0) {
	  		  APP_LOG(TS_OFF, VLEVEL_L,"Start Range failed\n");
	  	    return (-1);
	  }

		status = VL53L1X_GetDistance(dev, &estimated_distance_mm);
		APP_LOG(TS_OFF,VLEVEL_M,"Target detected! Distance =%d mm \r\n", estimated_distance_mm );
		*ranged_distance = estimated_distance_mm;
		status = VL53L1X_StopRanging(dev);
		APP_LOG(TS_OFF,VLEVEL_M,"End of VL53L1X Ranging Process\n");
		return status;

#if 0
	/*********************************/
	/*   VL53L1X ranging variables  */
	/*********************************/
	uint8_t 				status, loop;
	uint8_t 				dev;
	//uint16_t 				sensor_id=0;
	uint8_t 				measurement_status;
	uint16_t 				estimated_distance_mm, r_signal_kcps, r_sigma_mm, r_ambient_kcps;
	/*********************************/
	/*      Customer platform        */
	/*********************************/
	/* Default VL53L1X Ultra Low Power I2C address */
	dev = 0x52;

	/* (Optional) Change I2C address */
	// status = VL53L1X_ULP_SetI2CAddress(dev, 0x52);
	// dev = 0x20;

	/*********************************/
	/*   Power on sensor and init    */
	/*********************************/
	APP_LOG(TS_OFF,VLEVEL_L,"Range Mode =%d \r\n",range_mode);
	/* (Optional) Check if there is a VL53L1X sensor connected */
	status = VL53L1X_GetSensorId(dev, &sensor_id);
	APP_LOG(TS_OFF,VLEVEL_L,"VL53L1X address =%X\r\n",sensor_id );
	if(status || (sensor_id != 0xEACC))
	{
		APP_LOG(TS_OFF,VLEVEL_L,"VL53L1X not detected at requested address\n");
		return status;
	}
	/* (Mandatory) Init VL53L1X sensor */
	status = VL53L1X_SensorInit(dev);
	if(status)
	{
		APP_LOG(TS_OFF,VLEVEL_L,"VL53L1X ultra low power Loading failed\n");
		//HAL_Delay(100);
		return status;
	}
	APP_LOG(TS_OFF,VLEVEL_L,"VL53L1X ultra low power ready ! \r\n");
	/*********************************/
	/*     Sensor configuration      */
	/*********************************/
	/* (Optional) Program sensor to raise an interrupt ONLY below 300mm */
	//status = VL53L1X_SetInterruptConfiguration(dev, distance_threshold_mm, 1);  //i_distance_threshold_mm
	status = VL53L1X_SetDistanceThreshold(dev, distance_threshold_mm,distance_threshold_mm, 0,1);  //i_distance_threshold_mm
	/* (Optional) Program a 10Hz ranging frequency */
	status = VL53L1X_SetInterMeasurementInMs(dev, inter_measurement_ms);			// range_interval_ms
	/* Increase the macro timing. This is equivalent as increasing the integration time */
	//status = VL53L1X_SetMacroTiming(dev, macro_timing);				// micro_timing_ms
	status = VL53L1X_SetTimingBudgetInMs(dev, macro_timing);
	/* Enable all the SPADS */
	status = VL53L1X_SetROI(dev, roi_width, roi_width);						// SPADS { 1 -- 16 }

	if(range_mode != STS_TOF_LOW_POWER_RANGE)
	{
		/* Example for robust and short distance measurements. Max distance reduced
		 * but very low number of false-positives */
		status |= VL53L1X_SetSigmaThreshold(dev, sigma_mm);
		status |= VL53L1X_SetSignalThreshold(dev, signal_kcps);
	}

	/*********************************/
	/*         Ranging loop          */
	/*********************************/
	status = VL53L1X_StartRanging(dev);
	if(status)
	{
		APP_LOG(TS_OFF,VLEVEL_L,"VL53L1X_ULP_StartRanging failed with status %u\n", status);
		return status;
	}
	APP_LOG(TS_OFF,VLEVEL_L,"Ranging started. Put your hand close to the sensor to generate an interrupt...\n");
	loop = 0;
	while(loop < 20)
	{
		/* Use this external function to detect when a hardware interrupt is generated on PIN 7 (GPIO1). It means that a new measurement is ready.
		 */

		if(IsInterruptDetected(dev))
		{
			/* (Mandatory) Clear HW interrupt to restart measurements */
			VL53L1X_ClearInterrupt(dev);
			/* Dump debug data */
#if 0
			status = VL53L1X_DumpDebugData(dev, &measurement_status,
						&estimated_distance_mm, &r_sigma_mm, &r_signal_kcps, &r_ambient_kcps);
			*ranged_distance = estimated_distance_mm;
			APP_LOG(TS_OFF,VLEVEL_L,"Target detected! Interrupt raised by sensor, Distance =%d mm \r\n", estimated_distance_mm );
#endif
			status = VL53L1X_GetDistance(dev, &estimated_distance_mm);
			APP_LOG(TS_OFF,VLEVEL_L,"Target detected! Interrupt raised by sensor, Distance =%d mm \r\n", estimated_distance_mm );
			loop++;
		}
	}

	status = VL53L1X_StopRanging(dev);
	APP_LOG(TS_OFF,VLEVEL_L,"End of VL53L1X ultra low power demo\n");
	return status;
#endif
}
#endif

#ifdef __cplusplus
}
#endif