#include "stdio.h"
#include "device_heat.h"
#include "gd32f4xx.h"
#include "ptz_struct.h"
#include "agent_hyt.h"
#include "pdebug.h"
#include "cpu.h"
#include "tmp75.h"
#include "service_statusmonitor.h"
/*
 * 温度采集使用的ADC1
*/


#define HC4051_S0_PIN      GPIO_PIN_14
#define HC4051_S0_PORT     GPIOB
#define HC4051_S1_PIN      GPIO_PIN_15
#define HC4051_S1_PORT     GPIOB

#define HEAT_PIN            GPIO_PIN_12
#define HEAT_PORT           GPIOA



#define R_constant  10.0  //千欧姆——分压电阻值

// #define R_25     10000.0//热敏电阻常温下的电阻值

// #define Ntc_B  3435.0//常量B

// #define Kelvin_temp  273.15+25//常温——开尔文温度
//NTC电流
static float Ntc_current(uint16_t data)
{
  static float curr;
  curr = ((float)data / 4096.0 * 3.3)/R_constant;
  return curr;
  
}
//NTC电压
static float Ntc_voltage(uint16_t data)
{
  static float voltage;
  voltage = 3.3 - ((float)data / 4096.0 * 3.3);
  return voltage;
}
//NTC电阻
static float Ntc_resis(uint16_t data)
{
  static float resis,curr,voltage;
  curr = Ntc_current(data);
  voltage = Ntc_voltage(data);
  resis = voltage / curr * 1000.0;//因为电流值放大了1000倍
  return resis;
}

/*!
    \brief      ADC1初始化,电压,电流,NTC温度采集
    \param[in]  none
    \param[out] none
    \retval     none
    \note       LH  @2022.07.21
*/
void ADC1_Init()
{
    //配置引脚时钟
    rcu_periph_clock_enable(RCU_GPIOC);
    rcu_periph_clock_enable(RCU_GPIOB);
    //引脚复用，PC2——电压ADC1-CH12，PC3——电流ADC1-CH13
    gpio_mode_set(GPIOC,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_2);
    gpio_mode_set(GPIOC,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_3);
    /* H_NTC-PB0 ,V_NTC-PB1 */
    // gpio_mode_set(GPIOB,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_0);
    gpio_mode_set(GPIOB,GPIO_MODE_ANALOG,GPIO_PUPD_NONE,GPIO_PIN_1);

    rcu_periph_clock_enable(RCU_ADC1);
    //总线时钟20分频=6MHZ
    adc_clock_config(ADC_ADCCK_PCLK2_DIV4);
    /***********************************************/
    
    //对齐方式      ADC_INSERTED_CHANNEL
    adc_data_alignment_config(ADC1,ADC_DATAALIGN_RIGHT);
    //扫描模式
    adc_special_function_config(ADC1,ADC_SCAN_MODE,ENABLE);
    //外部触发关闭
    adc_external_trigger_config(ADC1,ADC_REGULAR_CHANNEL,DISABLE);
    //采集通道数
    adc_channel_length_config(ADC1,ADC_INSERTED_CHANNEL, 3);
    
    //通道注入顺序
    adc_inserted_channel_config(ADC1, 0, ADC_CHANNEL_13, ADC_SAMPLETIME_480);//电流
    adc_inserted_channel_config(ADC1, 1, ADC_CHANNEL_12, ADC_SAMPLETIME_480);//电压
    adc_inserted_channel_config(ADC1, 2, ADC_CHANNEL_9, ADC_SAMPLETIME_480);
        
    adc_enable(ADC1);
    
    adc_calibration_enable(ADC1);


    /* 初始化分时复用IO */
    gpio_mode_set(HC4051_S0_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, HC4051_S0_PIN);
    gpio_output_options_set(HC4051_S0_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, HC4051_S0_PIN);
    gpio_mode_set(HC4051_S1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, HC4051_S1_PIN);
    gpio_output_options_set(HC4051_S1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, HC4051_S1_PIN);

    /* 初始化加热引脚 */
    gpio_mode_set(HEAT_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, HEAT_PIN);
    gpio_output_options_set(HEAT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, HEAT_PIN);
}

