星期六, 11 04月 2020 18:25

基于CAN总线的汽车诊断协议UDS (网络层 ISO 15765)

网络层的国际标准是ISO 15756-2,该标准详细规定了协议的具体细节。CAN总线是一帧8个字节,该协议可以使CAN总线高效的传输大约8个字节(up to 4095 bytes)的命令和数据。基于该标准文档,我开发出了一个独立性良好的协议栈,工作在上层诊断协议之下和下层CAN驱动之上,下面详解开发协议栈时需要实现的部分(基于 ISO 15765-2:2004(E))

网络层的国际标准是ISO 15756-2,该标准详细规定了协议的具体细节。CAN总线是一帧8个字节,该协议可以使CAN总线高效的传输大约8个字节(up to 4095 bytes)的命令和数据。基于该标准文档,我开发出了一个独立性良好的协议栈,工作在上层诊断协议之下和下层CAN驱动之上,下面详解开发协议栈时需要实现的部分(基于 ISO 15765-2:2004(E))
 
    4 Network layer overview    4.2 Services provided by network layer to higher layers    4.2小节是描述网络层协议提供给上层的服务
    (a) Communication services  (通信服务)     有四个,其中第1个是发送消息的服务,我实现为一个外部函数,提供给上层调用,第2,3,4是上层获取协议栈发送和接收状态的服务,我按照回调函数的方式实现,于是变成了上层提供给网络层的接口。如果转成C++代码,可以用虚函数来实现。
    1) N_USData.request
    是网络层提供给上层的发送消息的服务,5.2.1小节对其有详细的描述,我只实现了两个参数,msg_buf和msg_dlc,发送时根据消息长度判断是单帧发送还是多帧发送,
extern void network_send_udsmsg (uint8_t msg_buf[],uint16_t msg_dlc) { if (msg_dlc==0|| msg_dlc> UDS_FF_DL_MAX)return; if (msg_dlc= UDS_SF_DL_MAX) { send_singleframe (msg_buf, msg_dlc); } else { nwl_st = NWL_XMIT; send_multipleframe (msg_buf, msg_dlc); }}
 
    2)N_USData_FF.indication
    该服务用来通知上层,网络层收到了首帧,5.2.3小节对其有详细的描述,我实现了一个参数msg_dlc,该函数通过回调实现,具体细节在上层代码中,按下不表。
函数原型声明如下
typedef void (*ffindication_func) (uint16_t msg_dlc);
网络层接收到首帧后调用该服务。
    3)N_USData.indication
    该服务把接收到的完整消息传递给上层,5.2.4小节对其有详细的描述,我实现了3个参数,msg_buf,msg_dlc和n_result,该函数通过回调实现,具体细节在上层代码中,按下不表。
函数原型声明如下
typedef void (*indication_func) (uint8_t msg_buf[], uint16_t msg_dlc, n_result_t n_result);
该函数调用较多:
    1.接收到单帧,with N_OK
    2.接收连续帧,如果sn错误,with N_WRONG_SN
    3.接收连续帧,如果长度正确,with N_OK
    4.网络层主循环中,如果CR定时器超时,with N_TIMEOUT_Cr
    5.接收到首帧和单帧,如果网络层状态异常,with N_UNEXP_PDU
 
    4)N_USData.confirm
该服务用来通知上层,消息发送已经完成,并返回成功与否,5.2.2小节对其有详细的描述。我实现了1个参数n_result,该函数通过回调实现。具体细节在上层代码中,按下不表。
函数原型声明如下
typedef void(*confirm_func)(n_result_t n_result);
该函数调用如下:
    1.接受到流控帧,如果流状态>= FS_RESERVED, with N_INVALID_FS
    2.接收到流控帧,如果流状态== FS_OVERFLOW, with N_BUFFER_OVFLW
    3.网络层主循环中,如果BS定时器超时,with N_TIMEOUT_Bs
    b) Protocol parameter setting services (协议参数控制服务)协议参数控制服务有两个,我没有实现,具体用处我还不明白,但是不影响实现协议栈功能。
 
    6 Network layer protocol    第6节描述网络层协议内容
    6.1-6.4小节简要说明    当消息长度小于等于6(扩展地址和混合地址)或者7(普通地址)个字节时,是通过一个N_PDU(数据单元)发送完成,叫做SF(单帧)。
    当消息长度较大时,是通过多个N_PDUs(数据单元)发送完成,这种数据单元叫做FF(首帧,第一个N_PDU)和CF(连续帧,后续的N_PDUs)。
    FF(首帧)包括前面5个(扩展地址和混合地址)或者6个(普通地址)字节的内容,1个或者多个CF(连续帧),每个CF包括后续的6个(扩展地址和混合地址)或者7个(普通地址)字节的内容,当然也可以少于6个或者7个字节。消息长度信息在FF(首帧)中发送,所有的CF(连续帧)在发送端被编号,以帮助接收者按顺序重组
消息。(最后一句话没什么卵用)
    接收者通过Flow control(流控帧)的机制,告知发送者自己有多大的接收能力。(其实就是每两个FC之间允许连续发送多少个CF,每两个CF之间的时间不能过快)
Flow control 包含三个字段:
    Flow status(FS),流状态,用来控制发送方接下来的行为,总共有三个定义,分别是FC.CTS(继续发送),FC.WAIT(继续等待),FC_OVFLW(缓存溢出,此时应该终止发送)。
    Block Size (BS),每次收到流控帧之后,发送者最大可发送的连续帧的个数。
    SeparationTimeMin (STmin),两个连续帧之间的最小间隔。
    综上所述,网络层共有4中数据单元类型:SF N_PDU,FF N_PDU, CF N_PDU, FC N_PDU。详细说明在6.4节,不再赘述。
 
    Tale 2 是N_PDU format (数据单元格式),每个N_PDU由三个域组成。
 
    在使用普通地址时,地址域仅由CAN ID组成,CAN消息数据的第一个字节(或前两字节)为N_PCI Bytes。N_PCI(Protocol control information)标识了一条消息的类型和附加信息。
6.5 Protocol control information specificationTable 3描述各种类型的N_PDU 的N_PCI bytes的定义。
 
    N_PCI byte的第一个字节的高4位为N_PCItype,标识该N_PDU(数据单元)的类型。
    0,SF(单帧)
    1,FF(首帧)
    2,CF(连续帧)
    3,FC(流控帧)
    4-F,保留定义
 
我在程序中接收到一条诊断报文后,通过一条宏定义获取N_PCItype
 
#define NT_GET_PCI_TYPE(n_pci) (n_pci>>4) pci_type = NT_GET_PCI_TYPE (frame_buf[0]);
 
然后根据pci_type进行不同的处理。...

继续阅读完整内容

请查看下方广告以解锁文章剩余内容

广告加载中...
查看 24374 最后修改日期 星期六, 11 04月 2020 19:22
 

瑞驰车友会微信公众号

qrcode for gh 673928177533 258

Please support our site by viewing this advertisement.

Please support our site by viewing this advertisement

Free Content