/*
 * VEML6031X00_Application_Library.c
 *
 * Created  : 20 August 2021
 * Modified : 13 June 2023
 * Author   : HWanyusof
 * Version	: 1.2
 */

#include "VEML6031X00_Prototypes.h"
#include "VEML6031X00.h"
#include "I2C_Functions.h"
#include "VEML6031X00_Application_Library.h"

extern int I2C_Bus;

//****************************************************************************************************
//***************************************Application API**********************************************


/*Determine Resolution (in lux/count) From ALS_IT, ALS_GAIN and PD_DIV4
 *VEML6031X00_CAL_Resolution(Byte PD_DIV4, Byte ALS_IT, Byte ALS_GAIN)
 *Byte PD_DIV - Input Parameter:
 *
 * VEML6031X00_PD_DIV4_FULL
 * VEML6031X00_PD_DIV4_QUARTER
 *
 *Byte ALS_IT - Input Parameter:
 *
 * VEML6031X00_ALS_IT_3_125ms
 * VEML6031X00_ALS_IT_6_25ms
 * VEML6031X00_ALS_IT_12_5ms
 * VEML6031X00_ALS_IT_25ms
 * VEML6031X00_ALS_IT_50ms
 * VEML6031X00_ALS_IT_100ms
 * VEML6031X00_ALS_IT_200ms
 * VEML6031X00_ALS_IT_400ms
 *
 *Byte ALS_GAIN - Input Parameter:
 *
 * VEML6031X00_ALS_GAIN_x0_5
 * VEML6031X00_ALS_GAIN_x0_66
 * VEML6031X00_ALS_GAIN_x1
 * VEML6031X00_ALS_GAIN_x2
 *
 *Info: Refer to Table 9 & 10 in Datasheet Page 10
 *
 *returns resolution (lux/count)
 */
float VEML6031X00_CAL_Resolution(Byte PD_DIV4, Byte ALS_IT, Byte ALS_GAIN)
{
    float Resolution;
    // For the whole PD size (High sensitivity)
    if(PD_DIV4 == VEML6031X00_PD_DIV4_FULL)
    {
        if (ALS_IT == VEML6031X00_ALS_IT_400ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.0034;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.0068;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.0103;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.0136;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_200ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.0068;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.0136;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.0206;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.0272;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_100ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.0136;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.0272;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.0412;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.0544;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_50ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.0272;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.0544;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.0824;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.1088;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_25ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.0544;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.1088;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.1648;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.2176;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_12_5ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.1088;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.2176;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.3297;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.4352;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_6_25ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.2176;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.4352;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.6594;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.8704;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_3_125ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.4352;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.8704;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 1.3188;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 1.7408;
        }
    }
    // For a quarter of the PD size (Quarter sensitivity)
    if(PD_DIV4 == VEML6031X00_PD_DIV4_QUARTER)
    {
        if (ALS_IT == VEML6031X00_ALS_IT_400ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.0136;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.0272;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.0412;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.0544;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_200ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.0272;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.0544;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.0824;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.1088;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_100ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.0544;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.1088;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.1648;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.2176;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_50ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.1088;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.2176;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.3297;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.4352;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_25ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.2176;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.4352;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 0.6594;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 0.8704;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_12_5ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.4352;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 0.8704;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 1.3188;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 1.7408;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_6_25ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 0.8704;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 1.7408;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 2.6376;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 3.4816;
        }
        if (ALS_IT == VEML6031X00_ALS_IT_3_125ms)
        {
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x2) Resolution = 1.7408;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x1) Resolution = 3.4816;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66) Resolution = 5.2752;
            if (ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5) Resolution = 6.9632;
        }
    }
    return(Resolution);
}

/*Calculate the ALS Lux
 *VEML6031X00_CAL_Lux(float Resolution, float Count)
 *float Resolution - output from VEML6031X00_CAL_Resolution(Byte PD_DIV4, Byte ALS_IT, Byte ALS_GAIN)
 *float Count - output from VEML6031X00_GET_ALS_Data()
 *
 *returns lux
 */
float VEML6031X00_CAL_Lux(float Resolution, float Count)
{
    float Lux;
    Lux = Resolution*Count;
    return(Lux);
}

/*Get Delay for Measurement
 *VEML6031X00_GET_Delay()
 *returns delay in ms
 */
int VEML6031X00_GET_Delay()
{
	int Delay;

	//Delay for ALS
	//Delay = Delay from IT + Circuit (~10ms)
	if (VEML6031X00_GET_ALS_IT_Bits() == 1) {Delay = 15;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 2) {Delay = 20;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 3) {Delay = 25;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 4) {Delay = 40;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 5) {Delay = 80;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 6) {Delay = 150;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 7) {Delay = 280;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 8) {Delay = 500;}

	return Delay;
}

