/********************************** (C) COPYRIGHT *******************************
* File Name          : temperature.c
* Author             : WCH
* Version            : V1.0.0
* Date               : 2023/11/17
* Description        : Temperature program body.
*********************************************************************************
* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
* Attention: This software (modified or not) and binary are used for 
* microcontroller manufactured by Nanjing Qinheng Microelectronics.
*******************************************************************************/

/*
 *@Note
 *Internal temperature sensor routine:
 *Through the ADC channel 16, the output voltage value and temperature value of the internal
 *temperature sensor are collected.
 *
 */

#include "debug.h"
#include "lib/telemetry/telemetry.h"

/* Global Variable */
int16_t Calibrattion_Val = 0;

/*********************************************************************
 * @fn      ADC_Function_Init
 *
 * @brief   Initializes ADC collection.
 *
 * @return  none
 */
void ADC_Function_Init(void)
{
	ADC_InitTypeDef ADC_InitStructure={0};

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE );
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);

	ADC_DeInit(ADC1);
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1, &ADC_InitStructure);

	ADC_Cmd(ADC1, ENABLE);

    ADC_BufferCmd(ADC1, DISABLE);   //disable buffer
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
	Calibrattion_Val = Get_CalibrationValue(ADC1);	
	
    ADC_BufferCmd(ADC1, ENABLE);   //enable buffer
	
	ADC_TempSensorVrefintCmd(ENABLE);
}

/*********************************************************************
 * @fn      Get_ADC_Val
 *
 * @brief   Returns ADCx conversion result data.
 *
 * @param   ch - ADC channel.
 *            ADC_Channel_0 - ADC Channel0 selected.
 *            ADC_Channel_1 - ADC Channel1 selected.
 *            ADC_Channel_2 - ADC Channel2 selected.
 *            ADC_Channel_3 - ADC Channel3 selected.
 *            ADC_Channel_4 - ADC Channel4 selected.
 *            ADC_Channel_5 - ADC Channel5 selected.
 *            ADC_Channel_6 - ADC Channel6 selected.
 *            ADC_Channel_7 - ADC Channel7 selected.
 *            ADC_Channel_8 - ADC Channel8 selected.
 *            ADC_Channel_9 - ADC Channel9 selected.
 *            ADC_Channel_10 - ADC Channel10 selected.
 *            ADC_Channel_11 - ADC Channel11 selected.
 *            ADC_Channel_12 - ADC Channel12 selected.
 *            ADC_Channel_13 - ADC Channel13 selected.
 *            ADC_Channel_14 - ADC Channel14 selected.
 *            ADC_Channel_15 - ADC Channel15 selected.
 *            ADC_Channel_16 - ADC Channel16 selected.
 *            ADC_Channel_17 - ADC Channel17 selected.
 *
 * @return  none
 */
uint16_t Get_ADC_Val(uint8_t ch)
{
    uint16_t val;

	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 );
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);

	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));

	val = ADC_GetConversionValue(ADC1);

	return val;
}

/*********************************************************************
 * @fn      Get_ADC_Average
 *
 * @brief   Returns ADCx conversion result average data.
 *
 * @param   ch - ADC channel.
 *            ADC_Channel_0 - ADC Channel0 selected.
 *            ADC_Channel_1 - ADC Channel1 selected.
 *            ADC_Channel_2 - ADC Channel2 selected.
 *            ADC_Channel_3 - ADC Channel3 selected.
 *            ADC_Channel_4 - ADC Channel4 selected.
 *            ADC_Channel_5 - ADC Channel5 selected.
 *            ADC_Channel_6 - ADC Channel6 selected.
 *            ADC_Channel_7 - ADC Channel7 selected.
 *            ADC_Channel_8 - ADC Channel8 selected.
 *            ADC_Channel_9 - ADC Channel9 selected.
 *            ADC_Channel_10 - ADC Channel10 selected.
 *            ADC_Channel_11 - ADC Channel11 selected.
 *            ADC_Channel_12 - ADC Channel12 selected.
 *            ADC_Channel_13 - ADC Channel13 selected.
 *            ADC_Channel_14 - ADC Channel14 selected.
 *            ADC_Channel_15 - ADC Channel15 selected.
 *            ADC_Channel_16 - ADC Channel16 selected.
 *            ADC_Channel_17 - ADC Channel17 selected.
 *
 * @return  val - The Data conversion value.
 */
