/******************** (C) COPYRIGHT 2011 嵌入式开发工作室 ******************** * 文件名 :can_app.c * 描述 : * * 版本 :V1.0 **********************************************************************************/ #include "Sys.h" #include "adc.h" #include "can.h" #include "CanBusDrv.h" #include "candrvctrl.h" static st_cl candrv_if[2]; /***************************************************************************** * 记录每一个CAN ID的发送时间 ****************************************************************************/ static struct { unsigned int frame_id; /* ID */ unsigned int period; /* 发送周期 */ unsigned int send_tick; /* 发送TICK */ unsigned int sent_tick; /* 发送成功TICK */ } CAN_ID_SENT_TICK_MAP[] = { {CANBMS65CINFOID_WULING, 1000, 0, 0}, {CANBMS38AINFOID_WULING, 100, 0, 0}, {CANBMS38BINFOID_WULING, 100, 0, 0}, {CANBMS38CINFOID_WULING, 100, 0, 0}, {CANBMS38DINFOID_WULING, 100, 0, 0}, {CANBMS38EINFOID_WULING, 100, 0, 0}, {CANBMS598INFOID_WULING, 1000, 0, 0}, {CANBMS599INFOID_WULING, 1000, 0, 0}, {CANBMS59AINFOID_WULING, 1000, 0, 0}, }; void can2_bus_error_cb(e_link_sts err); /**************************************************************************** * @brief: 检测can ID的实际发送时间是否超过指定时间 * * @param frame_id: 要检测的CAN ID, * @param outtime: 超时时间,单位ms * * @return: bool * true: 周期超时 * false: 未达到超时时间 */ bool can_sent_cycle_timeout(unsigned int frame_id) { unsigned short i; for (i=0; i < (sizeof(CAN_ID_SENT_TICK_MAP)/sizeof(CAN_ID_SENT_TICK_MAP[0])); i++) { if (CAN_ID_SENT_TICK_MAP[i].frame_id == frame_id) { if ( CAN_ID_SENT_TICK_MAP[i].sent_tick == 0) { return true; } // if (CAN_ID_SENT_TICK_MAP[i].send_tick == 0 || CAN_ID_SENT_TICK_MAP[i].sent_tick == 0) // { // return true; // } #if 0 else if (abs(CAN_ID_SENT_TICK_MAP[i].sent_tick - CAN_ID_SENT_TICK_MAP[i].send_tick) < 5) { /* 发送时间和发送成功时间相近,则表示肯定上一次发送成功了,用发送时间进行对比 */ if (TickOut(&CAN_ID_SENT_TICK_MAP[i].send_tick, CAN_ID_SENT_TICK_MAP[i].period)) { return true; } else { return false; } } #endif else if (TickOut(&CAN_ID_SENT_TICK_MAP[i].sent_tick, CAN_ID_SENT_TICK_MAP[i].period - 3)) { /* 发送时间和发送成功时间不相近,则表示肯定上一次发送失败了,用上一次发送成功时间进行对比 */ return true; } else { return false; } } } return true; } /**************************************************************************** * @brief: 记录每一个CANid的发送成功的时间 * * @param frame_id: 发送成功CAN ID * * @return: void */ static __inline void can_sent_tick_update(unsigned int frame_id) { unsigned short i; for (i=0; i < (sizeof(CAN_ID_SENT_TICK_MAP)/sizeof(CAN_ID_SENT_TICK_MAP[0])); i++) { if (CAN_ID_SENT_TICK_MAP[i].frame_id == frame_id) { TickOut(&CAN_ID_SENT_TICK_MAP[i].sent_tick, 0); } } } /**************************************************************************** * @brief: 记录每一个CANid的发送的时间 * * @param frame_id: 发送成功CAN ID * * @return: void */ static __inline void can_send_tick_update(unsigned int frame_id) { unsigned short i; for (i=0; i < (sizeof(CAN_ID_SENT_TICK_MAP)/sizeof(CAN_ID_SENT_TICK_MAP[0])); i++) { if (CAN_ID_SENT_TICK_MAP[i].frame_id == frame_id) { TickOut(&CAN_ID_SENT_TICK_MAP[i].send_tick, 0); } } } /*can 包 发送*/ int8_t can_write( CanTxMsg *TxMessage) { u16 time_up = 0; if (candrv_if[0].SEND != NULL) { return candrv_if[0].SEND(0, (TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId, \ TxMessage->Data, (TxMessage->RTR == CAN_RTR_DATA)?TxMessage->DLC:0, \ (TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId,NULL); } return 0; } int8_t can_write2( CanTxMsg *TxMessage) { u16 time_up = 0; uint8_t TransmitMailbox; static u16 sendpoweronflag = 0; static u8 sendlowvoltflag = 0; static u8 sendhighvoltflag = 0; #if 1 if(sendpoweronflag++ < 12) //刚上电不判断输入电压 { } else { if(sendpoweronflag > 100)sendpoweronflag =100; if(sendlowvoltflag == 0) { if (Sample_DataS.VIN_Input_Voltage < 5.90) { sendlowvoltflag = 1; return 1; } } else { if (Sample_DataS.VIN_Input_Voltage < 6.40) { return 1; } else { sendlowvoltflag = 0; } } if(sendhighvoltflag == 0) { if (Sample_DataS.VIN_Input_Voltage > 18.1) { sendhighvoltflag = 1; return 1; } } else { if (Sample_DataS.VIN_Input_Voltage > 17.6) { return 1; } else { sendhighvoltflag = 0; } } } #endif //UDS禁止发送 if (!UdsApi_Is_UdsEnableNCMTx()) { return 1; } if (candrv_if[1].SEND != NULL) { if (candrv_if[1].SEND(1, (TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId, \ TxMessage->Data, (TxMessage->RTR == CAN_RTR_DATA)?TxMessage->DLC:0, \ (TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId, NULL)) { /* 暂时不需要更新 */ //can_send_tick_update((TxMessage->IDE == CAN_ID_EXT)?TxMessage->ExtId:TxMessage->StdId); return 0; } } return 0; } /************************************************************************************************************ * 总线异常BUSSOFF的处理 ***********************************************************************************************************/ typedef enum { E_BUS_NORMAL = 0, E_BUS_BUSOFF, E_BUS_RECOVERY_ACK, } bus_recovery_step_e; typedef struct { unsigned char step; /* 0 - 正常 1 - bus off 延时 2-bus off recovery 确认 */ unsigned int bus_off_tick; /* 触发bus off的时间 */ unsigned int recovery_tick; /* recovery的时间 */ unsigned short recovery_times; /* 连续recovey次数 */ unsigned char first_frm; } bus_off_recovery_t; static const unsigned short BUS_OFF_TIME_MS[] = {30, 198, 198, 198, 198, 198}; static bus_off_recovery_t canbus[BSP_CAN_CHANNEL_NUM]; /** * @brief: 处理bus off的recovery操作 * * @param : void * * @return: void * * @remark: 自动恢复总线,可放在定时器或在循环内,其被执行的间隔不能超过10ms。 */ #include "led.h" extern void WULING_DCDCSendBms2_force(void); extern u8 EntSlpFlag ; void can_bus_off_recovery(void) { unsigned char i; unsigned int timeout; unsigned char buffer[8]={0}; for (i = 0; i < BSP_CAN_CHANNEL_NUM; i++) { // if ((canbus[i].step == E_BUS_BUSOFF) && (EntSlpFlag==0)/* && 非休眠条件*/) if ((canbus[i].step == E_BUS_BUSOFF)/* && 非休眠条件*/) { if (canbus[i].recovery_times < (sizeof(BUS_OFF_TIME_MS)/sizeof(BUS_OFF_TIME_MS[0]))) { timeout = BUS_OFF_TIME_MS[canbus[i].recovery_times]; } else { /* reopen 超过指定次数则使用设定的最后一个间隔 */ timeout = BUS_OFF_TIME_MS[(sizeof(BUS_OFF_TIME_MS)/sizeof(BUS_OFF_TIME_MS[0]))-1]; } if (TickOut(&canbus[i].bus_off_tick, timeout)) { SYS_ENTER_CRITICAL(); canbus[i].recovery_times++; if (candrv_if[i].ConfigBus != NULL) candrv_if[i].ConfigBus(i, 0,0,0); canbus[i].step = E_BUS_RECOVERY_ACK; // /* 模拟发送网络管理数据包 */ // if(ChkPwrManageAccoff()!=0 ) // { buffer[0]=1; // } if (candrv_if[i].SEND!= NULL) candrv_if[i].SEND(i, CANBMS65CINFOID_WULING, buffer, 8, CANBMS65CINFOID_WULING, NULL); SYS_EXIT_CRITICAL(); TickOut(&canbus[i].recovery_tick, 0); canbus[i].first_frm = 1; } } else if (canbus[i].step == E_BUS_RECOVERY_ACK) { if (TickOut(&canbus[i].recovery_tick, 103)) { WULING_DCDCSendBms2_force(); canbus[i].recovery_times = 0; canbus[i].step = E_BUS_NORMAL; } } } } /** * @brief: 打印 can 总线状态 */ void can_bus_off_status_printf(void) { printf("can 1: step(%d), recorvery(%d), last bus off tick(%d), last recovery tick(%d)!\n", \ canbus[0].step, canbus[0].recovery_times, canbus[0].bus_off_tick, canbus[0].recovery_tick); printf("can 2: step(%d), recorvery(%d), last bus off tick(%d) last recovery tick(%d)!\n", \ canbus[1].step, canbus[1].recovery_times, canbus[1].bus_off_tick, canbus[1].recovery_tick); } /*********************************************************************************************** * 以下是应用层针对总线底层的接口 **********************************************************************************************/ void can2_bus_error_cb(e_link_sts err) { if (err != e_err_bussoff) { /* 不是BUSS OFF暂时不处理 */ return; } if (canbus[1].step != E_BUS_BUSOFF) { if (candrv_if[1].CloseLink != NULL) candrv_if[1].CloseLink(1); canbus[1].step = E_BUS_BUSOFF; TickOut(&canbus[1].bus_off_tick, 0); } } static void can2_comm_sent_cb(unsigned int canid, unsigned int result) { /* 发送回调 */ if (result == _SUCCESS) { /* 发送成功 */ can_sent_tick_update(canid); if (canbus[1].first_frm > 0 && canbus[1].step == E_BUS_RECOVERY_ACK) { canbus[1].first_frm = 0; TickOut(&canbus[1].recovery_tick, 0); } } else if (result == _ABANDON) { /* 因为异常恢复 */ } else { /* 发送失败 */ } } static st_pl can2_protocol = { "整车协议", 0, 3, 10, NULL, can2_bus_error_cb, can2_comm_sent_cb }; #if 0 static void can1_bus_error_cb(e_link_sts err) { } static void can1_comm_sent_cb(unsigned int canid, unsigned int result) { /* 发送回调 */ } #endif static st_pl can1_protocol = { "整车协议", 0, 3, 10, NULL, NULL, NULL }; void InitCanDrvCtrlMode(void); void InitCanifToCanDrvCtrl(void); bool InstallProtocalToIF(unsigned char chan, st_pl* ppl, st_cl * pcl); /** * @brief: 初始化can 协议的基础功能 */ void can_porting_init(void); /** * @brief: 初始化can 协议的基础功能的调度 */ void can_porting_schedule(void); void app_can_handle(void) { static uint8_t bms_rev_busy_flag = 0; static CanRxMsg MutliBMSCAN1Msg; CanRxMsg rec_message; unsigned int id; unsigned char data[8], len; can_porting_schedule(); while (candrv_if[0].REC != NULL && candrv_if[0].REC(0,&id, data, &len) == true) { /* 数据接收 */ CAN_FRAME_INIT((CanTxMsg *)(&rec_message), id, data, len); rec_message.FMI = 0; bms_rev_busy_flag = 1; if(bms_RcvCanSingleDataProc(rec_message) == 1) { MutliBMSCAN1Msg = rec_message; bms_RcvCanMutliData(MutliBMSCAN1Msg,0,&bms_rev_busy_flag); } IWDG_Feed(); } while (candrv_if[1].REC != NULL && candrv_if[1].REC(1,&id, data, &len) == true) { /* 数据接收 */ CAN_FRAME_INIT((CanTxMsg *)(&rec_message), id, data, len); rec_message.FMI = 0; //UDS允许接收 if (UdsApi_Is_UdsEnableNCMRx()) { bms_RcvCan2DataProc(rec_message); } UdsApi_MsgQueueIn(rec_message); memset(&rec_message,0,sizeof(rec_message)); // bms_RcvCan2DataProc(rec_message); IWDG_Feed(); } can_bus_off_recovery(); } void app_can_init(void) { memset(&canbus[0], 0x00, sizeof(canbus)); memset(&candrv_if[0], 0x00, sizeof(candrv_if)); can_porting_init(); InitCanDrvCtrlMode(); InitCanifToCanDrvCtrl(); if(InstallProtocalToIF(0,&can1_protocol,&candrv_if[0]) == true) { printf("can1 协议初始化成功\r\n"); } if(InstallProtocalToIF(1,&can2_protocol,&candrv_if[1]) == true) { printf("can2 协议初始化成功\r\n"); } if (candrv_if[0].ConfigBus != NULL) { candrv_if[0].ConfigBus(0, 0, 0, 0); } if (candrv_if[1].ConfigBus != NULL) { candrv_if[1].ConfigBus(1, 0, 0, 0); } }