[车联网/以太网] SOME/IP 协议

概述: SOME/IP 协议

车载以太网

  • 以太网作为车载网络的主干网络CAN网络作为车载网络的次主干网络,是智能网联汽车行业不可阻挡的大势。
  • 以太网,带宽高(支持百MB/千MB),但成本也高
  • CAN网络,带宽低(支持若干MB/数十MB),成本低,且可靠性高,大量用于嵌入式设备、工控、制造领域

  • 车载以太网协议栈总共可划分为5层:
  • 物理层
  • 数据链路层
  • 网络层
  • 传输层
  • 应用层

其中本文所要描述的SOME/IP就是一种应用层协议

  • SOME/IP协议内容按照AUTOSAR中的描述,我们可以更进一步的拆分为3类子协议
  • 应用层的SOME/IP标准协议
  • SOME/IP-SD协议
  • TP层的SOME/IP-TP协议

产生背景与动机

  • 2011年宝马公司开发设计了一套中间件,该中间件能够实现以服务为导向的通信方式

该中间件区别于传统以信号为导向的通信方式,不仅能够大大减少网络负载以提高通信双方的效率
同时,引入以太网通信也能够大大满足未来车辆不断增长的通信需求。

  • 面向信号的数据传输模式不管网络需不需要始终会不断循环发送,而面向服务的通信方式则不同,只有当网络中至少存在一个接收方需要这些数据时,发送方才会发送数据,这是一种面向服务通信方式的显著优点。

  • 宝马将该面向服务的通信方式叫做SOME/IP(全称为:Scalable service-Oriented MiddlewarE over IP, 基于IP协议的可扩展的、面向服务的中间件)。

正如其名,可见该协议跟以太网密切相关。
没错!SOME/IP就是运行在车载以太网协议栈基础之上的中间件,或者也可以称为应用层软件

SOME/IP 发展历程

  • SOME/IP正由于其知名度逐渐被AUTOSAR接纳并计划纳入其正式标准,并且在2014年集成进AUTOSAR 4.X中。其几个关键发展节点如下:
  • AUTOSAR 4.0 - 完成宝马SOME/IP消息的初步集成;
  • AUTOSAR 4.1 - 支持SOME/IP-SD及其发布/订阅功能;
  • AUTOSAR 4.2 - 添加transformer用于序列化以及其他相关优化;
  • AUTOSAR 4.3 - 修复一些transformer bug同时添加针对大量UDP数据包的SOME/IP-TP协议以及其他SOME/IP-SD的优化工作;

SOME/IP 协议的特点、协议的定位

特点 描述
Scalable(可扩展) 该协议设计的初衷之一就是为了实现不同硬件平台、不同操作系统或嵌入式固件以及不同应用软件的异构设备之间的可扩展性和互操作性。
service-Oriented(面向服务) 表明它是一种面向服务的基本协议。因此仅当客户端请求或服务器通知特定订阅者时,才在客户端-服务器配置中交换数据 ,这就确保了永远不会浪费带宽,并且仅在需要的时间和地点进行数据通信/交换。
MiddlewarE 它也是一种中间件。即其位于应用层,有自己的通用协议层来处理更具体的操作及应用;
Serialization(序列化) 在ECU内部进行序列化及反序列化以实现信息的高效传输
Remote Procedure Calls(远程调用) 该协议可以传递消息(作为字段发送)以及方法的远程调用(实现过程/函数调用)
Service Discovery(服务发现) SOME/IP协议的数据通信发生在客户端-服务器模型中,同时服务器提供客户端可以订阅的许多不同服务。该协议允许客户端动态查找服务、订阅服务并配置对服务的访问。
Publish/Subscribe(发布与订阅) SOME/IP中的数据通信通过发布/订阅进行。客户端可以订阅服务器提供的服务,服务器可以向活跃的订阅者发布通知。
Segementation of UDP message 每当服务器必须向活动订阅者发送通知时,他们是通过UDP协议发送的。SOME/IP能够在不需要任何分段的情况下传送大型UDP消息。
over IP(基于以太网) 它也是一个基于以太网的协议
它使用类似的硬件接口,确保高达 100Mbps 的带宽。
同时数据通过中间件(即应用层)通过网络电缆使用 TCP/IPUDP 协议进行通信。
当客户端需要来自服务器的数据时,它可由客户端使用 TCP 协议进行请求。
如果服务器必须将数据传送给所有活动的订阅者,则可通过 UDP 协议传输。
UDP 协议上的数据通信可以是单播、多播或广播。
如下图所示,就十分清晰地展示了SOME/IP在车载以太网协议栈中的位置以及与其他模块的关系

SOME/IP以太网协议栈层级

  • Use TCP:只有当需要传输非常大的数据块(> 1400字节),并且在存在错误的情况下没有硬延迟要求时,才使用TCP
  • Use UDP:如果需要非常硬的延迟要求(<100ms),在错误的情况下使用UDP
  • Use UDP:如果需要传输非常大的数据块(> 1400字节),并且存在错误时需要硬延迟,可以使用UDP和SOME/IP-TP

图: SOME/IP 与车载以太网协议栈关系

  • 那么在AUTOSAR协议栈中,SOME/IP协议又处于一个什么样的位置呢?