/*!
    \brief      初始化分时复用控制引脚和加热使能引脚
    \param[in]  none
    \param[out] none
    \retval     none
    \note       psx  @2025.07.31
*/
void heat_Init()
{
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_GPIOB);

    /* 初始化分时复用IO */
    gpio_mode_set(HC4051_S0_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, HC4051_S0_PIN);
    gpio_output_options_set(HC4051_S0_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, HC4051_S0_PIN);
    gpio_mode_set(HC4051_S1_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, HC4051_S1_PIN);
    gpio_output_options_set(HC4051_S1_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, HC4051_S1_PIN);    
    gpio_bit_reset(HC4051_S0_PORT, HC4051_S0_PIN);
    gpio_bit_reset(HC4051_S1_PORT, HC4051_S1_PIN);

    /* 初始化加热引脚 */
    gpio_mode_set(HEAT_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, HEAT_PIN);
    gpio_output_options_set(HEAT_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, HEAT_PIN);
}

/*!
    \brief      分时复用温度采集选择为H_NTC
*/
static void choose_H_NTC(void)
{
    gpio_bit_reset(HC4051_S0_PORT, HC4051_S0_PIN);
    gpio_bit_reset(HC4051_S1_PORT, HC4051_S1_PIN);
}

/*!
    \brief      分时复用温度采集选择为V_NTC
*/
static void choose_V_NTC(void)
{
    gpio_bit_set(HC4051_S0_PORT, HC4051_S0_PIN);
    gpio_bit_reset(HC4051_S1_PORT, HC4051_S1_PIN);
}

/*!
    \brief      分时复用温度采集选择为EXT_NTC1
*/
static void choose_EXT_NTC1(void)
{
    gpio_bit_reset(HC4051_S0_PORT, HC4051_S0_PIN);
    gpio_bit_set(HC4051_S1_PORT, HC4051_S1_PIN);
}

/*!
    \brief      分时复用温度采集选择为EXT_NTC2
*/
static void choose_EXT_NTC2(void)
{ 
    gpio_bit_set(HC4051_S0_PORT, HC4051_S0_PIN);
    gpio_bit_set(HC4051_S1_PORT, HC4051_S1_PIN);
}

typedef void(*pctr) (void);
pctr choose_ntc_func[4] = {&choose_H_NTC, &choose_V_NTC, &choose_EXT_NTC1, &choose_EXT_NTC2};

/*!
    \brief      启动加热
*/
static void startHeat()
{
    gpio_bit_set(HEAT_PORT, HEAT_PIN);
}

/*!
    \brief      关闭加热
*/
static void closeHeat()
{
    gpio_bit_reset(HEAT_PORT, HEAT_PIN);
}

//电压采集
static void ptz_Voltage_collect_adc1_task()
{
    static uint32_t adc1_v[5];
    static unsigned char adc1_num;
    int j,k;
    float tem;
    float curadc1;
    uint16_t value_V;

    adc1_v[adc1_num] = ADC_IDATA1(ADC1);
    
    // adc1_v[adc1_num] = (float)value_V / 4096.0 * 11 *3.3;//(float)value_V;//
    adc1_num++;
    if (adc1_num >= 5) {
        adc1_num = 0;
        for (j = 0; j < 5-1; j++) {//采样值由小到大排列        
            for (k = 0; k < 5-j-1; k++) {             
                if (adc1_v[k] > adc1_v[k+1]) {
                    tem = adc1_v[k];
                    adc1_v[k] = adc1_v[k+1];
                    adc1_v[k+1] = tem;
                }
            }
        }
        for (uint8_t i = 1; i < 5 - 1; i++) {
            curadc1 = curadc1 + adc1_v[i];
        }
        curadc1 = curadc1 /((float)(5 - 2));//去掉一个最大值和一个最小值求平均值
        g_ptz.Voltage =  (float)curadc1 / 4096.0 * 11 *3.3;;
        memset(adc1_v,0,sizeof(adc1_v));
    }
}


