#include "rotate_plan.h"
#include "ptz_header_file.h"
#include "gd32f4xx.h"
#include "angle_poweroffsave.h"
#include "mb85rc64.h"
static BSP_OS_SEM ptz_power_off_mutex;//共享资源锁

static float power_v;//实时电压
static float power_v1;//用于保存用于判断电压升高还是降低的基本电压

PowerOffData power_off_data;

// //电压采集
// static float ptz_voltage_adc1()
// {
//   unsigned short int adc1_value;
//   float float_adc1;
  
//   adc_software_trigger_enable(ADC1,ADC_INSERTED_CHANNEL);
//   adc1_value = ADC_IDATA1(ADC1);
  
//   float_adc1 = (float)adc1_value / 4096.0 * 12.55 *3.38;
//   // float_adc1 = (float)adc1_value / 4096.0 * 36.3;
//   return float_adc1;
// }

static float ptz_power_off_data_crc(PowerOffData data)
{
  float crc = 0;
  crc = data.hori_as5047d.as5047d_ptz_init_angle       +
        data.hori_as5047d.as5047d_ptz_angle_max        +
        data.hori_as5047d.as5047d_ptz_angle_K          +
        data.hori_as5047d.as5047d_ptz_angle_wf_actual  +
        data.hori_as5047d.as5047d_ptz_angle_wf_last    +
        data.hori_as5047d.as5047d_ptz_angle_actual     +
        data.hori_as5047d.as5047d_ptz_angle_last       +
        data.hori_as5047d.as5047d_remain_angle         +
        data.hori_as5047d.as5047d_cycle_num            +
        data.hori_as5047d.as5047d_cycle_count          +
        data.hori_as5047d.as5047d_cycle_count_last     +
        data.hori_as5047d.as5047d_angle_actual         +
        data.hori_as5047d.as5047d_dir                  +
        data.hori_as5047d.as5047d_angle_last           +
        data.hori_as5047d.as5047d_angle_difference     +
        data.hori_as5047d.as5047d_state                +
        data.hori_as5047d.as5047d_data_reset           + 
  
        data.vert_as5047d.as5047d_ptz_init_angle       +
        data.vert_as5047d.as5047d_ptz_angle_max        +
        data.vert_as5047d.as5047d_ptz_angle_K          +
        data.vert_as5047d.as5047d_ptz_angle_wf_actual  +
        data.vert_as5047d.as5047d_ptz_angle_wf_last    +
        data.vert_as5047d.as5047d_ptz_angle_actual     +
        data.vert_as5047d.as5047d_ptz_angle_last       +
        data.vert_as5047d.as5047d_remain_angle         +
        data.vert_as5047d.as5047d_cycle_num            +
        data.vert_as5047d.as5047d_cycle_count          +
        data.vert_as5047d.as5047d_cycle_count_last     +
        data.vert_as5047d.as5047d_angle_actual         +
        data.vert_as5047d.as5047d_dir                  +
        data.vert_as5047d.as5047d_angle_last           +
        data.vert_as5047d.as5047d_angle_difference     +
        data.vert_as5047d.as5047d_state                +
        data.vert_as5047d.as5047d_data_reset           +
        data.vert_angle                                +
        data.hori_angle                                +
        data.power_down_offset_anle                    +

          
        data.num;
  
  return crc;
}




char ptz_power_off_data_save(unsigned short int add)
{
  BSP_OS_SemWait(&ptz_power_off_mutex, 0u);
  PowerOffData power_off_data_b;
  int i;
  memcpy(&power_off_data.hori_as5047d, &g_ptz.hori_as5047d, sizeof(g_ptz.hori_as5047d));
  memcpy(&power_off_data.vert_as5047d, &g_ptz.vert_as5047d, sizeof(g_ptz.vert_as5047d));
  power_off_data.vert_angle = g_ptz.vert_angle_actual;
  power_off_data.hori_angle = g_ptz.hori_angle_actual; 
  power_off_data.power_down_offset_anle = g_ptz.offset_angle.offset_anle;//误差补偿参数保存
  power_off_data.crc = ptz_power_off_data_crc(power_off_data);
  
  for(i = 0; i < PTZ_POWER_OFF_DATA_SAVE_NUM; i++)
  {
    memset(&power_off_data_b, 0, sizeof(power_off_data_b));
    // mb85rc64_page_write(add, (unsigned char *)&power_off_data, sizeof(power_off_data));
    mb85rc64_write_read(add, (unsigned char *)&power_off_data, sizeof(power_off_data), PAGE_WRITE);
    asm("nop");
    asm("nop");
    // mb85rc64_add_read(add, (unsigned char *)&power_off_data_b, sizeof(power_off_data_b));
    mb85rc64_write_read(add, (unsigned char *)&power_off_data_b, sizeof(power_off_data_b), ADDR_READ);
    if(memcmp(&power_off_data_b, &power_off_data, sizeof(power_off_data)) == 0)//判断擦除数据是否正确
    {
      BSP_OS_SemPost(&ptz_power_off_mutex);
      return 1;
    }
  }
  BSP_OS_SemPost(&ptz_power_off_mutex);
  return 0;
}