//Wait for measurement function
void Wait()
{
    #ifdef STM32F

        HAL_Delay(VEML6031X00_GET_Delay());

    #endif

	#ifdef Cypress

        CyDelay(VEML6031X00_GET_Delay());

    #endif

	#ifdef Arduino

       delay(VEML6031X00_GET_Delay());

    #endif
}

/*Get ALS_IT
 *VEML6031X00_GET_ALS_IT()
 *returns ALS_IT
 */
Byte VEML6031X00_GET_ALS_IT()
{

	if (VEML6031X00_GET_ALS_IT_Bits() == 1) {return VEML6031X00_ALS_IT_3_125ms;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 2) {return VEML6031X00_ALS_IT_6_25ms;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 3) {return VEML6031X00_ALS_IT_12_5ms;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 4) {return VEML6031X00_ALS_IT_25ms;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 5) {return VEML6031X00_ALS_IT_50ms;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 6) {return VEML6031X00_ALS_IT_100ms;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 7) {return VEML6031X00_ALS_IT_200ms;}
	if (VEML6031X00_GET_ALS_IT_Bits() == 8) {return VEML6031X00_ALS_IT_400ms;}
	else
	return 0;
}

/*Get ALS_GAIN
 *VEML6031X00_GET_ALS_GAIN()
 *returns ALS_GAIN
 */
Byte VEML6031X00_GET_ALS_GAIN()
{

	if (VEML6031X00_GET_ALS_GAIN_Bits() == 1) {return VEML6031X00_ALS_GAIN_x1;}
	if (VEML6031X00_GET_ALS_GAIN_Bits() == 2) {return VEML6031X00_ALS_GAIN_x2;}
	if (VEML6031X00_GET_ALS_GAIN_Bits() == 3) {return VEML6031X00_ALS_GAIN_x0_66;}
	if (VEML6031X00_GET_ALS_GAIN_Bits() == 4) {return VEML6031X00_ALS_GAIN_x0_5;}
	else
	return 0;
}

/*Get PD_DIV4
 *VEML6031X00_GET_PD_DIV4()
 *returns PD_DIV4
 */
Byte VEML6031X00_GET_PD_DIV4()
{

	if (VEML6031X00_GET_PD_DIV4_Bit() == 0) {return VEML6031X00_PD_DIV4_FULL;}
	if (VEML6031X00_GET_PD_DIV4_Bit() == 1) {return VEML6031X00_PD_DIV4_QUARTER;}
	else
	return 0;
}

/*Get ALS Mode
 *returns the ALS mode status of the sensor as follows:
 *
 * 0 - ALS Shutdown Mode
 * 1 - AF Mode
 * 2 - Auto Mode
 *
 */
int VEML6031X00_GET_ALS_Mode()
{
	int Mode;

	//Read the SD bit: Mode = 0 - ALS Shutdown
	if ((VEML6031X00_GET_SD_Bit() == 0b1) && (VEML6031X00_GET_ALS_IR_SD_Bit() == 0b1)) Mode = 0;

	//Read the ALS_AF bit: Mode = 1 - AF Mode
	if ((VEML6031X00_GET_SD_Bit() == 0b0) && (VEML6031X00_GET_ALS_IR_SD_Bit() == 0b0) && (VEML6031X00_GET_ALS_AF_Bit() == 0b1)) Mode = 1;

	//Read the ALS_AF bit: Mode = 2 - Auto Mode
	if ((VEML6031X00_GET_SD_Bit() == 0b0) && (VEML6031X00_GET_ALS_IR_SD_Bit() == 0b0) && (VEML6031X00_GET_ALS_AF_Bit() == 0b0)) Mode = 2;

	return Mode;
}

//Reset the Sensor to the default value
void Reset_Sensor()
{
	struct TransferData VEML6031X00_Data;
	VEML6031X00_Data.Slave_Address = VEML6031X00_Slave_Address;
	VEML6031X00_Data.RegisterAddress = VEML6031X00_ALS_CONF_0;
	VEML6031X00_Data.Select_I2C_Bus = I2C_Bus;
	VEML6031X00_Data.WData[0] = 0x01;
	VEML6031X00_Data.WData[1] = 0x00;
	WriteI2C_Bus(&VEML6031X00_Data);

	VEML6031X00_Data.Slave_Address = VEML6031X00_Slave_Address;
	VEML6031X00_Data.RegisterAddress = VEML6031X00_ALS_WH_L;
	VEML6031X00_Data.Select_I2C_Bus = I2C_Bus;
	VEML6031X00_Data.WData[0] = 0x00;
	VEML6031X00_Data.WData[1] = 0x00;
	WriteI2C_Bus(&VEML6031X00_Data);

	VEML6031X00_Data.Slave_Address = VEML6031X00_Slave_Address;
	VEML6031X00_Data.RegisterAddress = VEML6031X00_ALS_WL_L;
	VEML6031X00_Data.Select_I2C_Bus = I2C_Bus;
	VEML6031X00_Data.WData[0] = 0x00;
	VEML6031X00_Data.WData[1] = 0x00;
	WriteI2C_Bus(&VEML6031X00_Data);
}