//电流采集
static void ptz_Current_collect_adc1_task()
{
    static uint32_t adc1_i[5];
    static unsigned char adc1_num;
    int j,k;
    float tem;
    float curadc0;
    uint16_t value_I;
    
    adc1_i[adc1_num] = ADC_IDATA0(ADC1);
        
    adc1_num ++;
    if (adc1_num >= 5) {
        adc1_num = 0;
        for (j = 0; j < 5-1; j++) {//采样值由小到大排列        
            for (k = 0; k < 5-j-1; k++) {
                if (adc1_i[k] > adc1_i[k+1]) {
                    tem      = adc1_i[k];
                    adc1_i[k]   = adc1_i[k+1];
                    adc1_i[k+1] = tem;
                }
            }
        }
        for (uint8_t i = 1; i < 5 - 1; i++) {
            curadc0 = curadc0 + adc1_i[i];
        }
        curadc0 = curadc0 /((float)(5 - 2));//去掉一个最大值和一个最小值求平均值
        g_ptz.electric_current = ((float)curadc0 / 4096.0  * 3.3) / 0.25;

        // memset(adc1_i, 0, sizeof(adc1_i));
    }  
}

typedef struct _heat_data {
    float ext_ntc1;
    float ext_ntc2;
    float ntcT;
} heat_data;
heat_data m_heatData;

//NTC温度计算,开尔文温度
static float Ntc_temp(uint16_t adc_data, float Ntc_B)
{
  float R_ntc;//实际电阻
  double temp,K,j,l,m;//实际温度
  R_ntc = Ntc_resis(adc_data);
  K = R_ntc/10000.0;
  j = log(K);//log e为底数
  l = j / Ntc_B;
  m = 1.0 /298.15; 
  temp = 1/(l+m);
//  temp = 1/(j / Ntc_B + 1/Kelvin_temp);
  return (float)temp;
}

