/*Includes ----------------------------------------------*/
#include "nrf_delay.h"
#include "nrf_strerror.h"
#include "ble_comm.h"
#include "exception.h"
#include "system.h"
#include "bsp_time.h"
#include "hal_flash.h"
#include "hal_ser_imu_mode_manage.h"
#include "hal_led.h"
#include "hal_ble_client.h"
#include "hal_ble_host.h"
#include "hal_ser_imu_mode_manage.h"
#include "app_flash.h"
#include "app_error.h"
#include "app_client.h"
#include "app_flash.h"
#include "app_util_platform.h"

/*Private macro ------------------------------------------------*/
#define EXCEPT_LED_ON_ACC_Z						1500																	//加速度Z轴触发异常灯开启
#define EXCEPT_LED_OFF_ACC_Z					-1500																	//加速度Z轴触发异常灯关闭
#define LED_PROCESS_CYCLE							200																		//异常灯线程周期,ms为单位
#define EXCEPT_LED_TOGGLE_TIME				200																		//异常灯翻转周期,ms为单位
#define EXCEPT_LED_DISPLAY_TIME				10000																	//异常灯显示时长,ms为单位
#define UNKOWN_RESET_INFO_SEND_CYCLE	100																		//未知重启异常信息发送线程周期,ms为单位
#define __NO_INIT__ 									__attribute__((at(0x2000FF9C)))

/*STRUCTION ----------------------------------------------------*/
//原理如下：当异常时，硬件会将一些CPU的寄存器保存到栈中，通过在异常时获取堆栈指针SP的值，通过SP获取当前栈的位置，然后获取异常之前的PC指针的值，就知道异常的位置了。
//这个就是CPU寄存器在栈中的排列
//栈数据定义
typedef struct
{
	uint32_t R0;
	uint32_t R1;
	uint32_t R2;
	uint32_t R3;
	uint32_t R12;
	uint32_t LR;
	uint32_t PC;
	uint32_t xPSR;
}STACK_DATA_TYPE;

typedef enum{
	EXCEPT_LED_ON,																														//异常灯 - 开
	EXCEPT_LED_OFF,																														//异常灯 - 关
	
} EXCEPT_LED_SWITCH_e;

typedef enum{

	EXCEPT_UNKOWN_RESET_TRIGGER_WDT = 0,																			//异常——未知重启触发原因——看门狗
	
	EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT,																			//异常——未知重启触发原因——跑飞
	
	EXCEPT_UNKOWN_RESET_TRIGGER_NUMS,																					//异常——未知重启触发原因——数量
	
} EXCEPT_UNKOWN_RESET_TRIGGER_e;

typedef struct no_init
{
	STACK_DATA_TYPE 									stack;																	//堆栈信息
	
	uint32_t													cur_process_id;													//当前正在处理的进程号
	
	EXCEPT_UNKOWN_RESET_TRIGGER_e 		trigger;																//导致未知重启触发的类型
	
	bool															is_upload;															//是否正在上传
	
} No_Init_t;

typedef struct exception{
	
	/*private member*/
	EXCEPT_LED_SWITCH_e  							led_switch;															//异常灯开关
	
	uint16_t													led_display_time;												//异常灯显示时长
	
	uint16_t													led_toggle_time;												//异常灯翻转时长	
	
	uint8_t														except_type[EXCEPT_NUM];								//异常类型
	
	uint16_t													except_number_of_exist;									//已存在的异常数量
	
} Exception_t;

/*Local Variable ----------------------------------------------*/
static Exception_t 						ob_exception;

static __NO_INIT__ No_Init_t 	no_init_data[EXCEPT_UNKOWN_RESET_TRIGGER_NUMS];