//Print the output of the sensor
void Print_Data_Only()
{
	Word ALS_Data;
	Word IR_Data;
	float Resolution;
	float Lux;
	Byte ALS_IT;
	Byte ALS_GAIN;
	Byte PD_DIV4;
	Byte Interrupt;

	#ifdef STM32F

		#define TRANSMIT_BUFFER_SIZE  128
		char   TransmitBuffer[TRANSMIT_BUFFER_SIZE];
		char   TransmitBuffer2[TRANSMIT_BUFFER_SIZE];

		HAL_Delay(300);

		//Active Force Mode
		if(VEML6031X00_GET_ALS_Mode() == 1)
		{
			//Set the active force mode trigger
			VEML6031X00_SET_ALS_TRIG(VEML6031X00_ALS_TRIG_EN);

			//Wait for data ready flag
			while(!VEML6031X00_GET_AF_DATA_READY_FLAG())
			{
				Wait();
			}
		}

		//Auto Mode
		if(VEML6031X00_GET_ALS_Mode() == 2)
		{
			//Delay of IT ms + other Circuit Delay (~10ms)
			Wait();
		}

		//Read the ALS channels output data
		ALS_Data = VEML6031X00_GET_ALS_DATA();

		//Read the needed parameters to determine the resolution for  channel
		ALS_IT = VEML6031X00_GET_ALS_IT();
		ALS_GAIN = VEML6031X00_GET_ALS_GAIN();
		PD_DIV4 = VEML6031X00_GET_PD_DIV4();

		//Determine Resolution (in lux/count) From ALS_IT, ALS_GAIN and PD_DIV4
		Resolution = VEML6031X00_CAL_Resolution(PD_DIV4, ALS_IT, ALS_GAIN);

		//Calculate Lux for the  channel
		Lux = VEML6031X00_CAL_Lux(Resolution, ALS_Data);

		//Read the IR channel
		IR_Data = VEML6031X00_GET_IR_DATA();

		/* Print the ALS channel data */
		sprintf(TransmitBuffer,"ALS Channel : %d Counts \r\n",ALS_Data);
		CDC_Transmit_FS(TransmitBuffer,strlen(TransmitBuffer));
		HAL_Delay(50);

		/* Print the resolution for the ALS channel */
		ftoa(Resolution,TransmitBuffer, 6);
		sprintf(TransmitBuffer2,"Resolution (ALS Channel) : %s Lux/Count \r\n",TransmitBuffer);
		CDC_Transmit_FS(TransmitBuffer2,strlen(TransmitBuffer2));
		HAL_Delay(50);

		/* Print the lux values */
		ftoa(Lux,TransmitBuffer, 6);
		sprintf(TransmitBuffer2,"Lux (ALS Channel) : %s Lux \r\n",TransmitBuffer);
		CDC_Transmit_FS(TransmitBuffer2,strlen(TransmitBuffer2));
		HAL_Delay(50);

		/* Print the IR channel data */
		sprintf(TransmitBuffer,"IR Channel : %d Counts \r\n",IR_Data);
		CDC_Transmit_FS(TransmitBuffer,strlen(TransmitBuffer));
		HAL_Delay(50);

		//Auto Mode
		if(VEML6031X00_GET_ALS_Mode() == 2)
		{
			//Read interrupt flag register
			Interrupt = VEML6031X00_GET_ALS_INT();
			HAL_Delay(50);

			/* Print the interrupt register */
			sprintf(TransmitBuffer,"Interrupt : 0x%x \r\n",Interrupt);
			CDC_Transmit_FS(TransmitBuffer,strlen(TransmitBuffer));
			HAL_Delay(50);
		}

		sprintf(TransmitBuffer," \r\n");
		CDC_Transmit_FS(TransmitBuffer,strlen(TransmitBuffer));
		HAL_Delay(50);

	#endif

	#ifdef Cypress

		#define TRANSMIT_BUFFER_SIZE  128
		char   TransmitBuffer[TRANSMIT_BUFFER_SIZE];
		char   TransmitBuffer2[TRANSMIT_BUFFER_SIZE];

		CyDelay(300);

		//Active Force Mode
		if(VEML6031X00_GET_ALS_Mode() == 1)
		{
			//Set the active force mode trigger
			VEML6031X00_SET_ALS_TRIG(VEML6031X00_ALS_TRIG_EN);

			//Wait for data ready flag
			while(!VEML6031X00_GET_AF_DATA_READY_FLAG())
			{
				Wait();
			}
		}

		//Auto Mode
		if(VEML6031X00_GET_ALS_Mode() == 2)
		{
			//Delay of IT ms + other Circuit Delay (~10ms)
			Wait();
		}

		//Read the ALS channels output data
		ALS_Data = VEML6031X00_GET_ALS_DATA();

		//Read the needed parameters to determine the resolution for  channel
		ALS_IT = VEML6031X00_GET_ALS_IT();
		ALS_GAIN = VEML6031X00_GET_ALS_GAIN();
		PD_DIV4 = VEML6031X00_GET_PD_DIV4();

		//Determine Resolution (in lux/count) From ALS_IT, ALS_GAIN and PD_DIV4
		Resolution = VEML6031X00_CAL_Resolution(PD_DIV4, ALS_IT, ALS_GAIN);

		//Calculate Lux for the  channel
		Lux = VEML6031X00_CAL_Lux(Resolution, ALS_Data);

		//Read the IR channel
		IR_Data = VEML6031X00_GET_IR_DATA();

		/* Print the ALS channel data */
		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer,"ALS Channel : %d Counts \r\n",ALS_Data);
			CDC_PutString(TransmitBuffer);
		}
		CyDelay(50);

		/* Print the resolution for the ALS channel */
		ftoa(Resolution,TransmitBuffer, 6);
		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer2,"Resolution (ALS Channel) : %s Lux/Count \r\n",TransmitBuffer);
			CDC_PutString(TransmitBuffer2);
		}
		CyDelay(50);

		/* Print the lux values */
		ftoa(Lux,TransmitBuffer, 6);
		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer2,"Lux (ALS Channel) : %s Lux \r\n",TransmitBuffer);
			CDC_PutString(TransmitBuffer2);
		}
		CyDelay(50);

		/* Print the IR channel data */
		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer,"IR Channel : %d Counts \r\n",IR_Data);
			CDC_PutString(TransmitBuffer);
		}
		CyDelay(50);

		//Auto Mode
		if(VEML6031X00_GET_ALS_Mode() == 2)
		{
			//Read interrupt flag register
			Interrupt = VEML6031X00_GET_ALS_INT();
			CyDelay(50);

			/* Print the interrupt register */
			if(CDC_CDCIsReady() != 0u)
			{
				sprintf(TransmitBuffer,"Interrupt : 0x%x \r\n",Interrupt);
				CDC_PutString(TransmitBuffer);
			}
			CyDelay(50);
		}

		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer," \r\n");
			CDC_PutString(TransmitBuffer);
		}
		CyDelay(50);

	#endif

	#ifdef Arduino

		delay(300);

		//Active Force Mode
		if(VEML6031X00_GET_ALS_Mode() == 1)
		{
			//Set the active force mode trigger
			VEML6031X00_SET_ALS_TRIG(VEML6031X00_ALS_TRIG_EN);

			//Wait for data ready flag
			while(!VEML6031X00_GET_AF_DATA_READY_FLAG())
			{
				Wait();
			}
		}

		//Auto Mode
		if(VEML6031X00_GET_ALS_Mode() == 2)
		{
			//Delay of IT ms + other Circuit Delay (~10ms)
			Wait();
		}

		//Read the ALS channels output data
		ALS_Data = VEML6031X00_GET_ALS_DATA();

		//Read the needed parameters to determine the resolution for  channel
		ALS_IT = VEML6031X00_GET_ALS_IT();
		ALS_GAIN = VEML6031X00_GET_ALS_GAIN();
		PD_DIV4 = VEML6031X00_GET_PD_DIV4();

		//Determine Resolution (in lux/count) From ALS_IT, ALS_GAIN and PD_DIV4
		Resolution = VEML6031X00_CAL_Resolution(PD_DIV4, ALS_IT, ALS_GAIN);

		//Calculate Lux for the  channel
		Lux = VEML6031X00_CAL_Lux(Resolution, ALS_Data);

		//Read the IR channel
		IR_Data = VEML6031X00_GET_IR_DATA();

		/* Print the ALS channel data */
		Serial.print("ALS Channel : ");
		Serial.print(ALS_Data,DEC);
		Serial.println(" Counts ");
		delay(50);

		/* Print the resolution for the ALS channel */
		Serial.print("Resolution (ALS Channel) : ");
		Serial.print(Resolution,5);
		Serial.println(" Lux/Count ");
		delay(50);

		/* Print the lux values */
		Serial.print("Lux (ALS Channel) : ");
		Serial.print(Lux,5);
		Serial.println(" Lux ");
		delay(50);

		/* Print the IR channel data */
		Serial.print("IR Channel : ");
		Serial.print(IR_Data,DEC);
		Serial.println(" Counts ");
		delay(50);

		//Auto Mode
		if(VEML6031X00_GET_ALS_Mode() == 2)
		{
			//Read interrupt flag register
			Interrupt = VEML6031X00_GET_ALS_INT();
			delay(50);

			/* Print the interrupt register */
			Serial.print("Interrupt : 0b");
			Serial.println(Interrupt,BIN);
			delay(50);
		}

		Serial.println("");
		delay(50);

	#endif
}

