#include "includes.h"

#include "drv_dtu.h"
#include "drv_gps.h"

RTC_HandleTypeDef hrtc;

// 当前工作模式
uint8_t Wakeup_workMode = WORK_MODE_NORMAL;

// 电量极低标志
uint8_t bat_veryLow = 0;

// 休眠标识
volatile uint8_t Wakeup_Sleeping = 0;
// 是否睡眠模式
volatile uint8_t Wakeup_SleepMode = 0;

// 实际启动时间和INITIAL_YEAR相差的秒数（当GPS定位或GPRS连接基站以后设置）
volatile uint32_t RTC_offsetSeconds = 0;

// 获取日期时间：输出格式为Nuvoton芯片格式
void RTC_GetDateAndTime(S_RTC_TIME_DATA_T *sRTC)
{
	RTC_TimeTypeDef sTime = {0};
	RTC_DateTypeDef sDate = {0};
	
	HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
	HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
	
	sRTC->u32Year = sDate.Year + RTC_YEAR2000;
	sRTC->u32Month = sDate.Month;
	sRTC->u32Day = sDate.Date;
	if(sDate.WeekDay == RTC_WEEKDAY_SUNDAY)
		sRTC->u32DayOfWeek = 0;
	else
		sRTC->u32DayOfWeek = sDate.WeekDay;
	sRTC->u32Hour = sTime.Hours;
	sRTC->u32Minute = sTime.Minutes;
	sRTC->u32Second = sTime.Seconds;
	sRTC->u32TimeScale = RTC_CLOCK_24;
}

// 设置日期时间：输入格式为Nuvoton芯片格式
void RTC_SetDateAndTime(S_RTC_TIME_DATA_T *sRTC)
{
	RTC_TimeTypeDef sTime = {0};
	RTC_DateTypeDef sDate = {0};
	
	sDate.Year = sRTC->u32Year - RTC_YEAR2000;
	sDate.Month = sRTC->u32Month;
	sDate.Date = sRTC->u32Day;
	if(sRTC->u32DayOfWeek == RTC_SUNDAY)
		sDate.WeekDay = RTC_WEEKDAY_SUNDAY;
	else
		sDate.WeekDay = sRTC->u32DayOfWeek;
	sTime.Hours = sRTC->u32Hour;
	sTime.Minutes = sRTC->u32Minute;
	sTime.Seconds = sRTC->u32Second;
	sTime.SubSeconds = 0;
	sTime.TimeFormat = RTC_HOURFORMAT_24;
	sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sTime.StoreOperation = RTC_STOREOPERATION_RESET;
		
	HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
	HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
}

void RTC_SetAlarmDateAndTime(S_RTC_TIME_DATA_T *sRTC)
{
	uint8_t try_count = 3;

	RTC_AlarmTypeDef sAlarm = {0};
	
	sAlarm.AlarmTime.Hours = sRTC->u32Hour;
	sAlarm.AlarmTime.Minutes = sRTC->u32Minute;
	sAlarm.AlarmTime.Seconds = sRTC->u32Second;
	sAlarm.AlarmTime.SubSeconds = 0;
	sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT_24;
	sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
	
	sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
	sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
	sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
	sAlarm.AlarmDateWeekDay = sRTC->u32Day;
	sAlarm.Alarm = RTC_ALARM_A;	
	
	while(try_count--)
	{
		if(HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) == HAL_OK)
			break;
		delay_ms(10);
	}
}

void RTC_SetAlarmDateAndTime_B(S_RTC_TIME_DATA_T *sRTC)
{
	uint8_t try_count = 3;

	RTC_AlarmTypeDef sAlarm = {0};
	
	sAlarm.AlarmTime.Hours = sRTC->u32Hour;
	sAlarm.AlarmTime.Minutes = sRTC->u32Minute;
	sAlarm.AlarmTime.Seconds = sRTC->u32Second;
	sAlarm.AlarmTime.SubSeconds = 0;
	sAlarm.AlarmTime.TimeFormat = RTC_HOURFORMAT_24;
	sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
	
	sAlarm.AlarmMask = RTC_ALARMMASK_DATEWEEKDAY;
	sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
	sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
	sAlarm.AlarmDateWeekDay = sRTC->u32Day;
	sAlarm.Alarm = RTC_ALARM_B;	
	
	while(try_count--)
	{
		if(HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) == HAL_OK)
			break;
		delay_ms(10);
	}
}