char ptz_power_off_data_read()
{
  BSP_OS_SemWait(&ptz_power_off_mutex, 0u);
  char i;
  PowerOffData power_off_data_a;
  PowerOffData power_off_data_b;
  char data_a = 0;
  char data_b = 0;
  
  memset(&power_off_data, 0, sizeof(power_off_data));
  //读取存储区域a的数据
  for(i = 0; i < PTZ_POWER_OFF_DATA_READ_NUM; i++)
  {
    memset(&power_off_data_a, 0, sizeof(power_off_data_a));
    // mb85rc64_add_read(PTZ_MB85RC64_ADD_A, (unsigned char *)&power_off_data_a, sizeof(power_off_data_a));
    mb85rc64_write_read(PTZ_MB85RC64_ADD_A, (unsigned char *)&power_off_data_a, sizeof(power_off_data_a), ADDR_READ);
    if(power_off_data_a.crc == ptz_power_off_data_crc(power_off_data_a) && power_off_data_a.crc != 0)
    {
       data_a = 1;
       break;
    }
  }
  
  //读取存储区域b的数据
  for(i = 0; i < PTZ_POWER_OFF_DATA_READ_NUM; i++)
  {
    memset(&power_off_data_b, 0, sizeof(power_off_data_b));
    // mb85rc64_add_read(PTZ_MB85RC64_ADD_B, (unsigned char *)&power_off_data_b, sizeof(power_off_data_b));
    mb85rc64_write_read(PTZ_MB85RC64_ADD_B, (unsigned char *)&power_off_data_b, sizeof(power_off_data_b), ADDR_READ);
    if(power_off_data_b.crc == ptz_power_off_data_crc(power_off_data_b) && power_off_data_b.crc != 0)
    {
       data_b = 1;
       break;
    }
  }
  
  if(data_a == 1 && data_b == 0)//只有存储区A的数据是对的,则只用A的数据
  {
    memcpy(&power_off_data, &power_off_data_a, sizeof(power_off_data));
    memcpy(&g_ptz.hori_as5047d, &power_off_data.hori_as5047d, sizeof(g_ptz.hori_as5047d));
    memcpy(&g_ptz.vert_as5047d, &power_off_data.vert_as5047d, sizeof(g_ptz.vert_as5047d));
    
    g_ptz.offset_angle.offset_anle = power_off_data.power_down_offset_anle;//读取偏移量
    
    if(power_off_data.num == 65535)
    {
      power_off_data.num = 0;
    }
    else
    {
      power_off_data.num ++;
    }
    
    BSP_OS_SemPost(&ptz_power_off_mutex);
    return 1;
  }
  
  
  if(data_a == 0 && data_b == 1)//只有存储区B的数据是对的,则只用B的数据
  {
    memcpy(&power_off_data, &power_off_data_b, sizeof(power_off_data));
    memcpy(&g_ptz.hori_as5047d, &power_off_data.hori_as5047d, sizeof(g_ptz.hori_as5047d));
    memcpy(&g_ptz.vert_as5047d, &power_off_data.vert_as5047d, sizeof(g_ptz.vert_as5047d));
    
    g_ptz.offset_angle.offset_anle = power_off_data.power_down_offset_anle;//读取偏移量
    
    if(power_off_data.num == 65535)
    {
      power_off_data.num = 0;
    }
    else
    {
      power_off_data.num ++;
    }
    
    BSP_OS_SemPost(&ptz_power_off_mutex);
    return 1;
  }
  
  if(data_a == 1 && data_b == 1)//如果存储区A的数据是对的，存储区B的数据也是对的
  {
    if(power_off_data_a.num > power_off_data_b.num)
    {
      if((power_off_data_a.num - power_off_data_b.num) == 1)
      {
        memcpy(&power_off_data, &power_off_data_a, sizeof(power_off_data));
        memcpy(&g_ptz.hori_as5047d, &power_off_data.hori_as5047d, sizeof(g_ptz.hori_as5047d));
        memcpy(&g_ptz.vert_as5047d, &power_off_data.vert_as5047d, sizeof(g_ptz.vert_as5047d));
        
        g_ptz.offset_angle.offset_anle = power_off_data.power_down_offset_anle;//读取偏移量
        
        if(power_off_data.num == 65535)
        {
          power_off_data.num = 0;
        }
        else
        {
          power_off_data.num ++;
        }
        
        BSP_OS_SemPost(&ptz_power_off_mutex);
        return 1;
      }
      
      if((power_off_data_a.num - power_off_data_b.num) == 65535)
      {
        memcpy(&power_off_data, &power_off_data_b, sizeof(power_off_data));
        memcpy(&g_ptz.hori_as5047d, &power_off_data.hori_as5047d, sizeof(g_ptz.hori_as5047d));
        memcpy(&g_ptz.vert_as5047d, &power_off_data.vert_as5047d, sizeof(g_ptz.vert_as5047d));
        
        g_ptz.offset_angle.offset_anle = power_off_data.power_down_offset_anle;//读取偏移量
        
        if(power_off_data.num == 65535)
        {
          power_off_data.num = 0;
        }
        else
        {
          power_off_data.num ++;
        }

        BSP_OS_SemPost(&ptz_power_off_mutex);
        return 1;
      }
    }
    
    if(power_off_data_b.num > power_off_data_a.num)
    {
      if((power_off_data_b.num - power_off_data_a.num) == 1)
      {
        memcpy(&power_off_data, &power_off_data_b, sizeof(power_off_data));
        memcpy(&g_ptz.hori_as5047d, &power_off_data.hori_as5047d, sizeof(g_ptz.hori_as5047d));
        memcpy(&g_ptz.vert_as5047d, &power_off_data.vert_as5047d, sizeof(g_ptz.vert_as5047d));
        
        g_ptz.offset_angle.offset_anle = power_off_data.power_down_offset_anle;//读取偏移量
        
        if(power_off_data.num == 65535)
        {
          power_off_data.num = 0;
        }
        else
        {
          power_off_data.num ++;
        }

        BSP_OS_SemPost(&ptz_power_off_mutex);
        return 1;
      }
      
      if((power_off_data_b.num - power_off_data_a.num) == 65535)
      {
        memcpy(&power_off_data, &power_off_data_a, sizeof(power_off_data));
        memcpy(&g_ptz.hori_as5047d, &power_off_data.hori_as5047d, sizeof(g_ptz.hori_as5047d));
        memcpy(&g_ptz.vert_as5047d, &power_off_data.vert_as5047d, sizeof(g_ptz.vert_as5047d));
        
        g_ptz.offset_angle.offset_anle = power_off_data.power_down_offset_anle;//读取偏移量
        
        if(power_off_data.num == 65535)
        {
          power_off_data.num = 0;
        }
        else
        {
          power_off_data.num ++;
        }
        
        BSP_OS_SemPost(&ptz_power_off_mutex);
        return 1;
      }
    }
    
  }
  
  
  BSP_OS_SemPost(&ptz_power_off_mutex);
  return 0;
}