//Execute automatic gain control for the ALS channel
Word VEML6031X00_AGC()
{
    Word ALS_Data_AGC;
    Byte ALS_IT;
    Byte ALS_GAIN;
    Byte PD_DIV4;

    //Check ALS count and change the integration time, gain and photodiode size to optimize the counts to be within upper and lower limit
    for(;;)
    {
        //Active Force Mode
        if(VEML6031X00_GET_ALS_Mode() == 1)
    	{
    		//Set Trigger for AF Mode
    		VEML6031X00_SET_ALS_TRIG(VEML6031X00_ALS_TRIG_EN);
    	}

        //Wait for the measurement to be completed
        Wait();

    	//Read the ALS channel data
        ALS_Data_AGC = VEML6031X00_GET_ALS_DATA();

        //Read the needed parameters to determine the resolution for ALS channel
        ALS_IT = VEML6031X00_GET_ALS_IT();
        ALS_GAIN = VEML6031X00_GET_ALS_GAIN();
        PD_DIV4 = VEML6031X00_GET_PD_DIV4();

        //If the ALS channel data is lower than the lower limit -> increase the integration time, gain and photodiode size until the counts and resolution are optimized
        if(ALS_Data_AGC < 25000)
        {
        	if(ALS_IT == VEML6031X00_ALS_IT_3_125ms)
			{
				VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_6_25ms);
				continue;
			}

        	if(ALS_IT == VEML6031X00_ALS_IT_6_25ms)
			{
				VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_12_5ms);
				continue;
			}

        	if(ALS_IT == VEML6031X00_ALS_IT_12_5ms)
			{
				VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_25ms);
				continue;
			}

        	if(ALS_IT == VEML6031X00_ALS_IT_25ms)
			{
				VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_50ms);
				continue;
			}

        	if(ALS_IT == VEML6031X00_ALS_IT_50ms)
			{
				VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_100ms);
				continue;
			}

        	if(ALS_IT == VEML6031X00_ALS_IT_100ms)
			{
				VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_200ms);
				continue;
			}

        	if(ALS_IT == VEML6031X00_ALS_IT_200ms)
			{
				VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_400ms);
				continue;
			}

        	if(ALS_IT == VEML6031X00_ALS_IT_400ms)
			{
				if(ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5)
				{
					VEML6031X00_SET_ALS_GAIN(VEML6031X00_ALS_GAIN_x0_66);
					continue;
				}

				if(ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66)
				{
					VEML6031X00_SET_ALS_GAIN(VEML6031X00_ALS_GAIN_x1);
					continue;
				}

				if(ALS_GAIN == VEML6031X00_ALS_GAIN_x1)
				{
					VEML6031X00_SET_ALS_GAIN(VEML6031X00_ALS_GAIN_x2);
					continue;
				}

				if(ALS_GAIN == VEML6031X00_ALS_GAIN_x2)
				{
					if(PD_DIV4 == VEML6031X00_PD_DIV4_QUARTER)
					{
						VEML6031X00_SET_PD_DIV4(VEML6031X00_PD_DIV4_FULL);
						continue;
					}
					if(PD_DIV4 == VEML6031X00_PD_DIV4_FULL)
					{
                        Wait();
						break;
					}
				}
			}
        }

        //If the ALS channel data is within the lower and upper limit -> break the loop since the counts and resolution are optimized
        if((ALS_Data_AGC >= 25000)&&(ALS_Data_AGC <= 55000))
        {
        	Wait();
            break;
        }

        //If the ALS channel data is higher than the upper limit -> reduce the integration time, gain and photodiode size until the counts and resolution are optimized
        if(ALS_Data_AGC > 55000)
        {

            if(ALS_IT == VEML6031X00_ALS_IT_400ms)
            {
                VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_200ms);
                continue;
            }

            if(ALS_IT == VEML6031X00_ALS_IT_200ms)
            {
                VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_100ms);
                continue;
            }

            if(ALS_IT == VEML6031X00_ALS_IT_100ms)
            {
                VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_50ms);
                continue;
            }

            if(ALS_IT == VEML6031X00_ALS_IT_50ms)
            {
                VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_25ms);
                continue;
            }

            else if(ALS_IT == VEML6031X00_ALS_IT_25ms)
            {
                VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_12_5ms);
                continue;
            }

            if(ALS_IT == VEML6031X00_ALS_IT_12_5ms)
            {
                VEML6031X00_SET_ALS_IT(VEML6031X00_ALS_IT_6_25ms);
                continue;
            }

            if(ALS_IT == VEML6031X00_ALS_IT_6_25ms)
            {
                if(ALS_GAIN == VEML6031X00_ALS_GAIN_x2)
                {
                    VEML6031X00_SET_ALS_GAIN(VEML6031X00_ALS_GAIN_x1);
                    continue;
                }

                if(ALS_GAIN == VEML6031X00_ALS_GAIN_x1)
                {
                    VEML6031X00_SET_ALS_GAIN(VEML6031X00_ALS_GAIN_x0_66);
                    continue;
                }

                if(ALS_GAIN == VEML6031X00_ALS_GAIN_x0_66)
                {
                    VEML6031X00_SET_ALS_GAIN(VEML6031X00_ALS_GAIN_x0_5);
                    continue;
                }

                if(ALS_GAIN == VEML6031X00_ALS_GAIN_x0_5)
                {
                    if(PD_DIV4 == VEML6031X00_PD_DIV4_FULL)
                    {
                        VEML6031X00_SET_PD_DIV4(VEML6031X00_PD_DIV4_QUARTER);
                        continue;
                    }
                    if(PD_DIV4 == VEML6031X00_PD_DIV4_QUARTER)
                    {
                    	Wait();
                        break;
                    }
                }
            }
        }
    }

    return ALS_Data_AGC;
}