void Wakeup_ShowTime(char *preStr, S_RTC_TIME_DATA_T *pRTC)
{
	S_RTC_TIME_DATA_T sRTC;
	
	uint32_t totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, pRTC->u32Year, pRTC->u32Month, pRTC->u32Day,
					pRTC->u32Hour, pRTC->u32Minute, pRTC->u32Second);
	totalSeconds += RTC_offsetSeconds;
	Wakeup_CalcUTCTime(totalSeconds, &sRTC);
	printf("\n%s%04d-%02d-%02d %02d:%02d:%02d\n", preStr, sRTC.u32Year, sRTC.u32Month, 
		sRTC.u32Day, sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
}

// 判断是否闰年
uint8_t IsLeapYear(uint16_t year)
{
	if(year % 4)
		return 0;
	if(year % 100 == 0 && year % 400)
		return 0;
	return 1;
}

// 计算从某年开始以来经过的秒数
uint32_t Calc_SecondsFromYear(uint16_t startYear, uint16_t year, uint8_t mon, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec)
{
	uint32_t totalSeconds = 0ul;
	uint16_t i;
	
	// 计算整年的
	for(i = startYear; i < year; i++)
	{
		totalSeconds += 31536000ul;	// 365 * 86400
		if(IsLeapYear(i))	// 闰年+1天
			totalSeconds += 86400ul;
	}
	// 计算整月的
	for(i = 1; i < mon; i++)
	{
		totalSeconds += 2678400ul;	// 31 * 86400
		if(i == 4 || i == 6 || i == 9 || i == 11)
			totalSeconds -= 86400ul;
		else if(i == 2)
		{			
			totalSeconds -= 259200ul; // 3 * 86400
			if(IsLeapYear(year)) // 闰年+1天
				totalSeconds += 86400ul;
		}
	}
	// 计算整天的
	totalSeconds += (day - 1) * 86400ul;
	// 计算时分秒的
	totalSeconds += hour * 3600ul;
	totalSeconds += min * 60ul;
	totalSeconds += sec;
	
	return totalSeconds;
}

uint16_t get_year_days(uint16_t year)
{
	if(IsLeapYear(year))
		return 366;
	return 365;
}

uint16_t get_month_days(uint16_t year, uint8_t month)
{
	if(month == 4 || month == 6 || month == 9 || month == 11)
		return 30;
	if(month == 2)
	{
		if(IsLeapYear(year))
			return 29;
		return 28;
	}
	return 31;
}

// 将从INITIAL_YEAR开始的描述，转换成年月日
void Wakeup_CalcUTCTime(uint32_t totalSeconds, S_RTC_TIME_DATA_T *pRTC)
{
	uint32_t totalDays, days;

	// 计算下次唤醒的年、月、日
	pRTC->u32Year = INITIAL_YEAR;
	pRTC->u32Month = 1;
	pRTC->u32Day = 1;
	totalDays = totalSeconds / 86400ul;
	while(totalDays >= 1)
	{
		// 计算整年的
		days = get_year_days(pRTC->u32Year);
		if(totalDays >= days)
		{
			pRTC->u32Year++;
			totalDays -= days;
			continue;
		}
		
		// 计算整月的
		days = get_month_days(pRTC->u32Year, pRTC->u32Month);
		if(totalDays >= days)
		{
			pRTC->u32Month++;
			totalDays -= days;
			continue;
		}
		
		// 计算整天
		pRTC->u32Day += totalDays;
		break;
	}

	// 计算下次唤醒的时、分、秒
	totalSeconds %= 86400ul;
	pRTC->u32Hour = totalSeconds / 3600ul;
	totalSeconds %= 3600;
	pRTC->u32Minute = totalSeconds / 60ul;
	totalSeconds %= 60ul;
	pRTC->u32Second = totalSeconds;
}