char ptz_power_off_data_erase(unsigned short int add)
{
  BSP_OS_SemWait(&ptz_power_off_mutex, 0u);
  PowerOffData power_off_data_a;
  int i;
  memset(&power_off_data, 0, sizeof(power_off_data));
  power_off_data.crc = -100;

  for(i = 0; i < PTZ_POWER_OFF_DATA_SAVE_NUM; i++)
  {
    memset(&power_off_data_a, 0, sizeof(power_off_data_a));
    // mb85rc64_page_write(add, (unsigned char *)&power_off_data, sizeof(power_off_data));
    mb85rc64_write_read(add, (unsigned char *)&power_off_data, sizeof(power_off_data), PAGE_WRITE);
    asm("nop");
    asm("nop");
    // mb85rc64_add_read(add, (unsigned char *)&power_off_data_a, sizeof(power_off_data_a));
    mb85rc64_write_read(add, (unsigned char *)&power_off_data_a, sizeof(power_off_data_a), ADDR_READ);
    if(memcmp(&power_off_data_a, &power_off_data, sizeof(power_off_data)) == 0)//判断擦除数据是否正确
    {
      BSP_OS_SemPost(&ptz_power_off_mutex);
      return 1;
    }
  }
  BSP_OS_SemPost(&ptz_power_off_mutex);
  return 0;
}