如上图可知,SOME/IP协议涉及到与RTE,COM,PDUR以及SOAd这些AUTOSAR标准模块的交互,而用于服务发现的SOME/IP-SD则涉及到BswM,SD以及SoAd模块的交互。
SOME/IP协议与各个模块的交互关系会在后续文章讲到,提及于此让大家对SOME/IP协议与AUTOSAR协议栈的关联有个整体概念,此文中不做过多展开。
SOME/IP 最初是作为另一种 RPC 机制开发的,以确保与 AUTOSAR 设备的兼容性并提供汽车用例所需的最大功能,同时它也是专为ECU间客户端-服务器序列化而设计的网络层协议。
目前,该协议可以在多种不同的操作系统上实现,包括 AUTOSAR、OSEK 和 GENIVI。它也可以在不运行操作系统的嵌入式固件上实现。
摄像头、主机、远程信息处理设备、AUTOSAR 设备,甚至信息娱乐系统等大型设备,都可以使用 SOME/IP 协议有效地交换 ECU 间消息。
Wireshark 3.2 SOME/IP 发布以来,SOME/IP 支持就已公开,可以在 Wireshark 上解析SOME/IP数据。

SOME/IP与SOA架构的关系

  • 重要论断:SOA 架构是智能网联汽车(车、云)总架构,是智能网联汽车行业的绝对主流架构

SOA

  • SOA,简而言之就是一种面向服务的架构(Service-Oriented Architecture), 当然也是一种软件设计的重要方式,IT研究与顾问咨询公司 Gartner1996 年提出的,其本身并不是新鲜概念,而且已经在IT互联网领域风靡了20余年。

  • 按照W3C对它的定义 : “SOA是一种应用程序架构,在这种架构中,所有功能都定义为独立的服务,这些服务带有定义明确的可调用接口,能够以定义好的顺序调用这些服务来形成业务流程。

  • 服务: 服务是一种比构件粒度更大的信息集合,实际是包含实现了多个关联业务需求的逻辑组合,并且允许每个服务使用特定的平台,架构或技术方案;

  • 可调用接口: 面向服务的接口不同于构件的接口,他的实现与特定语言无关,与特定的平台也无关,可十分方便的实现不同异构平台的交互;

  • 联系与区别:

首先,需要明确的是SOME/IP不是SOA,SOA也不是SOME/IP;
由于SOME/IP本身也是一种面向服务的协议,所以一般认为SOME/IP只不过是一种实现SOA可行的协议选择
一般而言,基于消息的通信与RPC(Remote Procedure Call 远程过程调用)通信都可以实现SOA,而SOME/IP就是一种基于RPC框架的协议;
可以通过SOME/IP用来实现SOA,但SOA的实现却不一定非得用SOME/IP;

SOME/IP 通信机制

SOME/IP通信三大功能

服务发现(Service Discovery)

  • SOME/IP SD 用于提供服务、发现服务、订阅事件组。
  • SOME/IP SD 只用 UDP 协议的 30490 端口通信。
  • SOME/IP SD 提供了两种动态发现服务的机制。
  • 一种是 Offer Service(Type = 0x01),由服务端广播其提供的服务;
  • 一种是 Find Service(Type = 0x00),由客户端请求可用的服务。
  • 服务发现的通信机制是通过SOME/IP-SD协议实现的,主要是为了实现在车载以太网告知客户端当前服务实例的可用性及访问方式,可通过Find ServiceOffer Service来实现。

  • SOME/IP 服务发现流程,可以分为3大基本步骤:

  • Client 通过发送Find Service的报文去寻找车载网络中可用的服务实例;
  • Server 接收到Client的Find Server后通过UDP发送Offer Service响应;
  • Client 通过发送Subcribe Event Group去订阅相关Event;
  • Server 检查是否满足Client是否满足订阅条件,如果满足回复ACK,如果不满足,则回复NACK;
  • Client 成功订阅相关事件后,Server会按照事件本身属性来实现对已订阅该事件的Client的发布;

远程进程调用(RPC)

  • 远程进程调用主要可分为四种通信模式:

Request/Response通信模式

可归纳为·Method·中的一种;其基本通信模型如下图所示:

  • Request-Response模型作为一种最为常见的通信方式,其主要任务就是客户端发送请求信息,服务端接收到请求,进行相关处理之后进行相应的响应。

Fire&Forget通信模式

可归纳为Method中的一种;

该通信模型的主要任务就是客户端向服务端发送请求,服务端无需进行任何响应,有点类似诊断服务中的抑制正响应。

Notification Event通信模式

  • 该通信模式主要描述了发布 /订阅消息内容,主要任务就是为了实现客户端向服务端订阅相关的事件组,当服务端的事件组发生或者值发生变化时,就需要向已订阅该事件组的客户端发布更新的内容。

  • Event 通信模式

远程进程控制(Field)

  • 访问进程通信机制主要是为了实现针对对应用程序的数据获取与更改,主要任务就是实现客户端通过Getter获取Server的值,通过Setter设置Server的值。

Field就可理解为一个Service的基本属性,可包含Getter,Setter,Notifier三种方式。其中Getter就是读取Field中某个值的方法,Setter就是一种改变Field值的方法,而Notifier则是一种当Field中的值发生变化的触发事件,发生变化时就通知Client。

SOME/IP 错误处理机制

  • AUTOSAR为了更为高效的定位到通讯过程中的问题所在,制定了一套检查SOME/IP协议格式内容的错误处理机制。比如版本信息检查,服务ID等,其他故障信息可以在Payload中进行详细定义。目前SOME/IP支持以下两种错误处理机制,这两种处理机制可以根据配置进行选择。
  • 消息类型0x80,Response信息,即可以通过Response Message中的Return Code来定位到问题所在;
  • 消息类型0x81,显式的错误信息;
  • 主要是校验协议首部结构,对Message TypeReturn code进行赋值,通知对端。

SOME/IP接口与核心概念