/*Local Functions ----------------------------------------------*/
//没有操作系统时的异常处理
static void Except_NotOSHardFault_Handler(uint32_t msp_addr)
{
	STACK_DATA_TYPE *p;										//堆栈中存储的数据
	
	msp_addr -= 4;												//堆栈指针减去4，因为默认堆栈指针指向的是下一个空的地方-所以必须减去4
	SEGGER_RTT_printf(0,"\r\n-----------------ERROR -----------------\r\nHardFault_Handler\r\n");
	
 
	if((msp_addr >> 20) != 0x200)		//判断地址范围，必须是0x200xxxxx 范围
	{
		SEGGER_RTT_printf(0,"Warning: stack pointer is damaged, unable to record the scene!\r\n");
		return;
	}
	
	
	msp_addr += 8;												//进入中断后，堆栈又进入了2个u32数据，因此需要往后推
	
	no_init_data[EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT].is_upload = true;
	
	no_init_data[EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT].trigger = EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT;
	
	memcpy(&no_init_data[EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT].stack, (STACK_DATA_TYPE *)msp_addr, sizeof(STACK_DATA_TYPE));
	
	p = (STACK_DATA_TYPE *)msp_addr;
	p->PC -= 3;														//PC指针要减去3
	//BackupArea_RecordHardFault(RTC_GetSec(), p->PC);		//记录异常pc指针信息到备份区
	SEGGER_RTT_printf(0,"R0:0x%08X\r\n", p->R0);
	SEGGER_RTT_printf(0,"R1:0x%08X\r\n", p->R1);
	SEGGER_RTT_printf(0,"R2:0x%08X\r\n", p->R2);
	SEGGER_RTT_printf(0,"R3:0x%08X\r\n", p->R3);
	SEGGER_RTT_printf(0,"R12:0x%08X\r\n", p->R12);
	SEGGER_RTT_printf(0,"LR:0x%08X\r\n", p->LR);
	SEGGER_RTT_printf(0,"PC:0x%08X\r\n", p->PC);
	SEGGER_RTT_printf(0,"xPSR:0x%08X\r\n", p->xPSR);
	SEGGER_RTT_printf(0,"system reset...\r\n");
}

//有操作系统时的异常处理
static void Except_OSHardFault_Handler(uint32_t psp_addr)
{
	STACK_DATA_TYPE *p;										//堆栈中存储的数据
	
	psp_addr -= 4;												//堆栈指针减去4，因为默认堆栈指针指向的是下一个空的地方-所以必须减去4
	SEGGER_RTT_printf(0,"\r\n-----------------ERROR -----------------\r\nHardFault_Handler\r\n");
	
 
	if((psp_addr >> 20) != 0x200)		//判断地址范围，必须是0x200xxxxx 范围
	{
		SEGGER_RTT_printf(0,"Warning: stack pointer is damaged, unable to record the scene!\r\n");
		return;
	}
	
	no_init_data[EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT].is_upload = true;
	
	no_init_data[EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT].trigger = EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT;
	
	memcpy(&no_init_data[EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT].stack, (STACK_DATA_TYPE *)psp_addr, sizeof(STACK_DATA_TYPE));
	
	p = (STACK_DATA_TYPE *)psp_addr;
	p->PC -= 3;												//PC指针要减去3
	//BackupArea_RecordHardFault(RTC_GetSec(), p->PC);		//记录异常pc指针信息到备份区
	SEGGER_RTT_printf(0,"R0:0x%08X\r\n", p->R0);
	SEGGER_RTT_printf(0,"R1:0x%08X\r\n", p->R1);
	SEGGER_RTT_printf(0,"R2:0x%08X\r\n", p->R2);
	SEGGER_RTT_printf(0,"R3:0x%08X\r\n", p->R3);
	SEGGER_RTT_printf(0,"R12:0x%08X\r\n", p->R12);
	SEGGER_RTT_printf(0,"LR:0x%08X\r\n", p->LR);
	SEGGER_RTT_printf(0,"PC:0x%08X\r\n", p->PC);
	SEGGER_RTT_printf(0,"xPSR:0x%08X\r\n", p->xPSR);
	SEGGER_RTT_printf(0,"system reset...\r\n");
}

static void Exception_Led_Process(void);