//温度采集并加热
static void ptz_heat_collect_adc1_task()
{
    static uint32_t adc1_T[4][5];
    static uint8_t adc1_num = 0;
    static uint8_t ntc_num = 0;

    adc1_T[ntc_num][adc1_num] = ADC_IDATA2(ADC1);

    if (++ntc_num < 4) {
        choose_ntc_func[ntc_num]();
        return;
    }
    ntc_num = 0;
    choose_ntc_func[ntc_num]();
    if (++adc1_num < 5) {
        return;
    }
    adc1_num = 0;

    uint32_t temp;
    uint32_t adc_data = 0;

    /* 采集H_NTC温度 */
    for (int j = 0; j < 5-1; j++) {//采样值由小到大排列        
        for (int k = 0; k < 5-j-1; k++) {
            if (adc1_T[0][k] > adc1_T[0][k+1]) {
                temp            = adc1_T[0][k];
                adc1_T[0][k]    = adc1_T[0][k+1];
                adc1_T[0][k+1]  = temp;
            }
        }
    }
    for(uint8_t i = 1; i < 5 - 1; i++) {
        adc_data += adc1_T[0][i];
    }
    adc_data = adc_data / 3;
    g_ptz.H_boad_temp = (short int)(Ntc_temp(adc_data, 3450.0f) - 273.15 + 0.5);
    adc_data = 0;

    /* 采集V_NTC温度 */
    for (int j = 0; j < 5-1; j++) {       
        for (int k = 0; k < 5-j-1; k++) {
            if (adc1_T[1][k] > adc1_T[1][k+1]) {
                temp            = adc1_T[1][k];
                adc1_T[1][k]    = adc1_T[1][k+1];
                adc1_T[1][k+1]  = temp;
            }
        }
    }
    for(uint8_t i = 1; i < 5 - 1; i++) {
        adc_data += adc1_T[1][i];
    }
    adc_data = adc_data / 3;
    g_ptz.V_boad_temp = (short int)(Ntc_temp(adc_data, 3450.0f) - 273.15 + 0.5);
    adc_data = 0;

    /* 采集EXT_NTC1温度 */
    for (int j = 0; j < 5-1; j++) {       
        for (int k = 0; k < 5-j-1; k++) {
            if (adc1_T[2][k] > adc1_T[2][k+1]) {
                temp            = adc1_T[2][k];
                adc1_T[2][k]    = adc1_T[2][k+1];
                adc1_T[2][k+1]  = temp;
            }
        }
    }
    for(uint8_t i = 1; i < 5 - 1; i++) {
        adc_data += adc1_T[2][i];
    }
    adc_data = adc_data / 3;
    m_heatData.ext_ntc1 = (short int)(Ntc_temp(adc_data, 3950.0f) - 273.15 + 0.5);
    adc_data = 0;

    /* 采集EXT_NTC2温度 */
    for (int j = 0; j < 5-1; j++) {       
        for (int k = 0; k < 5-j-1; k++) {
            if (adc1_T[3][k] > adc1_T[3][k+1]) {
                temp            = adc1_T[3][k];
                adc1_T[3][k]    = adc1_T[3][k+1];
                adc1_T[3][k+1]  = temp;
            }
        }
    }
    for(uint8_t i = 1; i < 5 - 1; i++) {
        adc_data += adc1_T[3][i];
    }
    adc_data = adc_data / 3;
    m_heatData.ext_ntc2 = (short int)(Ntc_temp(adc_data, 3950.0f) - 273.15 + 0.5);
    adc_data = 0;

    
    //判定温度是否异常
    if (m_heatData.ext_ntc1 < -90 || m_heatData.ext_ntc2 < -90) {
        g_ptz.fault_detect.temperature_fault = FAULT;
        // closeHeat();
        // ntc1温度异常
        if (m_heatData.ext_ntc1 < -90 && m_heatData.ext_ntc2 >= -90) {
            //判定是否需要加热
            if (m_heatData.ext_ntc2 < -20) {
                startHeat();
            }
            else if (m_heatData.ext_ntc2 > -10) {
                closeHeat();
            }
        }
        
        // ntc2温度异常
        else if (m_heatData.ext_ntc2 < -90 && m_heatData.ext_ntc1 >= -90) {
            //判定是否需要加热
            if (m_heatData.ext_ntc1 < -20) {
                startHeat();
            }
            else if (m_heatData.ext_ntc1 > -10) {
                closeHeat();
            }
        }
        
        // ntc1、2都温度异常
        else {
            //判定是否需要加热
            if (g_ptz.temperature < -20 || g_ptz.temperature < -20) {
                startHeat();
            }
            else if (g_ptz.temperature > -10 && g_ptz.temperature > -10) {
                closeHeat();
            }
        }
        
    }
    else {    
        //判定是否需要加热
        if (m_heatData.ext_ntc1 < -20 || m_heatData.ext_ntc2 < -20) {
            startHeat();
        }
        else if (m_heatData.ext_ntc1 > -10 && m_heatData.ext_ntc2 > -10) {
            closeHeat();
        }
    }
}


//温度采集
static void ptz_temperature_collect_tmp75_task()
{
  static float tmp75[5];
  static unsigned char tmp75_num;
  float curtmp75;
  float tem;
  int j,k;
  tmp75[tmp75_num] = tmp75_read_temp();
  tmp75_num ++;
  if(tmp75_num >= 5)
  {
    tmp75_num = 0;
    for(j = 0; j < 5-1; j++)//采样值由小到大排列
    {
       for(k = 0; k < 5-j-1; k++)
       {
           if(tmp75[k] > tmp75[k+1])
           {
              tem        = tmp75[k];
              tmp75[k]   = tmp75[k+1];
              tmp75[k+1] = tem;
           }
        }
     }
    for(uint8_t i = 1; i < 5 - 1; i++)
    {
      curtmp75 = curtmp75 + tmp75[i];//去掉一个最大值和一个最小值
    }
    curtmp75 = curtmp75 / ((float)(5 - 2));
    g_ptz.temperature = curtmp75;
    memset(tmp75,0,sizeof(tmp75));
//    pdebug(DEBUG_LEVEL_INFO,"get ptz Temperature: %.3f℃",g_ptz.temperature);
  }
  
}