//Print the output of the sensor using AGC
void Print_Data_Only_AGC()
{
	Word ALS_Data;
	float Resolution;
	float Lux;
	Byte ALS_IT;
	Byte ALS_GAIN;
	Byte PD_DIV4;

	#ifdef STM32F

		#define TRANSMIT_BUFFER_SIZE  128
		char   TransmitBuffer[TRANSMIT_BUFFER_SIZE];
		char   TransmitBuffer2[TRANSMIT_BUFFER_SIZE];

		//Clear Interrupt Flag
		VEML6031X00_GET_ALS_INT();

		if(VEML6031X00_GET_ALS_Mode() == 1)
		{
			//Set Trigger for AF Mode
			VEML6031X00_SET_ALS_TRIG(VEML6031X00_ALS_TRIG_EN);
		}

		//Delay of IT ms + other Circuit Delay (~10ms)
		Wait();

		//Read the ALS channel output data
		ALS_Data = VEML6031X00_AGC();

		//Read the needed parameters to determine the resolution for ALS channel
		ALS_IT = VEML6031X00_GET_ALS_IT();
		ALS_GAIN = VEML6031X00_GET_ALS_GAIN();
		PD_DIV4 = VEML6031X00_GET_PD_DIV4();

		//Determine Resolution (in lux/count) From ALS_IT, ALS_GAIN and PD_DIV4
		Resolution = VEML6031X00_CAL_Resolution(PD_DIV4, ALS_IT, ALS_GAIN);

		//Calculate Lux for the ALS channel
		Lux = VEML6031X00_CAL_Lux(Resolution, ALS_Data);

		/* Print the ALS channel data */
		sprintf(TransmitBuffer,"ALS Channel : %d Counts \r\n",ALS_Data);
		CDC_Transmit_FS(TransmitBuffer,strlen(TransmitBuffer));
		HAL_Delay(5);

		/* Print the resolution for the ALS channel */
		ftoa(Resolution,TransmitBuffer, 6);
		sprintf(TransmitBuffer2,"Resolution (ALS Channel) : %s Lux/Count \r\n",TransmitBuffer);
		CDC_Transmit_FS(TransmitBuffer2,strlen(TransmitBuffer2));
		HAL_Delay(5);

		/* Print the lux values */
		ftoa(Lux,TransmitBuffer, 6);
		sprintf(TransmitBuffer2,"Lux (ALS Channel) : %s Lux \r\n",TransmitBuffer);
		CDC_Transmit_FS(TransmitBuffer2,strlen(TransmitBuffer2));
		HAL_Delay(5);

		sprintf(TransmitBuffer," \r\n");
		CDC_Transmit_FS(TransmitBuffer,strlen(TransmitBuffer));
		HAL_Delay(5);

	#endif

	#ifdef Cypress

		#define TRANSMIT_BUFFER_SIZE  128
		char   TransmitBuffer[TRANSMIT_BUFFER_SIZE];
		char   TransmitBuffer2[TRANSMIT_BUFFER_SIZE];

		//Clear Interrupt Flag
		VEML6031X00_GET_ALS_INT();

		if(VEML6031X00_GET_ALS_Mode() == 1)
		{
			//Set Trigger for AF Mode
			VEML6031X00_SET_ALS_TRIG(VEML6031X00_ALS_TRIG_EN);
		}

		//Delay of IT ms + other Circuit Delay (~10ms)
		Wait();

		//Read the ALS channel output data
		ALS_Data = VEML6031X00_AGC();

		//Read the needed parameters to determine the resolution for ALS channel
		ALS_IT = VEML6031X00_GET_ALS_IT();
		ALS_GAIN = VEML6031X00_GET_ALS_GAIN();
		PD_DIV4 = VEML6031X00_GET_PD_DIV4();

		//Determine Resolution (in lux/count) From ALS_IT, ALS_GAIN and PD_DIV4
		Resolution = VEML6031X00_CAL_Resolution(PD_DIV4, ALS_IT, ALS_GAIN);

		//Calculate Lux for the ALS channel
		Lux = VEML6031X00_CAL_Lux(Resolution, ALS_Data);

		/* Print the ALS channel data */
		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer,"ALS Channel : %d Counts \r\n",ALS_Data);
			CDC_PutString(TransmitBuffer);
		}
		CyDelay(5);

		/* Print the resolution for the ALS channel */
		ftoa(Resolution,TransmitBuffer, 6);
		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer2,"Resolution (ALS Channel) : %s Lux/Count \r\n",TransmitBuffer);
			CDC_PutString(TransmitBuffer2);
		}
		CyDelay(5);

		/* Print the lux values */
		ftoa(Lux,TransmitBuffer, 6);
		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer2,"Lux (ALS Channel) : %s Lux \r\n",TransmitBuffer);
			CDC_PutString(TransmitBuffer2);
		}
		CyDelay(5);

		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer," \r\n");
			CDC_PutString(TransmitBuffer);
		}
		CyDelay(5);

	#endif

	#ifdef Arduino

		//Clear Interrupt Flag
		VEML6031X00_GET_ALS_INT();

		if(VEML6031X00_GET_ALS_Mode() == 1)
		{
			//Set Trigger for AF Mode
			VEML6031X00_SET_ALS_TRIG(VEML6031X00_ALS_TRIG_EN);
		}

		//Delay of IT ms + other Circuit Delay (~10ms)
		Wait();

		//Read the ALS channel output data
		ALS_Data = VEML6031X00_AGC();

		//Read the needed parameters to determine the resolution for ALS channel
		ALS_IT = VEML6031X00_GET_ALS_IT();
		ALS_GAIN = VEML6031X00_GET_ALS_GAIN();
		PD_DIV4 = VEML6031X00_GET_PD_DIV4();

		//Determine Resolution (in lux/count) From ALS_IT, ALS_GAIN and PD_DIV4
		Resolution = VEML6031X00_CAL_Resolution(PD_DIV4, ALS_IT, ALS_GAIN);

		//Calculate Lux for the ALS channel
		Lux = VEML6031X00_CAL_Lux(Resolution, ALS_Data);

		/* Print the ALS channel data */
		Serial.print("ALS Channel : ");
		Serial.print(ALS_Data,DEC);
		Serial.println(" Counts ");
		delay(5);

		/* Print the resolution for the ALS channel */
		Serial.print("Resolution (ALS Channel) : ");
		Serial.print(Resolution,5);
		Serial.println(" Lux/Count ");
		delay(5);

		/* Print the lux values */
		Serial.print("Lux (ALS Channel) : ");
		Serial.print(Lux,5);
		Serial.println(" Lux ");
		delay(5);

		Serial.println("");
		delay(5);

	#endif
}