#define  ADC1_NUM    5 //电压采集次数

static char ptz_power_off_task()
{
  unsigned short int number;
#ifdef PTZ_POWER_OFF_ADC_MANY 
  static float adc1_v[ADC1_NUM];
  float tem;
  char i,j;
#endif
  while(1)
  {
#ifdef PTZ_POWER_OFF_ADC_MANY    
    //连续读取电压
    for(i = 0; i < ADC1_NUM; i++)
    {
      tem = 0;
      tem = ptz_voltage_adc1();
      if(tem < 0 || isnan(tem) == 1)
      {
        tem = 0;
      }
      adc1_v[i] = tem;
      OSTimeDlyHMSM(0u, 0u, 0u, 1u);
    }
    //对读取电压排序
    for(i = 0; i < ADC1_NUM-1; i++)//采样值由小到大排列
    {
      for(j = 0; j < ADC1_NUM-i-1; j++)
      {
        if(adc1_v[j] > adc1_v[j+1])
        {
           tem         = adc1_v[j];
           adc1_v[j]   = adc1_v[j+1];
           adc1_v[j+1] = tem;
        }
       }
     }
    //去掉一个最小值和一个最大值求和
    tem = 0;
    for(i = 1; i < ADC1_NUM - 1; i++)
    {
      tem = tem + adc1_v[i];
    }
    tem = tem /((float)(ADC1_NUM - 2));//去掉一个最大值和一个最小值求平均值
    
    
    g_ptz.Voltage = tem;
    power_v = tem;
#endif    

#ifdef PTZ_POWER_OFF_ADC_SINGLE  
    
    OSTimeDlyHMSM(0u, 0u, 0u, 2u);
    //读取实时电压
    g_ptz.Voltage = ptz_Voltage_collect_adc1_task();
    //判断读出的电压是否大于0以及是否是一个数字
    if(g_ptz.Voltage < 0 || isnan(g_ptz.Voltage) == 1)
    {
      g_ptz.Voltage = 0;
    }
    if(g_ptz.Voltage == 0)//如果采集的值为0（采集数据异常为0或者电压数据确实降到了0），则再从新采集一次，
                          //可以防止某个时刻出现电压采集出错，导致云台误判为电源关电
    {
      //OSTimeDlyHMSM(0u, 0u, 0u, 1u);
      asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
      g_ptz.Voltage = ptz_Voltage_collect_adc1_task();//再采集一次
      asm("nop");asm("nop");asm("nop");asm("nop");asm("nop");
      g_ptz.Voltage = ptz_Voltage_collect_adc1_task();//再采集一次
      //判断读出的电压是否小于于0以及是否是一个数字
      if(g_ptz.Voltage < 0 || isnan(g_ptz.Voltage) == 1)
      {
        g_ptz.Voltage = 0;
      }
    }
    power_v = g_ptz.Voltage;

#endif

/*****************************************强制保存位置数据********************************************************/       
    if(g_ptz.no_self_check_force_save == 1)
    {
      //存储云台当前运行的数据
      if((power_off_data.num & 1) == 0)//偶数
      {
        if(ptz_power_off_data_save(PTZ_MB85RC64_ADD_A) == 1)//存储云台当前运行的数据
        {
          if(power_off_data.num == 65535)
          {
            
            power_off_data.num = 0;
          }
          else
          {
            power_off_data.num ++;
          }
        }
      }
      else
      {
        if(ptz_power_off_data_save(PTZ_MB85RC64_ADD_B) == 1)//存储云台当前运行的数据
        {
          if(power_off_data.num == 65535)
          {
            power_off_data.num = 0;
          }
          else
          {
            power_off_data.num ++;
          }
        }
      }
      g_ptz.no_self_check_force_save = 2;//表示强制保存过云台数据
    }
    
    if((g_ptz.hori_start_stop_set == PTZ_HORI_START || g_ptz.vert_start_stop_set == PTZ_VERT_START)
       && g_ptz.no_self_check_force_save == 2)
    {//强制保存数据后，如果云台又转动了，则又恢复自动判断掉电保存功能
      g_ptz.no_self_check_force_save = 0;
    }
/**************************************强制擦除保存的位置数据******************************************************/   
    if(g_ptz.no_self_check_force_erase == 1)
    {
      ptz_power_off_data_erase(PTZ_MB85RC64_ADD_A);
      ptz_power_off_data_erase(PTZ_MB85RC64_ADD_B);
      g_ptz.no_self_check_force_erase = 2;
    }
/********************************************自动保存位置数据*****************************************************/      
    if(g_ptz.hori_self_check == PTZ_HORI_SELF_CHECK_END &&
       g_ptz.vert_self_check == PTZ_VERT_SELF_CHECK_END && 
       g_ptz.no_self_check_force_save  != 2 && 
       g_ptz.no_self_check_force_erase != 2 &&
       g_ptz.no_self_check_state       != 1 &&
       g_ptz.hori_angle_state          == 1 &&
       g_ptz.vert_angle_state          == 1  )
    {
      //电压出现大的下降
      if(power_v < power_v1 && ((power_v1 - power_v) >= PTZ_POWER_DOWN_INC))
      {
        if((power_off_data.num & 1) == 0)//偶数
        {
          if(ptz_power_off_data_save(PTZ_MB85RC64_ADD_A) == 1)//存储云台当前运行的数据
          {
            if(power_off_data.num == 65535)
            {
              power_off_data.num = 0;
            }
            else
            {
              power_off_data.num ++;
            }
            
            power_v1 = power_v;
          }
        }
        else
        {
          if(ptz_power_off_data_save(PTZ_MB85RC64_ADD_B) == 1)//存储云台当前运行的数据
          {
            if(power_off_data.num == 65535)
            {
              power_off_data.num = 0;
            }
            else
            {
              power_off_data.num ++;
            }
            
            power_v1 = power_v;
          }
        }
        
        
      }
      
      //电压升高了
      if(power_v > power_v1)
      {
        power_v1 = power_v;
      }
//      term_printf("\n               power down save angle        \r\n\r\n");//测试
 
    }
   
/**********************************启动后，只要云台一转动就要擦除原先保存的位置数据**************************************/          
    if(g_ptz.no_self_check_state == 1 && 
      (g_ptz.hori_start_stop_set == PTZ_HORI_START || g_ptz.vert_start_stop_set == PTZ_VERT_START))
    {
      number = power_off_data.num;
      ptz_power_off_data_erase(PTZ_MB85RC64_ADD_A);
      ptz_power_off_data_erase(PTZ_MB85RC64_ADD_B);
      power_off_data.num = number;
      g_ptz.no_self_check_state = 2;
    }
    
  }
}


static OS_STK  task_power_off_stk[POWER_OFF_STK_SIZE];
static  void  creat_task_power_off(void)
{ 
   CPU_INT08U  task_err;
   CPU_INT08U  name_err;
   
   task_err = OSTaskCreateExt((void (*)(void *)) ptz_power_off_task,           
		   (void           *) 0,
		   (OS_STK         *)&task_power_off_stk[POWER_OFF_STK_SIZE - 1],
		   (INT8U           ) POWER_OFF_PRIO,
		   (INT16U          ) POWER_OFF_PRIO,
		   (OS_STK         *)&task_power_off_stk[0],
		   (INT32U          ) POWER_OFF_STK_SIZE,
		   (void           *) 0,
		   (INT16U          )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));     
    #if (OS_TASK_NAME_EN > 0)
    OSTaskNameSet(POWER_OFF_PRIO, "ptz_power_off_task", &name_err);
    #endif
       

}

void init_power_off_module(void)
{
#ifdef PTZ_NO_SELF_CHECK 
  // mb85rc64_gpio_init();
  
  BSP_OS_SemCreate(&ptz_power_off_mutex,1u,"ptz_power_off_mutex");//创建信号量
  
  creat_task_power_off();
#endif
}