#include "bms/sae1939.h" /* 缩写 全称 翻译 DLL data link layer 数据链路层 */ #define TIMEOUT_T1 750 //750ms #define TIMEOUT_T2 1250 //1250ms #define TIMEOUT_T3 1250 //1250ms #define TIMEOUT_T4 1050 //1050ms #define TP_CM_PGN 0x00EC00 //CM-多包传输的连接管理 #define TP_DT_PGN 0x00EB00 //DT-多包数据传输 #define TP_CM_RTS 16 //RTS-请求发送 #define TP_CM_CTS 17 //CTS-允许发送 #define TP_CM_ENDOFMSGACK 19 //结束应答 #define TP_CM_ABORT 255 //放弃连接 static U16_T u16_timer_count = 0; //定时其计数值 /** * ************************************************************************ * @brief - 用于上层清除底层的多包状态 * * @param[in] pt_dll_data - 1393层数据 * * * @author jiankalka * @date 2025-08-12 * ************************************************************************ */ void v_sae1393_clear_multi_pacet(DLL_DATA_T *pt_dll_data) { pt_dll_data->e_msg_state = NONE; } /** * ************************************************************************ * @brief - SAE1393层发送函数,单包报文直接发送,多包报文此函数只传送RTS,多包传输处理在u32_sae1393_rx内进行 * 注:27930中 不存在多包发送,此处仅考虑发送单包数据 * @param[in] pt_dll_data - 1393层数据 * @param[in] pt_can_data - 要送的报文 * * @return U32_T - 0:发送成功,1:发送失败 * * @author jiankalka * @date 2025-08-12 * ************************************************************************ */ U32_T u32_sae1393_tx(DLL_DATA_T *pt_dll_data, CAN_DATA_T *pt_can_data) { CAN_DATA t_msg; U32_T i; U8_T SendCmd = ((pt_can_data->u32_pgn & 0x0000FF00) >> 8); memset(&t_msg, 0, sizeof(CAN_DATA)); if (pt_can_data->u16_len <= 8) { //单包发送 t_msg.ID = u32_get_can_ID(pt_can_data->u8_pri,SendCmd,pt_can_data->u8_dest_addr,pt_can_data->u8_src_addr); //组帧ID t_msg.Len = pt_can_data->u16_len; for (i=0; iu8_data[i]; return pt_dll_data->u32_can_tx(&t_msg); //这样定义有助于多个can口复用 } return 1; } void v_delay_set_tymer_val(void) { u16_timer_count ++; } U32_T u32_delay_get_timer_val() { return u16_timer_count; } //计算时间间隔(单位:ms) (b+MAX-a)%MAX U32_T u32_delay_time_elapse(U32_T tim3_cnt_start, U32_T tim3_cnt_end) { if(tim3_cnt_end >= tim3_cnt_start) return (tim3_cnt_end-tim3_cnt_start)*10; else return (65535-tim3_cnt_end+tim3_cnt_start-1)*10; } /** * ************************************************************************ * @brief - SAE1393层接收函数,接收到多包请求后 发送cts应答报文 * * @param[in] ExtId - 帧ID * @param[in] Pgn - 多包帧pgn * @param[in] pack_num - 包总数 * @param[in] pack_cnt - 请求包数 * @param[in] t_tx_msg - 组帧报文内容 * * * @author jiankalka * @date 2025-08-13 * ************************************************************************ */ void v_sae1939_cts_send(U32_T ExtId,U32_T Pgn, U8_T pack_num , U8_T pack_cnt, CAN_DATA *t_tx_msg) { t_tx_msg->ID = (ExtId & 0xFFFF0000); t_tx_msg->ID |= ((ExtId & 0xFF00) >> 8 ); //帧ID目标地址 源地址转换 t_tx_msg->ID |= ((ExtId & 0x00FF) << 8 ); t_tx_msg->ID = (t_tx_msg->ID & 0xFF00FFFF)|(TP_CM_PGN << 8); //将帧ID PGN赋值为0xEC t_tx_msg->Len = 8; t_tx_msg->Data[0] = TP_CM_CTS; t_tx_msg->Data[1] = pack_num; t_tx_msg->Data[2] = pack_cnt; t_tx_msg->Data[3] = 0xFF; t_tx_msg->Data[4] = 0xFF; t_tx_msg->Data[5] = ((Pgn >> 16) & 0xFF); t_tx_msg->Data[6] = ((Pgn >> 8 ) & 0xFF); t_tx_msg->Data[7] = ((Pgn ) & 0xFF); } /** * ************************************************************************ * @brief - sae1939 放弃连接发送 * * @param[in] ExtID - 帧ID * @param[in] Pgn - 多包帧报文对应 PGN * @param[in] t_tx_msg - 发送can数据组包 * * * @author jiankalka * @date 2025-08-13 * ************************************************************************ */ void v_sae1939_abort_send(U32_T ExtID, U32_T Pgn, CAN_DATA *t_tx_msg) { t_tx_msg->ID = (ExtID & 0xFFFF0000); t_tx_msg->ID |= ((ExtID & 0xFF00) >> 8 ); //帧ID目标地址 源地址转换 t_tx_msg->ID |= ((ExtID & 0x00FF) << 8 ); t_tx_msg->Len = 8; t_tx_msg->Data[0] = TP_CM_ABORT; t_tx_msg->Data[1] = 0xFF; t_tx_msg->Data[2] = 0xFF; t_tx_msg->Data[3] = 0xFF; t_tx_msg->Data[4] = 0xFF; t_tx_msg->Data[5] = ((Pgn >> 16) & 0xFF); t_tx_msg->Data[6] = ((Pgn >> 8 ) & 0xFF); t_tx_msg->Data[7] = ((Pgn ) & 0xFF); } /************************************************************* 函数名称: v_sae1939_EndofMsgACK_send 函数功能: SAE1393层接收函数,放弃连接函数 输入参数: pt_dll_data 接收报文 输出参数: t_tx_msg 发送报文 返回值 :void **************************************************************/ /** * ************************************************************************ * @brief - 多包完成接收 发送结束应答帧 * * @param[in] pt_dll_data - sae1939 控制数据 * @param[in] t_tx_msg - 发送组包CAN数据 * * * @author jiankalka * @date 2025-08-13 * ************************************************************************ */ void v_sae1939_EndofMsgACK_send(DLL_DATA_T *pt_dll_data, CAN_DATA *t_tx_msg) { t_tx_msg->ID = ((U32_T)(pt_dll_data->u8_pri & 0x07) << 26); t_tx_msg->ID |= ((TP_CM_PGN & 0x0000FF00) << 8); t_tx_msg->ID |= ((pt_dll_data->u8_dest_addr & 0xFF) ); t_tx_msg->ID |= ((pt_dll_data->u8_src_addr & 0x00FF) << 8 ); t_tx_msg->Len = 8; t_tx_msg->Data[0] = TP_CM_ENDOFMSGACK; t_tx_msg->Data[1] = (U8_T)(pt_dll_data->u16_len); t_tx_msg->Data[2] = (U8_T)(pt_dll_data->u16_len>>8); t_tx_msg->Data[3] = (pt_dll_data->u16_len+6)/7; t_tx_msg->Data[4] = 0xFF; t_tx_msg->Data[5] = (U8_T)(pt_dll_data->u32_pgn); t_tx_msg->Data[6] = (U8_T)(pt_dll_data->u32_pgn>>8); t_tx_msg->Data[7] = (U8_T)(pt_dll_data->u32_pgn>>16); } /************************************************************* 函数名称: u32_sae1393_rx 函数功能: SAE1393层接收函数,此函数需要在BMS处理层主循环内调用, 处理报文的接收和多包报文的发送,也处理1393层的超时事件 输入参数: pt_dll_data -- 1393层数据, rxMsg -- 待解析的报文 输出参数: pt_can_data -- 保存接收到的完整报文 返回值 :0:接收成功,pt_can_data指向的报文可用;1:接收失败,pt_can_data指向的报文不可用 **************************************************************/ /** * ************************************************************************ * @brief - SAE1393层接收函数,此函数需要在BMS处理层主循环内调用,处理报文的接收和多包报文的发送,也处理1393层的超时事件 * * @param[in] pt_dll_data - 1393层控制数据 * @param[in] pt_can_data - CAN解析存储数据 * @param[in] t_rx_msg - 接收CAN数据-原报文数据 * * @return U32_T - 1说明接收完整帧 0未接收完整帧 * * @author jiankalka * @date 2025-08-13 * ************************************************************************ */ U32_T u32_sae1393_rx(DLL_DATA_T *pt_dll_data, CAN_DATA_T *pt_can_data, CAN_DATA t_rx_msg) { CAN_DATA t_tx_msg; U32_T u32_ret = 0; U32_T i, u32_pgn,u32_data; S32_T j; U8_T u8_src_addr, u8_dest_addr, u8_pri, u8_r_dp, u8_data_len; u8_pri = ((t_rx_msg.ID & 0x1C000000) >> 26); //优先级 u8_r_dp = ((t_rx_msg.ID & 0x03000000) >> 24); //0 u32_pgn = ((t_rx_msg.ID & 0x00FF0000) >> 8); //pgn - 是分辨多包使用,而不是bms数据内的bgn u8_src_addr = t_rx_msg.ID & 0xFF; //源地址 u8_dest_addr = ((t_rx_msg.ID & 0x0000FF00) >> 8); //目标 u8_data_len = t_rx_msg.Len; //数据长度 (void)u8_r_dp; if (u32_pgn == TP_CM_PGN) //接收帧为多包连接管理帧 { if(u8_data_len != 8) //管理帧帧长度都为8 return u32_ret; switch(t_rx_msg.Data[0]) { case TP_CM_RTS: //接收到对方发送的请求发送报文,回复CTS(允许发送) if ((pt_dll_data->e_msg_state == NONE) || //一级 状态为空闲时,直接接收 (((pt_dll_data->e_msg_state == RX_WAIT_DATA_T2) || (pt_dll_data->e_msg_state == RX_WAIT_DATA_T1)) && //一级 接收状态下 重复接收相同帧 (pt_dll_data->u32_pgn == ((t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5])) && //二级 接受帧pgn与正在接受的数据相同 (pt_dll_data->u8_src_addr == u8_src_addr) && (pt_dll_data->u8_dest_addr == u8_dest_addr))) //二级 接收帧 目标地址和发送地址相同 { //回复CTS u32_data = (U32_T)((t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5]); v_sae1939_cts_send(t_rx_msg.ID ,u32_data, t_rx_msg.Data[3],1, &t_tx_msg); if (pt_dll_data->u32_can_tx(&t_tx_msg) == 0) //发送成功 { pt_dll_data->e_msg_state = RX_WAIT_DATA_T2; pt_dll_data->u32_time = u32_delay_get_timer_val(); pt_dll_data->u32_pgn = (t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5]; //记录接收多包报文的pgn,有多个多包时也先收此pgn pt_dll_data->u8_src_addr = u8_src_addr; pt_dll_data->u8_dest_addr = u8_dest_addr; pt_dll_data->u8_pri = u8_pri; pt_dll_data->u16_len = ((U16_T)(t_rx_msg.Data[2])<<8) | t_rx_msg.Data[1]; pt_dll_data->u8_packet_cnt = t_rx_msg.Data[3]; pt_dll_data->u8_retry = 0; //等待接收数据,将缓存区置0xFF for (i=0; it_packet[i].u8_data, 0xFF, 7); pt_dll_data->t_packet[i].u8_flag = 0; } } } else //放弃连接 { //回复Abort u32_data = (U32_T)((t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5]); v_sae1939_abort_send(t_rx_msg.ID , u32_data, &t_tx_msg); pt_dll_data->u32_can_tx(&t_tx_msg); pt_dll_data->e_msg_state = NONE; } break; case TP_CM_ABORT: //结束应答 if ((pt_dll_data->e_msg_state == RX_WAIT_DATA_T2) || (pt_dll_data->e_msg_state == RX_WAIT_DATA_T1)) { if ((u8_src_addr == pt_dll_data->u8_src_addr) && (pt_dll_data->u8_dest_addr == u8_dest_addr) && (pt_dll_data->u32_pgn == ((t_rx_msg.Data[7]<<16) | (t_rx_msg.Data[6]<<8) | t_rx_msg.Data[5]))) { pt_dll_data->e_msg_state = NONE; } } break; default: break; } } else if (u32_pgn == TP_DT_PGN) //接收多包数据帧 { if ((t_rx_msg.Len == 8) && //长度为8 (pt_dll_data->u8_src_addr == u8_src_addr) && (pt_dll_data->u8_dest_addr == u8_dest_addr) && //接收报文目标、发送地址与报存的一致 ((pt_dll_data->e_msg_state == RX_WAIT_DATA_T2) || (pt_dll_data->e_msg_state == RX_WAIT_DATA_T1)) && //正在接收多包数据状态下 (t_rx_msg.Data[0] != 0)) //包序号不为0 { pt_dll_data->e_msg_state = RX_WAIT_DATA_T1; pt_dll_data->u32_time = u32_delay_get_timer_val(); pt_dll_data->t_packet[t_rx_msg.Data[0]-1].u8_flag = 1; memcpy(pt_dll_data->t_packet[t_rx_msg.Data[0]-1].u8_data, &(t_rx_msg.Data[1]), 7); for (i=0; iu8_packet_cnt; i++) //找到未接收的包,即下一个要求上送的包 { if (pt_dll_data->t_packet[i].u8_flag == 0) break; } //多包数据接收完成 if (i >= pt_dll_data->u8_packet_cnt) { pt_dll_data->e_msg_state = NONE; u32_ret = 1; pt_can_data->u32_pgn = pt_dll_data->u32_pgn; pt_can_data->u8_src_addr = u8_src_addr; pt_can_data->u8_dest_addr = u8_dest_addr; pt_can_data->u8_pri = u8_pri; pt_can_data->u16_len = pt_dll_data->u16_len; if (pt_can_data->u16_len > (SAE1939_MULTI_PACKET_MAX_NUM*7)) pt_can_data->u16_len = (SAE1939_MULTI_PACKET_MAX_NUM*7); for (i=0; iu16_len; i++) pt_can_data->u8_data[i] = pt_dll_data->t_packet[i/7].u8_data[i%7]; //发送EndofMsgACK v_sae1939_EndofMsgACK_send(pt_dll_data,&t_tx_msg); pt_dll_data->u32_can_tx(&t_tx_msg); } else if (pt_dll_data->t_packet[pt_dll_data->u8_packet_cnt-1].u8_flag == 1) //有包未接收,但是最后一包接收了,说明有丢包的 则重新申请丢的包 { pt_dll_data->e_msg_state = RX_WAIT_DATA_T2; pt_dll_data->u32_time = u32_delay_get_timer_val(); for (j=pt_dll_data->u8_packet_cnt-1; j>=0; j--) { if (pt_dll_data->t_packet[j].u8_flag == 0) break; } //回复CTS u32_data = pt_dll_data->u32_pgn; t_rx_msg.ID = (t_rx_msg.ID & 0xFF00FFFF)|(TP_CM_PGN << 8); //将帧ID PGN赋值为0xEC v_sae1939_cts_send(t_rx_msg.ID ,u32_data, j-i+1,i+1, &t_tx_msg); pt_dll_data->u32_can_tx(&t_tx_msg); } } } else //单包数据 { u32_ret = 1; //返回解析成功 pt_can_data->u32_pgn = u32_pgn; pt_can_data->u8_src_addr = u8_src_addr; pt_can_data->u8_dest_addr = u8_dest_addr; pt_can_data->u8_pri = u8_pri; pt_can_data->u16_len = t_rx_msg.Len; for (i=0; iu8_data[i] = t_rx_msg.Data[i]; } #if 1 //超时处理 switch (pt_dll_data->e_msg_state) { case RX_WAIT_DATA_T2: if (u32_delay_time_elapse(pt_dll_data->u32_time, u32_delay_get_timer_val()) > TIMEOUT_T2) { //回复Abort u32_data = ((U32_T)(pt_dll_data->u8_pri & 0x07) << 26); u32_data |= ((TP_CM_PGN & 0x0000FF00) << 8); u32_data |= ((U32_T)(pt_dll_data->u8_src_addr) <<8 ); u32_data |= pt_dll_data->u8_dest_addr; v_sae1939_abort_send(u32_data , pt_dll_data->u32_pgn, &t_tx_msg); pt_dll_data->u32_can_tx(&t_tx_msg); pt_dll_data->e_msg_state = NONE; } break; case RX_WAIT_DATA_T1: if (u32_delay_time_elapse(pt_dll_data->u32_time, u32_delay_get_timer_val()) > TIMEOUT_T1) { //回复Abort u32_data = ((U32_T)(pt_dll_data->u8_pri & 0x07) << 26); u32_data |= ((TP_CM_PGN & 0x0000FF00) << 8); u32_data |= ((U32_T)(pt_dll_data->u8_src_addr) <<8 ); u32_data |= pt_dll_data->u8_dest_addr; v_sae1939_abort_send(u32_data , pt_dll_data->u32_pgn, &t_tx_msg); pt_dll_data->u32_can_tx(&t_tx_msg); pt_dll_data->e_msg_state = NONE; } break; default: break; } #endif return u32_ret; }