/*Print the variable in DEC for debugging
 *Print_Variable_DEC(Word Var)
 *Word Var - Input Parameter:
 *
 * Value between 0d0 and 0d65535
 */
void Print_Variable_DEC(Word Var)
{

	#ifdef STM32F

		#define TRANSMIT_BUFFER_SIZE  128
		char   TransmitBuffer[TRANSMIT_BUFFER_SIZE];
		char   TransmitBuffer2[TRANSMIT_BUFFER_SIZE];

		sprintf(TransmitBuffer2,"*************************************************** \r\n");
		CDC_Transmit_FS(TransmitBuffer2,strlen(TransmitBuffer2));
		HAL_Delay(50);

		sprintf(TransmitBuffer,">>>>>>>Variable : 0d%d  \r\n",Var);
		CDC_Transmit_FS(TransmitBuffer,strlen(TransmitBuffer));
		HAL_Delay(50);

		sprintf(TransmitBuffer2,"*************************************************** \r\n");
		CDC_Transmit_FS(TransmitBuffer2,strlen(TransmitBuffer2));

		HAL_Delay(2000);

	#endif

	#ifdef Cypress

		#define TRANSMIT_BUFFER_SIZE  128
		char   TransmitBuffer[TRANSMIT_BUFFER_SIZE];
		char   TransmitBuffer2[TRANSMIT_BUFFER_SIZE];

		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer2,"*************************************************** \r\n");
			CDC_PutString(TransmitBuffer2);
		}
		CyDelay(50);

		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer,">>>>>>>Variable : 0d%d  \r\n",Var);
			CDC_PutString(TransmitBuffer);
		}
		CyDelay(50);

		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer2,"*************************************************** \r\n");
			CDC_PutString(TransmitBuffer2);
		}

		CyDelay(2000);

	#endif

	#ifdef Arduino

		Serial.println("***************************************************");
		delay(50);

		Serial.print(">>>>>>>Variable : 0d");
		Serial.println(Var,DEC);
		delay(50);

		Serial.println("***************************************************");

		delay(2000);

	#endif
}