SOME/IP接口

  • SOME/IP定义服务的接口支持请求/响应模式的远程服务调用,也可以支持订阅/发布模式的消息通知

  • 事件Events: 提供周期性发送的数据,或在提供者到订阅服务器的更改时发送的数据。
  • 方法Methods: 远程过程调用, 采用Request-Response(RR)Fire&Forget(FF) 机制进行通信
  • 字段Fields: 是下列三个中的一个或多个的组合
  • notifier: 遵循订阅-发布机制,以事件组的形式来订阅, Server发送到Client
  • getter: 请求/响应调用, Client调用来显式地查询提供程序的值, request消息中payload为空,response消息中payload的值就是field的值
  • setter: 请求/响应调用,Client想更改提供程序端值时, Server要将Client设置的数据通过Response反馈给Client,以便Client确认设置的数据是否成功

服务 Service

  • 服务是 SOME/IP 的核心,服务端提供服务,客户端使用服务。服务由零个或多个方法、事件以及字段组成。

方法 Method

  • 客户端调用服务端的函数/程序/服务/方法。方法有两种形式:
  • Request & Response:常规的客户端请求,服务端响应
  • Fire & Forget(Request_NoReturn):单向客服端请求,服务端不响应

事件 Event

  • 客户端向服务端订阅事件组 EventGroup,当事件组有更新时,服务端发布消息,通知所有订阅的客户端

字段 Field

  • 方法和事件的组合,提供 Getter/Setter 两个方法用于获取/设置字段值,以及一个 Notification 事件,当字段值变化时,服务端发布消息,通知订阅的客户端

Entry

  • 用于提供服务、发现服务、订阅事件组。

  • Entry 有 Service Entry 和 EventGroup Entry 两种:

  • Service Entry

  • EventGroup Entry

SOME/IP SD 提供了两种动态发现服务的机制。一种是 Offer Service(Type = 0x01),由服务端广播其提供的服务;另一种是 Find Service(Type = 0x00),由客户端请求可用的服务

Option

  • Option 字段用来传输 Entry 的附加信息,包括对于服务实例的 IP 地址、传输协议、端口号等信息。

例如 Type = 0x04 时

SOME/IP数据传输

SOME/IP 标准协议

SOME/IP 协议格式

// SomeIP 协议格式
SomeIP {
    ushort svcID; //Service ID; 标识出一个服务
    ushort mthdID;//Method ID; 标识出一个方法
    uint   length;//Length (此字节之后的长度)
    ushort cliID; //Client ID; 客户端ID,区分不同客户端
    ushort ssID;  //Session ID; 区分统一客户端的多次调用
    uchar  ver{0x01}; //SOME/IP Version; 协议版本号;固定为0x01
    uchar ifcVer; //interfaceVer; 服务接口版本
    uchar  type;  // | Message Type [.... xxxx]  报文类型,目前共5种
    bool   isAck; // | Message Type [.x.. ....]  Message Type Ack Flag
    bool   isTP;  // | Message Type [..x. ....]  Message Type TP Flag
    uchar  retCode;//返回码Return Code (0x00 Ok) ;
    char[] payload;//数据段
}

  • 如果应用了 E2E 通信保护,则 E2E 报头将放置在 Return Code 之后,具体取决于为 E2E 报头选择的偏移值。

默认偏移值为 64 位,这将 E2E 报头恰好放置在 Return Code 和 Payload 之间。

SOME/IP Message Header

Item Description
Message ID 1. 前2个字节为Service ID,后2个字节为Method ID
2. 每个服务仅定义一个唯一的Service ID
3. Method ID的最高位(第16bit)为0即为方法(包括Method Filed.Getter及Filed.Setter),最高位为1就为事件(包括Event和Filed.Notify)

Length 4byte/32bit,标识从Request ID开始至SOME/IP报文结束的长度
Request ID 1. RequestIDClientID(前2个字节,识别一个客户端,订阅者的的唯一标识)和Session ID(后2个字节,识别同一客户端的多次请求)组成
2. ClientID每个Client ID在整个车辆中应该是唯一的,可通过配置前缀或者固定值来实现唯一性;可不进行Session处理,如果需要,则Session ID需根据各自的用例从0x0001递增
3. 案例:汽车方向盘控件可以控制娱乐音响系统的音乐播放器切换到下一曲,后排的控制面板也可控制它,那么就可以用不同的ClientID区分它们
4. 提供者在生产响应消息时,应该把RequestID复制到响应消息中,这样订阅者收到后可以根据RequestID判断这是哪条请求的响应
在响应到达之前,订阅者不得重用RequestID;
由于提供者只需要在响应中复制RequestID,所以它并不需要提前知道Client ID
5. 如果会话处理未激活SessionID应设置为0x0000;
如果会话处理处于激活状态,Session ID应设置为0x0001-0xFFFF范围内的值,并根据各自的用例递增(例如:按方向盘上的切曲按键,每按一次,SessionID就加1)
当Session ID达到 最大值0xFFFF时,它应该从0x0001重新开始
如果响应的Session ID与请求的Session ID不匹配,订阅者必须忽略这个响应
Protocol Version 1. 协议版本号,用来表示SOME/IP首部的格式,目前固定为1
2. 对于SOME/IP协议首部中的改动,Protocol Version应该增加,但是对于payload中格式的改变,Protocol Version不应该增加
Interface Version 用来识别服务接口的主版本号,由用户定义
Message Type 用来识别不同的消息类型(目前共计5种),Message Type(8Bits)的Bit5标识TP-Flag,当TP-Flag=1时,标识一个TP类型的Message Type (当SOME/IP下层通信协议为UDP,且SOME/IP传输大数据(>1452Bytes)时,将使用SomeIpTp进行分段)
Return Code 用来指示Message是否被成功处理了,或针对请求中的错误内容进行反馈
E2E Header 可选,是否使能,并且可变长度(默认长度是8Bytes),可选使用一种E2E profile(常用E2E Profile4)
Payload 1. 有效载荷,序列化和反序列化定义了 PDU 中所有数据结构的确切位置,并且考虑了内存对齐;
2. 什么是内存对齐
计算机系统为了简化处理器内存之间的传输,以及提升读取数据的速度,对数据在内存中的存储位置进行了限制,要求是某个数k的倍数,这就是所谓的内存对齐
结构体中的元素由于大小不一,就需要设置这个k值,每个元素的长度必须是这个k值的倍数,如果不满足,就需要填充一定的内存空间以满足k值的倍数;
设置对齐方式,并不意味着结构体的长度/大小发生了变化;
而对于payload里的数据结构,如果某个元素大小可变,且不是序列化数据流中的最后一个元素,则应通过在可变元素数据后插入填充位来实现数据对齐
3. SOME/IP Payload由事件的数据元素方法的参数组成,大小取决于所使用的传输层协议,对于UDP,payload介于01400个字节之间,而由于TCP支持payload分段,故支持更大的长度
4. 字节序(Byte Order):SOME/IP payload应以网络字节顺序编码,也就是大端规则传输