static void Except_Led_Close(void)
{
	//全功率关闭
	Process_SetHoldOn(Exception_Led_Process,0);
	ob_exception.led_switch = EXCEPT_LED_OFF;
	ob_exception.led_display_time = EXCEPT_LED_DISPLAY_TIME/LED_PROCESS_CYCLE;
	ob_exception.led_toggle_time = EXCEPT_LED_TOGGLE_TIME/LED_PROCESS_CYCLE;
	LED_Stop(LED_EXCEPT);
}
static void Except_Led_OpenOnce(void)
{
	//异常灯显示/关闭
	if(ob_exception.led_display_time != 0)
	{
		//全功率开启
		Process_SetHoldOn(Exception_Led_Process,1);		
		
		if(ob_exception.led_toggle_time == 0)
		{
			if(ob_exception.led_switch == EXCEPT_LED_ON)ob_exception.led_switch = EXCEPT_LED_OFF;
			else ob_exception.led_switch = EXCEPT_LED_ON;
			
			ob_exception.led_toggle_time = EXCEPT_LED_TOGGLE_TIME/LED_PROCESS_CYCLE;
		}
		else
		{
			if(ob_exception.led_switch == EXCEPT_LED_ON)LED_Start(LED_EXCEPT,COLOR_ORANGE);
			if(ob_exception.led_switch == EXCEPT_LED_OFF)LED_Start(LED_EXCEPT,COLOR_BLACK);
			ob_exception.led_toggle_time--;
		}
		
		ob_exception.led_display_time--;
	}
}
static void Exception_Led_Process(void)
{
	int16_t f_acc[3];
	ser_imu_data_t data;
	//读取ACC值
	if(hal_ser_imu_mode_manage_get_data_num(SER_IMU_DIR_FRONT) >= 1){
		hal_ser_imu_mode_manage_get_data(SER_IMU_DIR_FRONT, 0, &data);
		f_acc[0] = data.acc[0];f_acc[1] = data.acc[1];f_acc[2] = data.acc[2];
	}
	
	//把鞋子倒转平放，且存在异常
//	SEGGER_RTT_printf(0,"Exception_Led_Process:%d,%d,%d\n",f_acc[0],f_acc[1],f_acc[2]);
	if(f_acc[2] >= EXCEPT_LED_ON_ACC_Z && ob_exception.except_number_of_exist > 0)
	{
		Except_Led_OpenOnce();
	}//把鞋子正放
	else if(f_acc[2] <= EXCEPT_LED_OFF_ACC_Z)
	{
		Except_Led_Close();
	}
}

static void Exception_UnkownReset_Info_Send_Process(void)
{
	char buf[255];
	
	static uint8_t cur_flow = 0;
	
	for(int i = 0; i < EXCEPT_UNKOWN_RESET_TRIGGER_NUMS; i++)
	{
		if(no_init_data[i].is_upload == true)
		{
			switch(no_init_data[i].trigger)
			{
				case EXCEPT_UNKOWN_RESET_TRIGGER_WDT:
					sprintf(buf,"id:%d\r\n",no_init_data[i].cur_process_id);
					if(Except_TxError(EXCEPT_UNKOWN_RESET,buf) == 0){no_init_data[i].is_upload = false;}
					break;
				
				case EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT:
					sprintf(buf,"id:%d,R:0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x\r\n",	no_init_data[i].cur_process_id, \
																																							no_init_data[i].stack.R0, \
																																							no_init_data[i].stack.R1, \
																																							no_init_data[i].stack.R2, \
																																							no_init_data[i].stack.R3, \
																																							no_init_data[i].stack.R12, \
																																							no_init_data[i].stack.LR, \
																																							no_init_data[i].stack.PC - 3, \
																																							no_init_data[i].stack.xPSR);
					if(Except_TxError(EXCEPT_UNKOWN_RESET,buf) == 0){no_init_data[i].is_upload = false;}
					break;
				
				default:
					break;
			}
			
			if(no_init_data[i].trigger == EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT)
			{
				SEGGER_RTT_printf(0,"R0:0x%08X\r\n", no_init_data[i].stack.R0);
				SEGGER_RTT_printf(0,"R1:0x%08X\r\n", no_init_data[i].stack.R1);
				SEGGER_RTT_printf(0,"R2:0x%08X\r\n", no_init_data[i].stack.R2);
				SEGGER_RTT_printf(0,"R3:0x%08X\r\n", no_init_data[i].stack.R3);
				SEGGER_RTT_printf(0,"R12:0x%08X\r\n", no_init_data[i].stack.R12);
				SEGGER_RTT_printf(0,"LR:0x%08X\r\n", no_init_data[i].stack.LR);
				SEGGER_RTT_printf(0,"PC:0x%08X\r\n", no_init_data[i].stack.PC - 3);
				SEGGER_RTT_printf(0,"xPSR:0x%08X\r\n", no_init_data[i].stack.xPSR);
				SEGGER_RTT_printf(0,"id:%d\r\n", no_init_data[i].cur_process_id);
			}
			else
			{
				SEGGER_RTT_printf(0,"id:%d\r\n", no_init_data[i].cur_process_id);
			}
		}
	}
}

/*API ----------------------------------------------*/