// 计算下次唤醒的时间
void Wakeup_CalcWakeupTime(S_RTC_TIME_DATA_T *pRTC, uint8_t charging)
{
	uint32_t period = 300;
		
	// 先计算从初始时间以来的秒数
	uint32_t	totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, pRTC->u32Year, pRTC->u32Month, pRTC->u32Day,
					pRTC->u32Hour, pRTC->u32Minute, pRTC->u32Second);

	if(dcBuff.configData.intervalTrans > 0 && period > dcBuff.configData.intervalTrans)
		period = dcBuff.configData.intervalTrans;
	if(dcBuff.configData.intervalSample > 0 && period > dcBuff.configData.intervalSample)
		period = dcBuff.configData.intervalSample;
	
	// 无外供电，采集频率不能快于1分钟
	if((!VCC_POWER_STATUS() || (dcBuff.configDisplay.op_USE_SOLAR && dcBuff.dtuData.batVoltage <= 4500)) && period < 60)
		period = 60;
	
	if(dcBuff.configDisplay.op_ANTI_OVERFILL && Charge_Enabled && period > 10)
		period = 10;
	if(Manual_Charing && period > 10)
		period = 10;
	if(charging && period > 60)
		period = 60;
	if(dcBuff.configDisplay.op_ANTI_NORM_OPEN && Anti_Enabled && charging && period > 10)
		period = 10;
	
	// 计算下次唤醒时间的秒数
	// 将这个秒数对齐到唤醒周期的倍数
	// 这是因为：每次复位以后虽然时间是继续的，但闹钟需要重新设置
	uint32_t sec = totalSeconds + period;
	sec -= sec % period;
	// 防止闹钟时间太近
	if(sec <= totalSeconds + 2)
		totalSeconds = sec + period;
	else
		totalSeconds = sec;

	// 计算下次唤醒的年、月、日
	Wakeup_CalcUTCTime(totalSeconds, pRTC);
}

// 计算下次唤醒的时间
void Wakeup_CalcWakeupTime_B(S_RTC_TIME_DATA_T *pRTC)
{
	// 先计算从初始时间以来的秒数
	uint32_t	totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, pRTC->u32Year, pRTC->u32Month, pRTC->u32Day,
					pRTC->u32Hour, pRTC->u32Minute, pRTC->u32Second);

	// 计算下次唤醒时间的秒数
	totalSeconds += 15;

	// 计算下次唤醒的年、月、日
	Wakeup_CalcUTCTime(totalSeconds, pRTC);
}

// 设定下次闹钟唤醒时间
void Wakeup_SetAlarm(uint8_t charging)
{
    S_RTC_TIME_DATA_T sRTC;

	// 设定下次闹钟唤醒时间
	RTC_GetDateAndTime(&sRTC);
	// 显示当前时间
	Wakeup_ShowTime("RTC time is: ", &sRTC);
	Wakeup_CalcWakeupTime(&sRTC, charging);
	RTC_SetAlarmDateAndTime(&sRTC);
	// 显示唤醒时间
	Wakeup_ShowTime("***********************************************\nWakeup time is: ", &sRTC);
}

// 设定下次闹钟唤醒时间
void Wakeup_SetAlarm_B()
{
    S_RTC_TIME_DATA_T sRTC;

	// 设定下次闹钟唤醒时间
	RTC_GetDateAndTime(&sRTC);
	Wakeup_CalcWakeupTime_B(&sRTC);
	RTC_SetAlarmDateAndTime_B(&sRTC);
}