5. 如图示:固定长度数据元素后不应该有填充,如果非要填充,必须在规范中明确
可变长度元素后面的数据对齐应为1、2、4、8、16、32个byte

Message ID

远程过程调用

事件类

Message Type

  • 用来识别不同的消息类型,目前存在的类型如下所示,其中TP表示分包的报文,按照AUTOSAR标准(R21-11)定义如下:

其中 Message Type 取值及含义如下表:

Message Type 报文类型 说明
0x00 REQUEST 请求并期待响应(A request expecting a response)。请求,需要回复
0x01 REQUEST_NO_RETURN 请求但不期待响应(A fire&forget request)。请求,不需要回复
0x02 NOTIFICATION 通知/事件回调的请求,不期待有响应(A request for a notification expecting no response)。Notifier/Event,不需要回复
0x40 REQUEST_ACK Acknowledgment for REQUEST (optional)
REQUEST的ACK确认
0x41 REQUEST_NO_RETURN_ACK Acknowledgment for REQUEST_NO_RETURN (informational)
REQUEST_NO_RETURN的ACK确认
0x42 NOTIFICATION_ACK Acknowledgment for NOTIFICATION (informational)
NOTIFICATION的ACK确认
0x80 RESPONSE The response message
响应
0x81 ERROR The response containing an error
响应中包含的错误
0x20 TP_REQUEST TP segment of a Request Message for methods
TP请求并期待响应
0x21 TP_REQUEST_NO_RETURN TP segment of a Request Message for Fire & Forget methods
TP请求但不期待响应
0x22 TP_NOTIFICATION TP segment of an Event (Notification) Message
TP通知/事件回调的请求,不期待有响应
0xA0 TP_RESPONSE TP segment of a Response Message for methods
TP响应
0xA1 TP_ERROR TP segment of an Error Message for methods
TP响应中包含的错误

Return Code

  • 用来指示Message是否被成功处理了,或针对请求中的错误内容进行反馈,如下为AUTOSAR(R21-11)中定义的Return Code类型:
ID Name Description
0x00 E_OK 没有错误发生
0x01 E_NOT_OK 发生了未定义的错误
0x02 SOMEIPXF_E_UNKNOWN_SERVICE 未知的服务ID
0x03 SOMEIPXF_E_UNKNOWN_METHOD 未知的Method ID
0x04 SOMEIPXF_E_NOT_READY 应用程序未就绪
0x05 SOMEIPXF_E_NOT_REACHABLE 运行该服务的系统不可用
0x06 SOMEIPXF_E_TIMEOUT 发生超时
0x07 SOMEIPXF_E_WRONG_PROTOCOL_VERSION SOME/IP协议版本不支持
0x08 SOMEIPXF_E_WRONG_INTERFACE_VERSION 接口版本不匹配
0x09 SOMEIPXF_E_MALFORMED_MESSAGE 反序列化错误
0x0A SOMEIPXF_E_WRONG_MESSAGE_TYPE 接收到不符合预期的消息类型
0x0B E_E2E_REPEATED E2E重复错误
0x0C E_E2E_WRONG_SEQUENCE E2E错误的时序
0x0D E_E2E 没有进一步的E2E错误
0x0E E_E2E_NOT_AVAILABLE E2E不可用
0x0F E_E2E_NO_NEW_DATA 没有E2E计算的新数据
0x10-0x1F RESERVED 预留给到SOME/IP一般性错误
0x20-0x5E RESERVED 预留给到服务及方法的特定错误

Payload的序列化与反序列化

  • SOME/IP报文收发的过程中,上层应用所定义的MethodEventField参数都是面向用户的structstring等,序列化就是将这些输出参数转换为字节流的过程;而反序列化的过程正好相反,就是将字节流反向解析成structstring等具体的参数。

  • 大小端:

SOME/IP报文的payload(负载)大小端(字节序)指的是数据在内存中的存储和传输顺序。在计算机系统中,数据的存储和传输顺序主要有两种标准: 大端字节序(Big-Endian)和小端字节序(Little-Endian)。

  • 大端字节序(Big-Endian):是指数据的高位字节存放在低地址处,而低位字节存放在高地址处。也就是说,从内存的起始位置开始,第一个字节是最高位字节。

  • 小端字节序(Little-Endian):是指数据的低位字节存放在低地址处,而高位字节存放在高地址处。在这个模式下,内存起始位置存放的是最低位字节。

SOME/IP报文的payload部分可以采用上述两种字节序中的任何一种,这取决于数据交换双方的协议约定或者通信端点的实现。在网格协议中,端字节序通常由协议规范明确指出。开发者在处理SOME/IPP报文时,必须确保发送方和接收方在端字节序上保持一致,以避免数据解析错误。