/*Print the variable in HEX for debugging
 *Print_Variable_HEX(Word Var)
 *Word Var - Input Parameter:
 *
 * Value between 0d0 and 0d65535
 */
void Print_Variable_HEX(Word Var)
{

	#ifdef STM32F

		#define TRANSMIT_BUFFER_SIZE  128
		char   TransmitBuffer[TRANSMIT_BUFFER_SIZE];
		char   TransmitBuffer2[TRANSMIT_BUFFER_SIZE];

		sprintf(TransmitBuffer2,"*************************************************** \r\n");
		CDC_Transmit_FS(TransmitBuffer2,strlen(TransmitBuffer2));
		HAL_Delay(50);

		sprintf(TransmitBuffer,">>>>>>>Variable : 0x%x  \r\n",Var);
		CDC_Transmit_FS(TransmitBuffer,strlen(TransmitBuffer));
		HAL_Delay(50);

		sprintf(TransmitBuffer2,"*************************************************** \r\n");
		CDC_Transmit_FS(TransmitBuffer2,strlen(TransmitBuffer2));

		HAL_Delay(2000);

	#endif

	#ifdef Cypress

		#define TRANSMIT_BUFFER_SIZE  128
		char   TransmitBuffer[TRANSMIT_BUFFER_SIZE];
		char   TransmitBuffer2[TRANSMIT_BUFFER_SIZE];

		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer2,"*************************************************** \r\n");
			CDC_PutString(TransmitBuffer2);
		}
		CyDelay(50);

		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer,">>>>>>>Variable : 0x%x  \r\n",Var);
			CDC_PutString(TransmitBuffer);
		}
		CyDelay(50);

		if(CDC_CDCIsReady() != 0u)
		{
			sprintf(TransmitBuffer2,"*************************************************** \r\n");
			CDC_PutString(TransmitBuffer2);
		}

		CyDelay(2000);

	#endif

	#ifdef Arduino

		Serial.println("***************************************************");
		delay(50);

		Serial.print(">>>>>>>Variable : 0x");
		Serial.println(Var,HEX);
		delay(50);

		Serial.println("***************************************************");

		delay(2000);

	#endif
}

