基于UDS的DoIp实现(五) -- UDS单帧、多帧处理
通常来讲,上位机一般只会发送8个字节数据,那么对于UDS,只需要处理这个8个字节就可以,这里也不会涉及大数据传输。但是,有些机器,比如毫米波雷达,其设计是64位,那么每次发送的数据,按照单帧的处理,是无法接收完全的,这个时候就需要进行多帧处理。
以下列举部分帧类型,以及区分方法:
//pci type typedef enum { SINGLE_FRAME = 0x00, FIRST_FRAME = 0x10, CONSECUTIVE_FRAME = 0x20, FLOW_CONTROL_FRAME = 0x30 } UDS_PCI_Type_T;
解释:
SINGLE_FRAME:单帧,其第一个字节为0x00 | 数据长度(这个长度通常是不需要的);
FIRST_FRAME:首帧,其第一个字节为0x10 | 数据长度;
CONSECUTIVE_FRAME:连续帧,其第一个字节为0x20 | 块号(1、2、3.....);
FLOW_CONTROL_FRAME:流控帧,这个是UDS服务向上位机发送请求数据的帧信息,其第一个字节为0x30 | 块号(也有的实现,将块号放在第二个或第三个字节发出去)。
s_boolean ReceiveMsg(u_uint8_t *buffer, u_uint16_t len) { //数据检测实现 //获取帧类型 UDS_PCI_Type_T type = buffer[0] & FRAME_TYPE_MASK; //按照不同的类型,执行不同的操作 if (type == SINGLE_FRAME) { return receive_sf(buffer, len); } else if (type == FIRST_FRAME) { return receive_ff(buffer, len); } else if (type == CONSECUTIVE_FRAME) { return receive_cf(buffer, len); } //其它操作 return SE_LORF; }
s_boolean receive_sf(u_uint8_t *buffer, u_uint16_t len) { //数据处理 char *ptr = GetValidBuffer(len); memcpy(ptr, buffer, len); //通知UDS Server,已经获取数据 return S_OK; }
单帧的实现,只是一些数据检测、拷贝数据操作,过程还是比较简单的,但是多帧的实现,就比较复杂了。
多帧流程图:
+----------------+ +----------------+ | Client | | Server | +----------------+ +----------------+ | | | Send frame 1 | |---------------------------------->| | | | Receive acknowledgement for frame1 | |<----------------------------------| | | | Send frame 2 | |---------------------------------->| | | | Receive acknowledgement for frame2 | |<----------------------------------| | | | ... | | | | | | Send frame n | |---------------------------------->| | | | Receive acknowledgement for frame n | |<----------------------------------| | | | Process the entire message and | | send the processing result. | |---------------------------------->| | | | Receive processing result. | |<----------------------------------| | | | Done. | | | +----------------+ +----------------+ | Client | | Server | +----------------+ +----------------+
解释:(Client -上位机 Server - UDS服务)
- 上位机先发送第一帧,逻辑判断是FF后,进行FF处理;
- 服务向上位机发送FC,请求下一帧;
- 上位机接收到请求后,再发送一帧(CF);
- 后面便进入FC与CF的循环中,直到数据完全发送结束。
示例:
s_boolean receive_ff(u_uint8_t *buffer, u_uint16_t len) { //数据处理,获取数据长度、分块信息 char *ptr = GetValidBuffer(len); memcpy(ptr, &buffer[2], len - 2); //发送FC send_fc(mFrame.current_block); //其它处理 }
s_boolean send_fc(int block_cnt) { u_uint8_t tx_buf[MSG_SEND_SIZE] = {0}; tx_buf[0] = (FLOW_CONTROL_FRAME | block_cnt); //发送tx_buf到上位机 }
s_boolean receive_cf(u_uint8_t *buffer, u_uint16_t len) { //数据检测、保存 if (判断数据是否接收完成) { //接收完成处理 } else { //未接收完成,继续请求数据 send_fc(++mFrame.current_block); } //其它处理 }