/**
  * @brief  Alarm A callback.
  * @param  hrtc RTC handle
  * @retval None
  */
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    S_RTC_TIME_DATA_T sRTC;
	static uint32_t	gpsSeconds = 0;
	uint32_t totalSeconds;

	if(Wakeup_Sleeping)
	{
		SysTick->CTRL |= (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);	
		delay_ms(10);
		
		Vcc_Enable();
		delay_ms(40);
		
		printf("\n\nWake up by RTC.\n\n");
	}
		
	// 获取当前时间
	RTC_GetDateAndTime(&sRTC);
	// 计算自上次gps定位以来的时间
	totalSeconds = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
			sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
	// 如果超过6个发送周期（最小2小时，最大1天）未发送成功，复位
	if((totalSeconds >= DTU_succTime + 7200 && totalSeconds >= DTU_succTime + dcBuff.configData.intervalTrans * 6) || totalSeconds >= DTU_succTime + 86400)
	{
		if(!dcBuff.configDisplay.op_LOCAL_DISP)
			NVIC_SystemReset();
	}

	// 每隔24小时定位一次(3秒的容错）
	if(totalSeconds + 3 >= gpsSeconds + 86400ul)
	{
		// 重新定位
		GPS_Located = 0;
		GPS_Locate = 1;
		// 重新计时
		gpsSeconds = totalSeconds;
	}
	
	if(Wakeup_Sleeping)
		DTU_semSync = 1;
	else
		DTU_semGPRS = 1;

	Wakeup_Sleeping = 0;
	
	// 设定下次闹钟唤醒时间
	Wakeup_SetAlarm(dcBuff.sampleData.charging);
}

/**
  * @brief  Alarm B callback.
  * @param  hrtc RTC handle
  * @retval None
  */
void HAL_RTCEx_AlarmBEventCallback(RTC_HandleTypeDef *hrtc)
{
	DTU_CheckSleep();
}

// 充电唤醒中断
void Vcc_Power_Handler(void)
{
	// 控制电流输出开关
	DAC7311_Open();
	
	if(Wakeup_Sleeping)
	{
		SysTick->CTRL |= (SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);	
		delay_ms(10);
		
		Vcc_Enable();
		delay_ms(40);
		Wakeup_Sleeping = 0;
		
		// 判断是否为低电平，排除干扰
		if(!VCC_POWER_STATUS())
		{
			printf("\nWakeup by DISTURB ...\n");

			// 由干扰引起的中断，发信号休眠
			return;
		}

		printf("\n\nWake up by POWER.\n\n");
		
		// 采集数据
		Sample_NotifyFromISR();
	}
	// Modbus输出打开
	VCC_RS485_ON();
}

void Wakeup_Init()
{
  LL_EXTI_InitTypeDef EXTI_InitStruct = {0};

  // 充电唤醒引脚
  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOE);

  /**/
  LL_SYSCFG_SetEXTISource(LL_SYSCFG_EXTI_PORTE, LL_SYSCFG_EXTI_LINE7);

  /**/
  EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_7;
  EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE;
  EXTI_InitStruct.LineCommand = ENABLE;
  EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
  EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING;
  LL_EXTI_Init(&EXTI_InitStruct);

  /**/
  LL_GPIO_SetPinPull(GPIOE, LL_GPIO_PIN_7, LL_GPIO_PULL_DOWN);

  /**/
  LL_GPIO_SetPinMode(GPIOE, LL_GPIO_PIN_7, LL_GPIO_MODE_INPUT);
}

void Wakeup_InitializeTime(S_RTC_TIME_DATA_T *pRTC)
{
	pRTC->u32Year = INITIAL_YEAR;
	pRTC->u32Month = 1;
	pRTC->u32Day = 1;
	pRTC->u32DayOfWeek = RTC_WEEKDAY_FRIDAY;
	pRTC->u32Hour = 0;
	pRTC->u32Minute = 0;
	pRTC->u32Second = 0;
	pRTC->u32TimeScale = RTC_CLOCK_24;
}