uint16_t Get_ADC_Average(uint8_t ch,uint8_t times)
{
	u32 temp_val=0;
	uint8_t t;
	uint16_t val;

	for(t=0;t<times;t++)
	{
		temp_val+=Get_ADC_Val(ch);
		Delay_Ms(5);
	}

	val = temp_val/times;

	return val;
}

/*********************************************************************
 * @fn      Get_ConversionVal
 *
 * @brief   Get Conversion Value.
 *
 * @param   val - Sampling value
 *
 * @return  val+Calibrattion_Val - Conversion Value.
 */
uint16_t Get_ConversionVal(int16_t val)
{
	if((val+Calibrattion_Val)<0|| val==0) return 0;
	if((Calibrattion_Val+val)>4095||val==4095) return 4095;
	return (val+Calibrattion_Val);
}

s32 TempSensor_Volt_To_Temper_x10(s32 Value)
{
    s32 Temper_x10;
    s32 Refer_Volt, Refer_Temper;
    s32 k = 43; // slope in mV/ˇăC

    // Read factory calibration values
    Refer_Volt = (s32)((*(u32 *)0x1FFFF720) & 0x0000FFFF);       // mV at reference temp
    Refer_Temper = (s32)(((*(u32 *)0x1FFFF720) >> 16) & 0x0000FFFF); // ˇăC

    // Compute temperature in decicelsius
    // Formula: T_x10 = Tref*10 - ((V - Vref)*100 + k/2) / k
    // Multiply (V - Vref) by 100 to get tenths of ˇăC
    Temper_x10 = Refer_Temper * 10 - ((Value - Refer_Volt) * 100 + (k / 2)) / k;

    return Temper_x10;
}


s32 getTemperature(void)
{
	uint16_t ADC_val;
	s32 val_mv;

    ADC_val = Get_ADC_Average( ADC_Channel_TempSensor, 10 );

    ADC_val = Get_ConversionVal(ADC_val);

    val_mv = (ADC_val*3300/4096);

    return TempSensor_Volt_To_Temper(val_mv);
}

int16_t getDeciTemperature(void)
{
	uint16_t ADC_val;
	s32 val_mv;

    ADC_val = Get_ADC_Average( ADC_Channel_TempSensor, 10 );

    ADC_val = Get_ConversionVal(ADC_val);

    val_mv = (ADC_val*3300/4096);

	s32 temp_x10 = TempSensor_Volt_To_Temper_x10(val_mv);

	int16_t temp16 = (int16_t)temp_x10;  // store in 2 bytes
    return temp16;
}

s32 getVoltage(void)
{
	uint16_t ADC_val;
	s32 val_mv;

    ADC_val = Get_ADC_Average( ADC_Channel_1, 10 );

    ADC_val = Get_ConversionVal(ADC_val);


    val_mv = (ADC_val*3300/4096);

    return val_mv;
}

// Helper: convert signed 24-bit int to 3 bytes (big-endian)
void int24_to_bytes(int32_t value, uint8_t *bytes) {
    if (value < 0) value += 0x1000000; // 2's complement for 24-bit
    bytes[0] = (value >> 16) & 0xFF;
    bytes[1] = (value >> 8) & 0xFF;
    bytes[2] = value & 0xFF;
}

// Encode GPS into CayenneLPP payload
void encode_gps(uint8_t channel, int32_t lat, int32_t lon, int32_t alt, uint8_t *payload) {
    payload[0] = channel;
    payload[1] = LPP_GPS; // GPS type

    //int32_t latInt = lat * 10000;
    //int32_t lonInt = lon * 10000;
    //int32_t altInt = alt * 100;

    int24_to_bytes(lat, &payload[2]);
    int24_to_bytes(lon, &payload[5]);
    int24_to_bytes(alt, &payload[8]);
    //int24_to_bytes(latInt, &payload[2]);
    //int24_to_bytes(lonInt, &payload[5]);
    //int24_to_bytes(altInt, &payload[8]);
}