基本数据类型

  • 布尔类型
  • 无符号整数,包括8、16、32、64位
  • 有符号整数,包括8、16、32、64位
  • 浮点数,包括32位和64位
Type Description Size [bit] Remark
boolean TRUE/FALSE value 8 FALSE (0), TRUE (1)
uint8 unsigned Integer 8
uint16 unsigned Integer 16
uint32 unsigned Integer 32
uint64 unsigned Integer 64
sint8 signed Integer 8
sint16 signed Integer 16
sint32 signed Integer 32
sint64 signed Integer 64
float32 floating point number 32 IEEE 754 binary32 (Single Precision)
float64 floating point number 64 IEEE 754 binary64 (Double Precision)

结构化数据类型(结构体)

结构体应按顺序序列化,还需考虑内存对齐

  • SOME/IP不能自动插入虚拟或填充数据。

根据配置情况,可以在结构体前插入长度字段, 以表示这个结构体数据在SOME/IP传输时的长度,长度字段的大小为8、16或32位;
如果长度字段大小大于结构体长度,则仅反序列化指定的字节,并根据长度字段跳过其他字节;
如果长度字段大小小于结构体长度,且接收方无法在本地提供数据来替换,则中止反序列化,并将SOME/IP消息视为格式错误

  • 反序列化是对序列化的反向操作,接收方根据收到的SOME/IP Payload进行的解析

string

Fixed length

Dynamic length

Array

Fixed length

one-dimensional

multi-dimensional

Dynamic Length

one-dimensional

multi-dimensional

带有标识符和可选成员的结构化数据类型和参数

  • “ 为了兼容之前或之后的版本,可以为结构成员或方法参数添加数据ID,有了这个ID,接收方才会反序列化,这样就可以设置可选成功,同时可以在任意位置添加新的成员
  • “ 每个数据ID在结构中是唯一的,不能重复,在不同的结构或方法中不需要唯一
  • “ 结构中同一层级的成员,要么全部定义数据ID,要么全部都不定义;方法中所有参数要么全部定义数据ID,要么全部都不定义

通过上图,可以看到结构体中一个元素的组成

Wire Type

  • 第1个byte的6-4位,它的值表示后面数据的类型
Wire Type Following Data
0 8 Bit Data Base data type
1 16 Bit Data Base data type
2 32 Bit Data Base data type
3 64 Bit Data Base data type
4 Complex Data Type: Array, Struct, String, Union with length field of static size (configured in data definition)
5 Complex Data Type: Array, Struct, String, Union with length field size 1 byte (ignore static definition)
6 Complex Data Type: Array, Struct, String, Union with length field size 2 byte (ignore static definition)
7 Complex Data Type: Array, Struct, String, Union with length field size 4 byte (ignore static definition)
  • Wire Type 4时长度字段是静态配置的,而5、6、7是忽略静态配置,忽略长度字段的大小
  • 根据Wire Type选择长度字段的大小,5是1个byte,6是2个byte,7是4个byte,可以看上图

Data ID

  • 第1个byte的3-0位,和第二个byte的8位,共12位

如果结构的元素或方法的参数配置了Data ID,则应该在序列化字节流中插入tag,也就是下面这个东西

还有Strings、Arrays等数据类型

SOME/IP-SD 协议 : 服务发现

服务发现的过程

  • R/R的匹配关系 (Response 用 Request 的Request ID)

SOME/IP-SD 的两大类【消息】

  • 服务发现相关(Service Discovery)
  • FindService:客户端查找服务(广播/多播)。(client)
  • OfferService:服务器响应,提供服务 IP 和端口。(server)
  • StopOfferService:服务器通知停止提供某个服务。(server)
  • 订阅相关(Event Subscription)
  • SubscribeEventgroup:客户端请求订阅某个事件组。(client)
  • SubscribeEventgroupACK:服务器确认订阅成功。(server)
  • SubscribeEventgroupNACK:服务器拒绝订阅请求。(server)
  • StopSubscribeEventgroup:客户端取消订阅事件组。(client)

SOME/IP-SD 状态机

  • SOME/IP-SD定义了服务启动后的3个阶段:
  • 初始化等待阶段(Initial Wait Phase)
  • 重复阶段(Repetition Phase)
  • 正式阶段(Main Phase)
  • 这三个阶段的起止时间以及广播间隔时间可配置的,其中重复阶段通过指数递增的方式来从一个相对小的周期开始增长服务发现广播报文的间隔

  • Initial Wait Delay: Min-100ms, Max-1s
  • Repetition Phase: Base_Delay-30ms, Repetition Max-5
  • Cyclic_Offer_Delay-1s
状态 服务端行为 客户端行为
Down Service不可用 服务未被应用请求,则停留在该状态; 收到OfferService,启动TTL计时器,此时服务若被应用请求,进入Main;
Init 进入条件: 当服务准备完毕(Available)后; During: 收到Find Service报文,服务端忽略此消息; 退出条件: 若服务不可用了,将进入Down ; INITIAL_DELAY,当定时器超时后,进入Repetition。 进入条件: 服务被请求后,进入此阶段; During: 等待INITIAL_DELAY时间; 退出条件: 如果此时收到Offer Service,则取消计时器,直接进入Main ; 如果服务请求被释放,进入Down ; 计时器超时后,发送第一个Find service,进入Repetition。
Repetition 作用: 为了让客户端快速找到有哪些Service, During: 如果收到某客户端的FindService,延迟一定时间后,单独发送单播OfferService给服务请求端; 如果收到SubscribeEventgroup后,发送单播Ack/Nack,启动此订阅Entry的TTL计时器; 如果收到StopSubscribeEventgroup后,停止此订阅Entry的TTL计时器; 退出条件: 如果服务不可用,离开此阶段进入Down ,并发送StopOfferService通知所有客户端。 作用: 重复发送Find service,直到超过最大发送次数 退出条件: 收到Offer Service,停止发送计数和计时,立即进入Main 触发发送SubscribeEventgroup; 如果服务请求被释放,进入Down ,若有订阅,则发送StopSubscribeEventgroup。
Main 作用: 此阶段将周期性发送OfferService; During: 如果收到某客户端的FindService,不影响发送计数,发送单播OfferService给服务请求端; 如果收到SubscribeEventgroup后,发送单播Ack/Nack,启动此订阅Entry的TTL计时器; 收到StopSubscribeEventgroup后,停止此订阅Entry的TTL计时器; 退出条件: 如果服务不可用,离开此阶段进入Down并发送StopOfferService。 作用: 不再周期发送Find Service,不必要负载;During: 收到Offer Service,触发发送SubscribeEventgroup; 如果收到StopOfferService,则停止所有计时器; 退出条件: 如果服务请求被释放,进入Down Phase;若有订阅,则发送StopSubscribeEventgroup。