void Wakeup_Open()
{
	S_RTC_TIME_DATA_T sRTC;

  /** Initialize RTC Only 
  */
  hrtc.Instance = RTC;
  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
  hrtc.Init.AsynchPrediv = 127;
  hrtc.Init.SynchPrediv = 255;
  hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
  hrtc.Init.OutPutRemap = RTC_OUTPUT_REMAP_NONE;
  hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
  hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
  if (HAL_RTC_Init(&hrtc) != HAL_OK)
  {
    Error_Handler();
  }

	/* Set RTC date and time */
	Wakeup_InitializeTime(&sRTC);
	RTC_SetDateAndTime(&sRTC);

	printf("\n*******************************\n");
	printf("system reseted ...\n");

	// 设定下次闹钟唤醒时间
	Wakeup_SetAlarm(dcBuff.sampleData.charging);

  NVIC_SetPriority(EXTI9_5_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),5, 0));
  NVIC_EnableIRQ(EXTI9_5_IRQn);
 
  if(VCC_POWER_STATUS())
  {
 	// Modbus输出打开
	VCC_RS485_ON();
  }
}

// 检查是否进入掉电模式
void Wakeup_Powerdown()
{
	LL_EXTI_InitTypeDef EXTI_InitStruct = {0};
	uint32_t curr_time;
    S_RTC_TIME_DATA_T sRTC;
	static uint8_t last_PowerStatus = 0;
	uint8_t powerStatus;

#if 0	
	// 模拟充电和放电：每隔10分钟切换一次
	if(dcBuff.configDisplay.op_SEND_GPS_DATA)
	{
		RTC_GetDateAndTime(&sRTC);
		curr_time = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
			sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
		powerStatus = (curr_time / 600 % 2 == 0);
	}
	else
#endif
	{
		// 记录关电的时间
		powerStatus = VCC_POWER_STATUS();
	}
	if(last_PowerStatus != powerStatus && !powerStatus)
	{
		RTC_GetDateAndTime(&sRTC);
		Poweroff_time = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
			sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
	}
	last_PowerStatus = powerStatus;
	
	// 如果是槽车，且有外部供电，不休眠
	if(powerStatus && dcBuff.configDisplay.op_SEND_GPS_DATA)
		return;
	// 定位未成功且未超时，不允许休眠
	if(!dcBuff.configDisplay.op_SEND_GPS_DATA && Wakeup_GetWorkMode() == WORK_MODE_NORMAL && GPS_Waiting)
		return;
	// 采集任务未完成，不允许休眠
	if(Sample_Busy() || Config_Vacuum_Request)
		return;

	// 槽车，刚断电的时候延迟20分钟再休眠
	if(dcBuff.configDisplay.op_SEND_GPS_DATA)
	{
		// 正常模式的情况下，延迟休眠
		if(!powerStatus && Wakeup_GetWorkMode() == WORK_MODE_NORMAL)
		{
			// 获取当前时间
			RTC_GetDateAndTime(&sRTC);
			curr_time = Calc_SecondsFromYear(INITIAL_YEAR, sRTC.u32Year, sRTC.u32Month, sRTC.u32Day,
				sRTC.u32Hour, sRTC.u32Minute, sRTC.u32Second);
			if(Poweroff_time > 0 && curr_time >= Poweroff_time && curr_time < Poweroff_time + 1200)
//			if(Poweroff_time > 0 && curr_time >= Poweroff_time && curr_time < Poweroff_time + 60)
			{
				if((curr_time - Poweroff_time) % 10 == 0)
					printf("\ndelay sleep time: %d\n", curr_time - Poweroff_time);
				return;
			}
		}
	}
	
	// 关闭DTU
	if(Wakeup_GetWorkMode() != WORK_MODE_NORMAL || LCD_Disabled)
	{
		if(dcBuff.dtuData.networked)
			DTU_Sleep();
		else
			DTU_PowerOff();
	}
	
	// 如果显示屏在操作，不休眠
	if(Wakeup_GetWorkMode() == WORK_MODE_NORMAL && !LCD_Disabled)
		return;

	// 如果防过充电磁阀处于动作状态，不休眠
	if(dcBuff.configDisplay.op_ANTI_OVERFILL)
	{
		if((!dcBuff.configDisplay.op_ANTI_SINGLE_CTRL && IS_CHARGE_ENABLE_HIGH()) || IS_CHARGE_DISABLE_HIGH())
			return;
	}
	// 如果常开电磁阀处于闭合状态，不休眠
	if(dcBuff.configDisplay.op_ANTI_NORM_OPEN)
	{
		if(!IS_NORM_OPEN_ENABLED())
			return;
	}

	// 如果声光报警且外供电，不休眠
	if(dcBuff.configDisplay.op_ALARM_OUTPUT)
	{
		if(powerStatus)
			return;
	}
	
	// 有外部供电（且电池电压大于4.5v），不休眠
	if(powerStatus && (!dcBuff.configDisplay.op_USE_SOLAR || dcBuff.dtuData.batVoltage > 4500))
		return;
	
	// 如果RF未关闭，不休眠
	if(IS_VCC_RF_ON())
		return;
	
	// 如果是LNG-LORA版本，不休眠
	if(dcBuff.configDisplay.op_LNG_LORA)
		return;
	
	// Modbus输出关闭
	VCC_RS485_OFF();
	
	// 禁止按键功能
	NVIC_DisableIRQ(EXTI3_IRQn);
	NVIC_DisableIRQ(EXTI4_IRQn);
	NVIC_DisableIRQ(EXTI9_5_IRQn);

	// 非罐箱版，禁止加速度中断
	if(!dcBuff.configDisplay.op_BOX_VER)
	{
		EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_10;
		EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE;
		EXTI_InitStruct.LineCommand = DISABLE;
		EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
		EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING;
		LL_EXTI_Init(&EXTI_InitStruct);
	}
	
	printf("\nEnter to Power-Down ......\n");
	
	// 防止休眠意外（不喂狗）
	Watchdog_Feed();
	Wakeup_Sleeping = 1;
	
	VCC_SFLASH_FRAM_OFF();
	Vcc_Disable();
	
	// 允许按键唤醒，先清除中断标志
	LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3);
	LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4);
	LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5);
	LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6);
	NVIC_EnableIRQ(EXTI3_IRQn);
	NVIC_EnableIRQ(EXTI4_IRQn);
	NVIC_EnableIRQ(EXTI9_5_IRQn);
	
	// 设置唤醒以后的时钟源
	__HAL_RCC_PWR_CLK_ENABLE();
	__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);
	// 禁止Systick，否则不能休眠
	SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);

	// Wakeup_Sleeping在唤醒中断里面清零（如果未清零则说明休眠失败）
	do
	{
		/* Enter STOP 2 mode */
		HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
	}while(Wakeup_Sleeping);
	
	// 罐箱或槽车版，允许加速度中断
	if(dcBuff.configDisplay.op_BOX_VER || dcBuff.configDisplay.op_SEND_GPS_DATA)
	{
		// 读取运动状态
		Accelero_ReadStatus(LL_GPIO_IsInputPinSet(GPIOD, LL_GPIO_PIN_10));
		// 恢复加速度中断
		EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_10;
		EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE;
		EXTI_InitStruct.LineCommand = ENABLE;
		EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
		EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING;
		LL_EXTI_Init(&EXTI_InitStruct);
	}
	
	delay_ms(20);
	SFlash_UnlockBPR();
}

