/*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; }