/**
  *
  * Copyright (c) 2023 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.
  *
  ******************************************************************************
  */


/***********************************/
/*    VL53LMZ ULD CNH Data		   */
/***********************************/
/*
* This example how to configure, capture and decode CNH data from
* the VL53L7CH/VL53LCH sensors.
*
* In this example, we also suppose that the number of targets per zone is
* set to 1(see file platform.h).
*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>


#include "vl53lmz_api.h"
#include "vl53lmz_plugin_cnh.h"


int example12(void)
{
	/*********************************/
	/*   VL53LMZ ranging variables  */
	/*********************************/

	uint8_t 				status, loop, isAlive, isReady, i;
	VL53LMZ_Configuration 	Dev;					/* Sensor configuration */
	VL53LMZ_ResultsData 	Results;				/* Results data from VL53LMZ */

	VL53LMZ_Motion_Configuration 	cnh_config;		/* Motion Configuration is shared with CNH */

	cnh_data_buffer_t 		cnh_data_buffer;		/* cnh_data_bufer_t is sized to take the largest data transfer  */
													/* possible from the device. If smaller CNH configuration is 	*/
													/* used then cnh_data_buffer size could be make smaller.		*/

	uint32_t 				cnh_data_size;			/* This will be used to record the actual size of CNH data 		*/
													/* generated by the set CNH configuration.						*/

	int agg_id, bin_num;
	float amb_value, bin_value;

	/* variables needed for call to vl53lmz_cnh_get_mem_block_addresses() */
	int32_t					*p_hist = NULL;
	int8_t					*p_hist_scaler = NULL;
	int32_t					*p_ambient = NULL;
	int8_t					*p_ambient_scaler = NULL;

	/*********************************/
	/*      Customer platform        */
	/*********************************/

	/* Fill the platform structure with customer's implementation. For this
	* example, only the I2C address is used.
	*/
	Dev.platform.address = VL53LMZ_DEFAULT_I2C_ADDRESS;

	/* (Optional) Reset sensor toggling PINs (see platform, not in API) */
	//Reset_Sensor(&(Dev.platform));

	/* (Optional) Set a new I2C address if the wanted address is different
	* from the default one (filled with 0x20 for this example).
	*/
	//status = vl53lmz_set_i2c_address(&Dev, 0x20);

	
	/*********************************/
	/*   Power on sensor and init    */
	/*********************************/

	/* (Optional) Check if there is a VL53LMZ sensor connected */
	status = vl53lmz_is_alive(&Dev, &isAlive);
	if(!isAlive || status)
	{
		printf("VL53LMZ not detected at requested address\n");
		return status;
	}

	/* (Mandatory) Initialise the VL53LMZ sensor */
	status = vl53lmz_init(&Dev);
	if(status)
	{
		printf("VL53LMZ ULD Loading failed\n");
		return status;
	}

	printf("VL53LMZ ULD ready ! (Version : %s)\n",
			VL53LMZ_API_REVISION);


	/*********************************/
	/*  Set basic ranging settings   */
	/*********************************/
	status = vl53lmz_set_resolution(&Dev, 16);
	status |= vl53lmz_set_ranging_mode(&Dev, VL53LMZ_RANGING_MODE_AUTONOMOUS);
	status |= vl53lmz_set_ranging_frequency_hz(&Dev, 5);
	status |= vl53lmz_set_integration_time_ms(&Dev, 20);
	if(status)
	{
		printf("ERROR - Failed basic configuration sequence, status=%u\n", status);
		return status;
	}


	/*********************************/
	/*  CNH specific configuration   */
	/*********************************/

	/* Populate the basic CNH parameters into the CNH configuration structure */
	status = vl53lmz_cnh_init_config( &cnh_config,
										0,		/* StartBin 	*/
										24,		/* NumBins   	*/
										4 );	/* SubSample 	*/

	if (status != VL53LMZ_STATUS_OK){
		printf("ERROR at %s(%d) : vl53lmz_cnh_init_config failed : %d\n",__func__, __LINE__,status);
		return status;
	}

	/* Add the aggregate map that maps zones to aggregates. Resolution of map 	*/
	/* must follow that set by vl53lmz_set_resolution(), either 16 or 64 zones.	*/
	status = vl53lmz_cnh_create_agg_map( &cnh_config,
											16,				/* Resolution. Must match value used in vl53lmz_set_resolution() */
											0,				/* StartX 		*/
											0,				/* StartY 		*/
											1,				/* MergeX		*/
											1,				/* MergeY		*/
											4,				/* Cols			*/
											4 );			/* Rows 		*/
	if (status != VL53LMZ_STATUS_OK){
		printf("ERROR at %s(%d) : vl53lmz_cnh_create_agg_map failed : %d\n",__func__, __LINE__,status);
		return status;
	}

	/* Check that the requested configuration will not generate CNH data that is 		*/
	/* too large for the available space on the sensor.									*/
	/* Store the size of data generate so we can next setup an optimize data transfer 	*/
	/* from sensor to host.																*/
	status = vl53lmz_cnh_calc_required_memory( &cnh_config, &cnh_data_size );
	if (status != VL53LMZ_STATUS_OK){
		printf("ERROR at %s(%d) : vl53lmz_cnh_calc_required_memory : %d\n",__func__, __LINE__,status);
		if (cnh_data_size < 0){
			printf("Required memory is too high : %lu.	Maximum is %lu!\n", cnh_data_size, VL53LMZ_CNH_MAX_DATA_BYTES);
		}
		return status;
	}

	/* Send this CNH configuration to the sensor.										*/
	status = vl53lmz_cnh_send_config(&Dev,&cnh_config);
	if (status != VL53LMZ_STATUS_OK){
		printf("ERROR at %s(%d) : vl53lmz_cnh_send_config failed : %d\n",__func__, __LINE__,status);
		return status;
	}

	/* Because we want to use a non-standard data transfer from the device we can not   	*/
	/* use the standard vl53lmz_start_ranging() function, instead we need to use  			*/
	/* vl53lmz_create_output_config() followed by vl53lmz_send_output_config_and_start() 	*/
	/* This allows us to modify the data transfer requested between the two functions.		*/

	/* First create the standard data upload(output) configuration. 						*/
	status = vl53lmz_create_output_config(&Dev);
	if (status != VL53LMZ_STATUS_OK){
		printf("ERROR at %s(%d) : vl53lmz_create_output_config failed : %d\n",__func__, __LINE__,status);
		return status;
	}

	/* Next, add the CNH data block, sized correctly for the configuration we are using. */
	union Block_header cnh_data_bh;
	cnh_data_bh.idx = VL53LMZ_CNH_DATA_IDX;
	cnh_data_bh.type = 4;
	cnh_data_bh.size = cnh_data_size / 4;
	status = vl53lmz_add_output_block(&Dev, cnh_data_bh.bytes);
	if (status != VL53LMZ_STATUS_OK){
		printf("ERROR at %s(%d) : vl53lmz_add_output_block failed : %d\n",__func__, __LINE__,status);
		return status;
	}

	/*********************************/
	/*  Start the sensor ranging     */
	/*********************************/

	/* Finally, send the output configuration and start the sensor ranging. */
 	status = vl53lmz_send_output_config_and_start(&Dev);

   	printf("Started ranging\n");

   	loop = 0;
   	while(loop < 10)
   	{
   		status = vl53lmz_check_data_ready(&Dev, &isReady);
   		if(isReady)
   		{
   			vl53lmz_get_ranging_data(&Dev, &Results);

   			/* As the sensor is set in 4x4 mode by default, we have a total of 16 zones */
   			/* to print. This example assumes VL53LMZ_NB_TARGET_PER_ZONE == 1 */
   			printf("Print data no : %3u\n", Dev.streamcount);
   			for(i = 0; i < 16; i++)
   			{
				printf("Zone : %3d, Status : %3u, Distance : %4d mm\n",
					i,
					Results.target_status[VL53LMZ_NB_TARGET_PER_ZONE*i],
					Results.distance_mm[VL53LMZ_NB_TARGET_PER_ZONE*i]);
   			}

   			/* Because we use a non-standard upload configuration for CNH data we   */
   			/* must extract the data from the ULD transfer buffer and place it in   */
   			/* our own data area before accessing it.								*/
			status = vl53lmz_results_extract_block( &Dev, VL53LMZ_CNH_DATA_IDX, (uint8_t *)cnh_data_buffer, cnh_data_size );
			if (status != VL53LMZ_STATUS_OK){
				printf("ERROR at %s(%d) : vl53lmz_results_extract_block failed : %d\n",__func__, __LINE__,status);
				return status;
			}

   			for(agg_id = 0; agg_id < cnh_config.nb_of_aggregates; agg_id++)
   			{
   				/* Start address of each aggregates data blocks within the cnh_data_buffer depends	*/
   				/* on the exact CNH configuration in use. Function below calculates these start 	*/
   				/* locations for us.																*/
   				vl53lmz_cnh_get_block_addresses( &cnh_config,
   													agg_id,
   													cnh_data_buffer,
   													&(p_hist), &(p_hist_scaler),
   													&(p_ambient), &(p_ambient_scaler));

   				/* there is just a single ambient value per aggregate */
   				amb_value = ((float)*p_ambient)/(2<<*p_ambient_scaler);
				printf("Agg, %2d, Ambient, % .1f, Bins, ", agg_id, amb_value );

				for( bin_num = 0; bin_num < cnh_config.feature_length; bin_num++ ) {
					bin_value = ((float)p_hist[bin_num])/(2<<p_hist_scaler[bin_num]);
					printf("% .1f, ",bin_value);
				}

				printf("\n");
   			}

   			loop++;
   		}

		/* Wait a few ms to avoid too high polling (function in platform
		 * file, not in API) */
   		WaitMs(&(Dev.platform), 5);
   	}

   	status = vl53lmz_stop_ranging(&Dev);
   	printf("Stop ranging autonomous\n");

   	printf("End of ULD demo\n");
   	return status;
}