// 立即进入休眠模式（库存模式：休眠、熄屏，只能通过按键唤醒）
void Wakeup_SleepDown()
{
	LL_EXTI_InitTypeDef EXTI_InitStruct = {0};
	uint32_t curr_time;
    S_RTC_TIME_DATA_T sRTC;

	// 标记为休眠模式
	Wakeup_SleepMode = 1;
	
	// 关闭显示屏
	HT1621_ScreenOff();
	
	// 关闭所有外部电源
	VCC_GSM_OFF();
	VCC_GPS_OFF();
	VCC_RS485_OFF();
	VCC_RF_OFF();
	VCC_BD_OFF();
	VCC_SENSOR_5V_OFF();
	
	// 关闭电磁阀
	KZ_CHARGE_ENABLE_LOW();
	KZ_CHARGE_DISABLE_HIGH();
	delay_ms(1000);
	KZ_CHARGE_DISABLE_LOW();

	// 关闭报警输出
	KZ_ALARM_OFF();ALARM_OFF();
	KZ_LOW_ALARM_OFF();
	KZ_LOW_LEVEL_OFF();
	KZ_LEVEL_OFF();
	
	// 禁止RTC中断
	HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_A);
	HAL_RTC_DeactivateAlarm(&hrtc, RTC_ALARM_B);
	
	// 禁止加速度中断
	EXTI_InitStruct.Line_0_31 = LL_EXTI_LINE_10;
	EXTI_InitStruct.Line_32_63 = LL_EXTI_LINE_NONE;
	EXTI_InitStruct.LineCommand = DISABLE;
	EXTI_InitStruct.Mode = LL_EXTI_MODE_IT;
	EXTI_InitStruct.Trigger = LL_EXTI_TRIGGER_RISING_FALLING;
	LL_EXTI_Init(&EXTI_InitStruct);
	
	// 禁止按键功能
	NVIC_DisableIRQ(EXTI3_IRQn);
	NVIC_DisableIRQ(EXTI4_IRQn);
	NVIC_DisableIRQ(EXTI9_5_IRQn);

	printf("\nEnter to Sleep mode ......\n");
	
	// 防止休眠意外（不喂狗）
	Watchdog_Feed();
	
	VCC_SFLASH_FRAM_OFF();
	Vcc_Disable();
	
	// 允许按键唤醒，先清除中断标志
	LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_3);
	LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_4);
	LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_5);
	LL_EXTI_ClearFlag_0_31(LL_EXTI_LINE_6);
	NVIC_EnableIRQ(EXTI3_IRQn);
	NVIC_EnableIRQ(EXTI4_IRQn);
	NVIC_EnableIRQ(EXTI9_5_IRQn);
	
	// 设置唤醒以后的时钟源
	__HAL_RCC_PWR_CLK_ENABLE();
	__HAL_RCC_WAKEUPSTOP_CLK_CONFIG(RCC_STOP_WAKEUPCLOCK_HSI);
	// 禁止Systick，否则不能休眠
	SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);

	do
	{
		/* Enter STOP 2 mode */
		HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
	}while(Wakeup_SleepMode);
}