SOME/IP-SD 协议格式

SomeIPSD {
    ushort svcID{0xFFFF}; //Service ID; 固定值 0xFFFF
    ushort mthdID{0x8100};//Method ID;  固定值 0x8100
    uint   length;//Length (此字节之后的长度)
    ushort cliID; //Client ID; 客户端ID,区分不同客户端
    ushort ssID;  //Session ID; 区分统一客户端的多次调用
    uchar  ver{0x01}; //SOME/IP Version; 协议版本号;固定为0x01
    uchar  ifcVer{0x01}; //interfaceVer; 服务接口版本;固定为0x01
    uchar  type{0x02}; // | Message Type [.... xxxx]  报文类型;固定为0x02
    bool   isAck;      // | Message Type [.x.. ....]  Message Type Ack Flag
    bool   isTP;       // | Message Type [..x. ....]  Message Type TP Flag
    uchar  retCode{0x00};//返回码Return Code;固定为0x00
    //uchar  flags; //重新启动标志+单播标志+显示初始数据控制标志
    bool   flagReboot;  // | [x... ....] Reboot Flag ; 服务重新启动后,所有消息的Reboot Flag须置为1,直到Session ID重新从1开始计数,之后的Reboot Flag须置为0。
    bool   flagUnicat;  // | [.x.. ....] Unicast Flag
    bool   flagExplicit;// | [..x. ....] Explicit Inital Data Requested Flag
    uchar  reserved[3]{0x00};//保留,3byte
    uint   entrySize;//Length of Entries Array
    Entry[entrySize]  entris;// entrySize 个 Entry
    uint   optionSize;//Length of Options Array
    Option[optionSize] options;// optionSize 个 Option
}

固定属性值 (需留意)

  • SOME/IP SD报文的Message ID固定为0xFFFF8100

SOME/IP SD报文这些属性都是固定值:

  • ServiceID(0xFFFF)、MethodID(0x8100)
  • ClientID(0x0000)、ProtocolVersion(0x01)
  • Interface Version(0x01)
  • MessageType(0x02)、ReturnCode(0x00)等
  • Flag[0] : Reboot Flag [8 Bit]

  • Flag[1] : Unicast Flag [1 Bit] 设置为‘1’,表示:该ECU支持接收单播消息

  • 对于组播和单播通信伙伴,Session ID都会单独增加并单独存储

这意味着发送到多播地址的第一条SD消息具有会话ID 0x0001,并且发送给任何单播通信伙伴的第一条SD消息也具有会话ID 0x0001

  • SOME/IP-SD仅使用event消息

Entry

Entry {
    EntryType type; // enum EntryType
    uchar     opt1stInd; //Option1排在Array里第几个
    uchar     opt2stInd; //Option2排在Array里第几个
    uchar     opt1st; //Option1的数目
    uchar     opt2st; //Option2的数目
    ushort    svcID;  // service ID
    ushort    instID; // instance ID ; 0xFFFF表示全部实例
    uchar     majorVer;
    uchar[3]  ttl; // time to live; “Entry”的生命周期,单位为秒
    union {
      uint    minorVer;
      struct  group{
        uchar reserved{0x00};
        bool  idrf;      // | [x... ....] Inital Data Requested Flag; 如初始值由服务发送,须置为1
        uchar reserved_; // | [.xxx ....]
        uchar counter;   // | [.... xxxx] 区分相同订阅者的订阅请求
        ushort groupID;  //Event Group ID; 事件组ID,也就是说SOME/IP事件订阅和取消订阅的颗粒度到一个事件组,而不是一个事件
      };
    };
}

SOME/IP 报文

SOME/IP 通信矩阵

EntryType

// Entry 有服务和 EventGroup 两种:
// 有的类型具有相同的值,这时需要通过 Entry 中的 TTL 字段来区分到底是 Start 还是 Stop,是ACK 还是 NACK。
enum EntryType : uchar {
    FindService = 0x00,
    OfferService = 0x01,
    StopOfferService = 0x01,
    SubscribeEventgroup = 0x06,
    StopSubscribeEventgroup = 0x06,
    SubscribeEventgroupAck = 0x07,
    SubscribeEventgroupNAck = 0x07
}

OptionType

//Option 字段用来传输 Entry 的附加信息,包括对于服务实例的 IP 地址、传输协议、端口号等信息。
enum OptionType :uchar {
    Configuration = 0x01, //用于传输Entry的附加信息,比如服务名等等
    IPv4_Endpoint = 0x04, //用于传输IPv4相关的参数,比如服务的IP地址、TCP还是UDP、端口号
    IPv6_Endpoint = 0x06,
    IPv4_Multcast = 0x14,
    IPv6_Multcast = 0x16
}

Option