/*!
    \brief      采集并加热任务
*/
static char ptz_heat_data_collect_task()
{ 
    static uint16_t ntc_num = 0;

    static uint16_t overCurrTime;
    static uint16_t currTime;
    static uint8_t heatFlag = 0; //加热标志位，1-禁止加热，0-允许加热

    while (1) {
        adc_software_trigger_enable(ADC1, ADC_INSERTED_CHANNEL);
        // OSTimeDlyHMSM(0u, 0u, 0u, 1u);
        while (!adc_flag_get(ADC1, ADC_FLAG_EOC)) {
            OSTimeDlyHMSM(0u, 0u, 0u, 1u);
        }
        adc_flag_clear(ADC1, ADC_FLAG_EOC);

        ptz_Voltage_collect_adc1_task();
        ptz_Current_collect_adc1_task();
        ptz_temperature_collect_tmp75_task();
        /*未禁止加热后检测电流，查看是否过流*/
        if ( !heatFlag )
        {
            ptz_heat_collect_adc1_task();
            
            if ( g_ptz.electric_current > 4.0 ) //过流
            {
                overCurrTime++;
            }
            else
            {
                currTime = 0;
            }
            //长时间过流
            if ( overCurrTime >= 20 ) //20*100ms=2s
            {
                heatFlag = 1; //禁止加热
                closeHeat();
                overCurrTime = 0;
            }
        }
        else
        {
            if ( g_ptz.electric_current < 2.0 ) //电流恢复正常
            {
                currTime++;
            }
            else
            {
                currTime = 0;
            }
            //长时间电流正常
            if ( currTime >= 20 ) //20*100ms=2s
            {
                heatFlag = 0; //允许加热
                currTime = 0;
            }
        }
        // ptz_heat_collect_adc1_task();

        OSTimeDlyHMSM(0u, 0u, 0u, 100u);
    }
}

static OS_STK  task_heat_data_collect_stk[TASK_PTZ_HEAT_DATA_COLLECT_STK_SIZE];
static  void  creat_heat_task_data_collect(void)
{ 
   CPU_INT08U  task_err;   
   CPU_INT08U  name_err;
   
   task_err = OSTaskCreateExt((void (*)(void *)) ptz_heat_data_collect_task,           
		   (void           *) 0,
		   (OS_STK         *)&task_heat_data_collect_stk[TASK_PTZ_HEAT_DATA_COLLECT_STK_SIZE - 1],
		   (INT8U           ) TASK_PTZ_HEAT_DATA_COLLECT_PRIO,                   
		   (INT16U          ) TASK_PTZ_HEAT_DATA_COLLECT_PRIO,
		   (OS_STK         *)&task_heat_data_collect_stk[0],
		   (INT32U          ) TASK_PTZ_HEAT_DATA_COLLECT_STK_SIZE,
		   (void           *) 0,
		   (INT16U          )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));     
    #if (OS_TASK_NAME_EN > 0)
    OSTaskNameSet(TASK_PTZ_HEAT_DATA_COLLECT_PRIO, "ptz_heat_data_collect_task", &name_err);
    #endif
       if ((task_err == OS_ERR_NONE) && (name_err == OS_ERR_NONE)) {
		pdebug(DEBUG_LEVEL_INFO,"create ptz_heat_data_collect_task success\r\n");
	} else {
		pdebug(DEBUG_LEVEL_FATAL,"create ptz_heat_data_collect_task failed\r\n");
	}
}

void Init_ptz_heat_data_collect_task()
{
    ADC1_Init();
    heat_Init();
    creat_heat_task_data_collect();
}

static char g_str[80];
char* TempInfoGet(void)
{
  /*加热*/
  if ( gpio_input_bit_get(HEAT_PORT, HEAT_PIN) )
  {
    sprintf(g_str, "extTemp1 = %.2f, extTemp2 = %.2f,heating!\r\nH_Temp = %.2f, V_Temp = %.2f\r\n\r\n", m_heatData.ext_ntc1, m_heatData.ext_ntc2, g_ptz.H_boad_temp, g_ptz.V_boad_temp);
  }
  else
  {
    sprintf(g_str, "extTemp1 = %.2f, extTemp2 = %.2f,Noheating!\r\nH_Temp = %.2f, V_Temp = %.2f\r\n\r\n", m_heatData.ext_ntc1, m_heatData.ext_ntc2, g_ptz.H_boad_temp, g_ptz.V_boad_temp);
  }
  return &g_str[0];  
}