// 读取工作模式
uint8_t Wakeup_GetWorkMode()
{
	return Wakeup_workMode;
}

// 设置工作模式
void Wakeup_SetWorkMode()
{
	// 默认为正常工作模式
	uint8_t mode = WORK_MODE_NORMAL;
	
	// 放电状态
	if(!VCC_POWER_STATUS())
	{
		// 进入电池保护模式
		if(bat_veryLow)
			mode = WORK_MODE_PROTECT;
		// 进入充电提示模式
		else if(dcBuff.dtuData.batLow)
			mode = WORK_MODE_CHARGE;
	}
	
	printf("\nchange work mode from %d to %d\n", Wakeup_workMode, mode);
	
	// 电池保护模式
	if(mode == WORK_MODE_PROTECT)
	{
		// 关闭DTU和传感器供电
		DTU_PowerOff();
//		VCC_SENSOR_24V_OFF();
		
		// 保存模式
		Wakeup_workMode = mode;
		
		return;
	}
	
	// 解除电池保护模式
	if(Wakeup_workMode == WORK_MODE_PROTECT)
	{
	}
		
	// 充电提示模式
	if(mode == WORK_MODE_CHARGE)
	{
		// 关闭DTU和传感器供电
		DTU_PowerOff();
//		VCC_SENSOR_24V_OFF();
	}
	else
	{
//		VCC_SENSOR_24V_ON();
	}

	// 保存模式
	Wakeup_workMode = mode;
}