/*Reverses a string 'str' of length 'len'
 *reverse(char* str, int len)
 *char* str - Array pointer to be reversed
 *int len - Length of the array
 */
void reverse(char* str, int len)
{
    int i = 0, j = len - 1, temp;
    while (i < j) {
        temp = str[i];
        str[i] = str[j];
        str[j] = temp;
        i++;
        j--;
    }
}

/*Converts a given integer x to string str[].
 *intToStr(int x, char str[], int d)
 *int x - floating-point number to be converted to a string (Both the integer part as well as fraction/decimal point part)
 *char str[] - output string of the floating-point number in the form of array character
 *int d - number of decimal point (the integer part always = 0, the fraction/decimal point part = int afterpoint from ftoa() input)
 */
int intToStr(int x, char str[], int d)
{
    int i = 0;

    while (x)
	{
		//Store and convert int to char (Valid for single digit)
        str[i++] = (x % 10) + '0';
        x = x / 10;
    }

    //If number of digits required is more, then
    //add 0s at the beginning
    while (i < d) str[i++] = '0';

	//Reverse the string characters in the array str
    reverse(str, i);

	//Place the null character at the end of the array
    str[i] = '\0';

	//Return the position i
    return i;
}

/*Converts a floating-point/double number to string.
 *ftoa(float n, char* res, int afterpoint)
 *float n - floating-point number to be converted to a string
 *char* res - pointer to output string of the floating-point number in the form of array character
 *int d - number of decimal point
 */
void ftoa(float n, char* res, int afterpoint)
{
    //Extract integer part
    int ipart = (int)n;

    //Extract decimal part
    float fpart = n - (float)ipart;

    //Convert integer part to string and the function returns the position after the interger
    int i = intToStr(ipart, res, 0);

    //Check for display option after point
    if (afterpoint != 0)
	{
		//Add dot after the integer part
        res[i] = '.';

        //Multiply decimal part by 10^decimal point
        fpart = fpart* pow(10, afterpoint);

		//Convert decimal part to string
        intToStr((int)fpart, res + i + 1, afterpoint);
    }
}
