/*Includes ----------------------------------------------*/ #include "nrf_delay.h" #include "nrf_strerror.h" #include "ble_comm.h" #include "exception.h" #include "system.h" #include "bsp_time.h" #include "bsp_wdt.h" #include "hal_led.h" #include "hal_ble_client.h" #include "hal_ble_host.h" #include "app_flash.h" #include "app_error.h" #include "app_client.h" #include "app_flash.h" #include "app_util_platform.h" #include "bll_imu.h" #include "app_detectIsHost.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 EXCEPT_NO_INIT_DATA_CHANGE_FLAG 0x01 //被更改标志位,每次修改结构体,都要加1 #define __NO_INIT__ __attribute__((at(0x2000FFA0))) /*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 struct { uint32_t wdt_remain_tim; //距离上次喂狗剩余时间,单位ms uint32_t thread_start_tim; uint32_t thread_end_tim; }WDT_INFO_TYPE; typedef struct { char buff[28]; }APP_ERROR_CHECK_INFO_TYPE; typedef struct _process_info { STACK_DATA_TYPE stack; WDT_INFO_TYPE wdt_info; APP_ERROR_CHECK_INFO_TYPE app_error_check_info; }Process_Info_t; 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_APP_ERROR_CHECK, //异常——APP_ERROR_CHECK EXCEPT_UNKOWN_RESET_TRIGGER_NUMS, //异常——未知重启触发原因——数量 } EXCEPT_UNKOWN_RESET_TRIGGER_e; typedef struct _except_unkown_reset_info { Process_Info_t process_info; //线程信息(堆栈信息和看门狗信息) uint32_t trigger; //导致未知重启触发的类型 uint32_t cur_process_id; //当前正在处理的进程号 uint32_t end_process_id; //处理完的进程号 uint8_t is_upload; //是否正在上传 } Except_Unkown_Reset_Info_t; typedef struct no_init { Except_Unkown_Reset_Info_t unkown_reset_info; uint32_t struct_change_flag; //被更改标志位 } 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 volatile __NO_INIT__ No_Init_t no_init_data; battercb_t battery_record={0}; /*Local Functions ----------------------------------------------*/ //没有操作系统时的异常处理 static void Except_NotOSHardFault_Handler(uint32_t msp_addr) { STACK_DATA_TYPE *p; //堆栈中存储的数据 msp_addr -= 4; //堆栈指针减去4,因为默认堆栈指针指向的是下一个空的地方-所以必须减去4 DEBUG_LOG("\r\n-----------------ERROR -----------------\r\nHardFault_Handler\r\n"); if((msp_addr >> 20) != 0x200) //判断地址范围,必须是0x200xxxxx 范围 { DEBUG_LOG("Warning: stack pointer is damaged, unable to record the scene!\r\n"); return; } msp_addr += 8; //进入中断后,堆栈又进入了2个u32数据,因此需要往后推 no_init_data.unkown_reset_info.is_upload = 1; no_init_data.unkown_reset_info.trigger |= (1<PC -= 3; //PC指针要减去3 } ////有操作系统时的异常处理 //static void Except_OSHardFault_Handler(uint32_t psp_addr) //{ // STACK_DATA_TYPE *p; //堆栈中存储的数据 // // psp_addr -= 4; //堆栈指针减去4,因为默认堆栈指针指向的是下一个空的地方-所以必须减去4 // DEBUG_LOG("\r\n-----------------ERROR -----------------\r\nHardFault_Handler\r\n"); // // // if((psp_addr >> 20) != 0x200) //判断地址范围,必须是0x200xxxxx 范围 // { // DEBUG_LOG("Warning: stack pointer is damaged, unable to record the scene!\r\n"); // return; // } // // no_init_data.unkown_reset_info[EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT].is_upload = true; // // no_init_data.unkown_reset_info[EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT].trigger = EXCEPT_UNKOWN_RESET_TRIGGER_RUN_OUT; // // memcpy(&no_init_data.unkown_reset_info[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 // //// DEBUG_LOG("R0:0x%08X\r\n", p->R0); //// DEBUG_LOG("R1:0x%08X\r\n", p->R1); //// DEBUG_LOG("R2:0x%08X\r\n", p->R2); //// DEBUG_LOG("R3:0x%08X\r\n", p->R3); //// DEBUG_LOG("R12:0x%08X\r\n", p->R12); //// DEBUG_LOG("LR:0x%08X\r\n", p->LR); //// DEBUG_LOG("PC:0x%08X\r\n", p->PC); //// DEBUG_LOG("xPSR:0x%08X\r\n", p->xPSR); //// DEBUG_LOG("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]; bll_imu_data_t data; //读取ACC值 if(bll_imu_get_data_num(BLL_IMU_DIR_FRONT) >= 1){ bll_imu_get_data(BLL_IMU_DIR_FRONT, 0, &data); f_acc[0] = data.acc[0];f_acc[1] = data.acc[1];f_acc[2] = data.acc[2]; } else return; //把鞋子倒转平放,且存在异常 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) { uint32_t tim; char buf[250]={0}; memset(buf,0,sizeof(buf)); if(no_init_data.unkown_reset_info.is_upload == 1) { if((no_init_data.unkown_reset_info.trigger & (1<pDat,target->datLen); } void Exception_Init(void) { //若结构体被改动,则重置。 if(no_init_data.struct_change_flag != EXCEPT_NO_INIT_DATA_CHANGE_FLAG) { memset((void*)&no_init_data, 0 , sizeof(No_Init_t)); no_init_data.struct_change_flag = EXCEPT_NO_INIT_DATA_CHANGE_FLAG; no_init_data.unkown_reset_info.is_upload = 0; } 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",Exception_Led_Process); Process_Start(UNKOWN_RESET_INFO_SEND_CYCLE,"Exception_UnkownReset",Exception_UnkownReset_Info_Send_Process); BLE_Host_Rx_Regist(BLE_ERR,cb_BLE_Host_R_ERR); memcpy(&battery_record,&mFlash.mbattercb_t,sizeof(battercb_t)); } /** @brief 系统错误回调 @param id: @return 无 */ void app_error_fault_handler(uint32_t id, uint32_t pc, uint32_t info) { char err_info[200]; Flash_SaveLog(id,pc,info); DEBUG_LOG("app_error_fault_handler,System reset\n"); no_init_data.unkown_reset_info.is_upload = 1; no_init_data.unkown_reset_info.trigger |= (1<p_file_name+13, p_info->line_num); memcpy((void *)&no_init_data.unkown_reset_info.process_info.app_error_check_info,err_info,sizeof(APP_ERROR_CHECK_INFO_TYPE)); break; } case NRF_FAULT_ID_SDK_ERROR: { error_info_t * p_info = (error_info_t *)info; sprintf((char *)err_info,"e:%u,f:%s,l:%u\r\n", p_info->err_code, p_info->p_file_name+13, p_info->line_num); memcpy((void *)&no_init_data.unkown_reset_info.process_info.app_error_check_info,err_info,sizeof(APP_ERROR_CHECK_INFO_TYPE)); break; } default: sprintf((char *)err_info,"UNKNOWN FAULT 0x%08X\n", pc); memcpy((void *)&no_init_data.unkown_reset_info.process_info.app_error_check_info,err_info,sizeof(APP_ERROR_CHECK_INFO_TYPE)); break; } NVIC_SystemReset(); //复位重启 } 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(app_Get_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; } //硬件中断 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(uint32_t cur_process_id) { uint32_t cur_tim,feed_watchdogtim; if(no_init_data.unkown_reset_info.is_upload == 0) { no_init_data.unkown_reset_info.cur_process_id = cur_process_id; cur_tim = NRF_RTC0->COUNTER; feed_watchdogtim = Get_FeedWatchDogTime(); if(cur_timCOUNTER; } /** @brief 获取电量记录缓存区地址 @return 电量记录缓存区地址 */ battercb_t* Except_Get_Battery_Record_Buff(void) { return &battery_record; }