/**
	@brief 		注册接收右鞋错误信息的回调
	@param 		Handle
	@return 	无
*/
void cb_BLE_Host_R_ERR(void* handle)
{
	BLE_Host_Rx_t* target = handle;
	BLE_Client_Tx_Send(0,BLE_ERR,target->pDat,target->datLen);
}

void Exception_Init(void)
{
//	memset(&no_init_data, 0 , sizeof(No_Init_t)*EXCEPT_UNKOWN_RESET_TRIGGER_NUMS);
	memset(&ob_exception, 0 , sizeof(ob_exception));
	ob_exception.led_switch = EXCEPT_LED_OFF;
	ob_exception.led_display_time = EXCEPT_LED_DISPLAY_TIME/LED_PROCESS_CYCLE;
	ob_exception.led_toggle_time = EXCEPT_LED_TOGGLE_TIME/LED_PROCESS_CYCLE;
	
	Process_Start(LED_PROCESS_CYCLE,"Exception_Led_Process",Exception_Led_Process);
	
	Process_Start(UNKOWN_RESET_INFO_SEND_CYCLE,"Exception_UnkownReset_Info_Send_Process",Exception_UnkownReset_Info_Send_Process);
	
	BLE_Host_Rx_Regist(BLE_ERR,cb_BLE_Host_R_ERR);
}

/**
	@brief 		系统错误回调
  @param 		id: 
	@return 	无
*/
void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
{
	Flash_SaveLog(id,pc,info);
	SEGGER_RTT_printf(0,"app_error_fault_handler,System reset\n");
	nrf_gpio_cfg_output(PIN_RESET_PIN); 	nrf_gpio_pin_write(PIN_RESET_PIN,0);
}

int Except_TxError(ExcepType_t excep_type,const char *errstr){
	
	uint8_t buf[250];
	uint8_t L=0;
	uint16_t err_strlen =0;
	err_strlen = strlen(errstr);
	if(err_strlen > (sizeof(buf)-2))return -1;
	if(mFlash.isHost)buf[L++] =0;//0左鞋1右鞋
	else buf[L++] =1;
	buf[L++] = excep_type;		  	//错误编号
	
	memcpy(&buf[L],errstr,err_strlen);
	L +=err_strlen;
	
	return BLE_Client_Send(BLE_ERR,buf,L);
}

void Except_SetExceptype(ExcepType_t excep_type)
{
	if(ob_exception.except_type[excep_type] != 1)
	{
		ob_exception.except_type[excep_type] = 1;
		ob_exception.except_number_of_exist++;
	}
}

void Except_ClearExceptype(ExcepType_t excep_type)
{
	if(ob_exception.except_type[excep_type] == 1)
	{
		ob_exception.except_type[excep_type] = 0;
		if(ob_exception.except_number_of_exist != 0)ob_exception.except_number_of_exist--;
	}
}

bool Except_IsError(ExcepType_t excep_type)
{
	if(ob_exception.except_type[excep_type] == 1)
	{
		return true;
	}
	
	return false;
}

bool Except_IsErrorExist(void)
{
	if(ob_exception.except_number_of_exist > 0)return true;
		
	return false;
}

//硬件中断
void HardFault_Handler (void)
{
	uint32_t msp_addr = __get_MSP();		//获取线程模式下堆栈指针位置
	uint32_t psp_addr = __get_PSP();		//获取中断下的堆栈指针位置-用于OS启动后
	
#if(UCOS_II_EN)						//使能了操作系统的一个宏定义，自己去定义
	if(SYS_GetOsStartup())			//操作系统运行了-自己定义一个状态，可以获取操作系统是否启动
	{
		Except_OSHardFault_Handler(psp_addr);
	}
	else
	{
		Except_NotOSHardFault_Handler(msp_addr);
	}
#else //没有使能操作系统
	Except_NotOSHardFault_Handler(msp_addr);	
#endif //UCOS_II_EN
	
	nrf_delay_ms(10); 					//延时一下，防止重启速度太快
	
	NVIC_SystemReset();				//复位重启	
}

void Except_Get_Cur_Porcess_ID(int cur_process_id)
{
	for(int i = 0; i < EXCEPT_UNKOWN_RESET_TRIGGER_NUMS; i++)
	{
		if(no_init_data[i].is_upload == false)
		{
			no_init_data[i].cur_process_id = cur_process_id;
		}
	}
}

void Except_Unkown_Reset_WDT_Set(void)
{
	no_init_data[EXCEPT_UNKOWN_RESET_TRIGGER_WDT].is_upload = true;
}




