Option {
    ushort   length; //
    OptionType  type; // enum OptionType
    uchar    reserved;
    uchar[]  data; //包括服务实例的 IP 地址、传输协议、端口号等信息。
}
// SomeIPSD 协议格式

SOME/IP-TP 协议

SOME/IP-TP主体功能

  • 我们知道CAN-TP是用来对当总线CAN数据过大时,就需要对CAN整包数据进行分割拆包进行发送,这个时候发送方的TP层就起作用,同理对于接收方而言,也需要将分割的数据包进行组包完成整包数据的重组还原。

因此,举一反三,我们便可以知道SOME/IP-TP模块的主体功能就是为了实现对应用层发送数据过大时进行的必要拆包与组包的工作,进而完成大量数据包的发送与接收。

  • SOME/IP作为一种应用层协议,即可以运行在TCP之上,也可以运行在UDP之上

由于TCP协议本身支持【发送大量数据】,同时还支持流控等特点,因此无需用到SOME/IP-TP
该TP协议仅针对运行在UDP协议基础上的SOME/IP协议。

  • 该模块作为AUTOSAR中定义的标准模块,在AUTOSAR中与各个模块的交互关系又是如何的呢?

如下图所示,则较为清晰的表明了SOME/IP-TP在CP AUTOSAR的具体位置以及与其他模块的交互关系:

图 SOME/IP-TP在AUTOSAR的位置及交互关系

从图中可以直接看出SOME/IP-TP直接与PDUR层进行交互,当上层应用模块发送大量数据时,会通过PDUR发送数据给到SOME/IP-TP模块进行拆包,拆分的包按将照协议格式再通PPDUR模块依次发送。

  • 对于接收方而言,则是接收来自PDUR的报文,通过SOME/IP-TP模块进行组包,组包后的结果给到PDUR,然后由PDUR再传输至上层应用模块

SOME/IP-TP协议头

  • SOME/IP-TP作为SOME/IP报文的一种,因此前面的SOME/IP Header则保持一致,只是SOME/IP-TP存在自身的协议头,让我们一起来学习一下。

SOME/IP-TP层的协议头字段内容:

​图:SOME/IP-TP 协议头字段内容

其中Message Type更为细节地定义如下图所示:

  • 当且仅当TP-Flag==1时,OffsetField,Reserved Field以及More Segement Flag才会存在;
  • 当TP-Flag == 1时,表示当前SOME/IP报文为被分割的报文,即Segement报文;

Y 推荐资源

AUTOSAR

SOME-IP.COM : 可扩展的面向服务的 MiddlewarE over IP (SOME/IP),官方站点

  • SOME/IP 是一种可用于控制消息的汽车中间件解决方案。
  • 它从一开始就设计为完美适合不同尺寸和不同作系统的设备。
  • 这包括摄像头、AUTOSAR 设备等小型设备,以及高达音响主机或远程信息处理设备。
  • 此外,还确保 SOME/IP 支持信息娱乐域的功能以及车辆中其他域的功能。
  • 允许 SOME/IP 用于 MOST 替换场景以及更传统的 CAN 场景。
  • Open Source Tool 支持
  • 由于 Wireshark 3.2 SOME/IP 支持是公开的!去 Wireshark 买。 Wireshark 支持 SOME/IP、SOME/IP-SD、SOME/IP-TP 和可配置的 SOME/IP 负载剖析。在以下版本中,添加了一些重要的改进,例如 TECMP 对高效流量捕获的支持。

https://www.wireshark.org/

https://github.com/LarsVoelker/FibexConverter

  • 已添加对即将推出的 Wireshark 3.6 版本的支持。敬请期待。
  • SOME/IP 技术详细信息

https://some-ip.com/details.shtml

  • SOME/IP 论文和出版物

https://some-ip.com/papers.shtml

  • SOME/IP 标准

https://some-ip.com/standards.shtml

  • Automotive Network Security(外部)

https://automotive-network-security.com/

Wireshark

  • URL
  • 简介:
  • 因为Wireshark 3.2的SOME/IP支持是公开的!去Wireshark取吧。Wireshark支持SOME/IP、SOME/IP- sd、SOME/IP- tp和可配置的SOME/IP负载分解。在接下来的版本中,添加了一些重要的改进,比如对高效流量捕获的TECMP支持。

CAPL - Vector :支持 SOME/IP 报文的模拟和解析

CAPL

  • CAPL
  • CAPL(Communication Access Programming Language,通信访问编程语言,也有别称:CAN Access Programming Language)是一种专为CAN(Controller Area Network)网络开发的编程语言,主要用于汽车行业,特别是在自动化测试和网络通信方面
  • 它是 Vector 公司专门为 CANoe开发环境设计 都变成语言
  • CAPL是一种事件驱动的语言,大多数操作基于事件的发生,如消息的接收或发送
  • 在语法和概念上和C语言类似
  • 借助CAPL,用户开源编写程序并应用到网络的各个节点上
  • 也可以利用CAPL编程加强测量分析功能,及搭建高效的自动化测试模块。
  • 基本概念和语法特点
  • 事件驱动:CAPL是一种事件驱动的语言,操作基于事件的发生
  • 基本结构:CAPL脚本包含函数,常见的有on start(开始时执行)、on stop(停止时执行)、on message(接收消息时执行)等
  • 数据类型:支持多种数据类型,包括标准的整型、浮点型、字符串,以及专门用于CAN网络的数据类型,如消息和信号
  • 函数和操作:提供广泛的内置函数和操作符,用于数据处理、消息发送、时间管理等
  • 语法:类似于C语言,具有相似的控制结构(如if-else语句、循环)和语法规则
  • 开发环境和工具集成
  • CAPL编程,在CANoeCANalyzer等软件工具中广泛使用。
  • CAPL脚本,可以在CANoe界面中的CAPL Browser中编写和调试
  • CAPL程序,包括:头文件、全局变量、事件处理和自定义函数,提高程序复用性和可维护性

CAPL的三部分

  • CAPL的事件类型包含三种:总线事件、属性事件、时间事件。

  • CAPL常用的事件类型:

常用软件开发工具: Vector CAPL Brower of CANoe / CANalyzer

  • Vector CAPL Brower
  • CAPL通常作为Vector测试工具(如CANoeCANalyzer,二者均为Vector公司的收费软件)的一部分来安装
  • CANoe : 一款总线开发环境,支持从需求分析到系统实现的整个开发过程,功能强大且支持多种动态链接库的集成。

CANoeLicense分为RUN版和FULL版。
RUN版的license只能用于基本功能测试,而FULL版则可以通过编写CAPL(Communication Access Programming Language)进行二次开发,功能更为强大

  • CANalyzer : 主要用于总线仿真,针对单个节点的测试

Vector 的 CAN 全家桶

  • CAPL 的 打开方式

CAPL可以在CANoe界面Tools>>CAPL Browser中打开。

  • CAPL界面:由功能区、程序框架浏览树、输出窗口、编辑区、访问区五部分组成

  • 程序编辑区:编写CAPL脚本的区域;
  • 程序架构浏览树:起目录的作用,可以把编辑区定位到编写的事件或函数类型的语句;
  • 输出窗口:可以输出编译过程中的事件和使用搜索时定位到的结果;
  • 访问区: 能够访问到CANoe工程加载的数据库中的信号、创建的系统变量以及CAPL函数库中的语句,直接从右侧访问区拖拽到中间编辑区使用

(注意:工程创建路径中不能有中文,否则访问不到数据库文件)。

常用软件开发工具: vTESStudio

  • 应用场景
  • 模拟ECU行为:CAPL允许工程师模拟ECU的行为,测试系统在不同输入和条件下的反应
  • 网络通信测试:用于测试和验证车辆CAN网络上的数据通信,确保数据正确无误地传输
  • 自动化测试脚本:CAPL脚本可以自动化重复的测试过程,提高测试效率和准确性
  • 集成测试环境:与Vector等工具(如CANoe)紧密集成,为复杂的测试环境提供强大支持

推荐文献

Github SOME/IP 协议的项目

CommonAPI for SOMEIP : 提供 SOME/IP 的实现,支持C++ 【推荐】

  • CommonAPI C++

  • Basic Features
  • Interface description with the easy to learn, human-readable FrancaIDL.
  • Support of Franca features as inheritance, polymorphic structs, unions.
  • Code generation for clear and not too complex C++ code.
  • Actual support for D-Bus (http://www.freedesktop.org/wiki/Software/dbus/) and SOME/IP (see http://some-ip.com/).
  • High-performance implementation by using C++ templates (runtime-performance).
  • Highly configurable for the integration on different platforms (e.g. main-loop support, support of Franca deployment files).
  • Multithreading support (thread-safe).
  • 基本特征
  • 界面描述,易于学习,人类可读的FrancaIDL。
  • 支持Franca特性,如继承、多态结构、联合。
  • 生成清晰且不太复杂的C++代码。
  • 对D-Bus的实际支持(http://www.freedesktop.org/wiki/Software/dbus/)和一些/IP(参见http://some-ip.com/).
  • 使用C++模板实现高性能(运行时性能)。
  • 高度可配置,可在不同平台上集成(例如主循环支持、Franca部署文件支持)。
  • 多线程支持(线程安全)。
  • Links

CommonAPI-SOMEIP是一个用于实现SOME/IP协议的C++运行时库,属于GENIVI联盟的开源项目,支持方法调用、事件通知等功能

  • Bindings

vSomeIP : 轻量级的SOME/IP库,适用于嵌入式系统

vSomeIP是一个基于Linux平台采用C++语言进行开发的SOME/IP协议实现,支持SOME/IP的通信和服务发现功能,并增加了少许的安全机制

ndk-someiplib : 基于Android平台的SOME/IP协议实现

这是一个基于Android平台的SOME/IP协议实现,适用于需要在Android设备上进行SOME/IP通信的场景

其他推荐文献

GitHub上的开源代码,在GitHub中搜索"vsomeip"关键字便可找到对应的开源代码学习。值得注意的是vsomeip是一种基于Linux平台采用C++语言进行开发的SOME/IP协议

推荐重点文献(规范/协议)

迟来的总结发布,这份总结2021年已经整理好,本人在2020年左右开始做someip通信协议,也是车载领域最早做someip通信协议的人之一;
同时,对vsomeip源码有着深刻的理解,是重要的issue者之一。

  • 规范
  • IEEE规范

IEEE 802.3bw:100BASE-T1
IEEE 802.3bp:1000BASE-T1
IEEE 802.1Q:VLAN

  • AUTOSAR规范

SOMEIP: AUTOSAR_PRS_SOMEIPProtocol / Requirements on SOME/IP Protocol
SOMEIP/SD: AUTOSAR_PRS_SOMEIPServiceDiscoveryProtocol
SOMEIP/SD: AUTOSAR_SWS_ServiceDiscovery
SOMEIP数据序列化: AUTOSAR_SWS_SOMEIPTransformer
SOMEIP: AUTOSAR_TR_SomeIpExample
TCP测试标准: Acceptance Test Specification of TCP communication
UDP测试标准: Acceptance Test Specification of UDP communication
IPv4测试标准: Acceptance Test Specification of IPv4 communication
TCP/IP软件接口描述: Specification of TCP/IP Stack

X 参考文献

posted @ 2025-01-16 10:32  千千寰宇  阅读(3661)  评论(1)    收藏  举报