SOMEIP官方文档 【4 Protocol specification】

        SOME/IP提供基于车载网络的面向服务的通信功能,SOME/IP的服务定义列出了该服务可以对外提供的功能。一个SOME/IP服务由一个或者多个事件(event),方法(method)和属性(field)组成。

        其中事件(event)可以按照周期,也可以在数据发生变化的时候向服务的订阅者发送数据。

        方法(method)让服务的订阅者发起远程方法调用,并且方法的执行在服务的提供这这边。

        属性(field)由下面的三个部分组成(实际属性可以只包含其中的get,set或者notifier中的某一个或者多个):

  1. notifier: 当notifier关联的属性的值发生变化时或者周期性将属性的值从服务的提供方发送给服务的订阅方

  2. getter: 可以被服务订阅方调用的方法(本质上是服务中的method),订阅方通过getter方法获取服务提供方的该属性的当前值

  3. setter: 可以被服务订阅方调用的方法(同上),订阅方通过setter方法设置该属性的当前值

        notifer和event的主要区别就是event一般是在数据发生变化的时候才发送给订阅方(vsomeip中在event的配置中增加update-cycle属性可以做到周期发送),而notifier是可以自动并且周期的将属性值发送给对方的。

4.1 Specification of SOME/IP Message Format (Serialization)

        序列化描述了PDU(Protocol Data Unit)中数据被序列化的方式,PDU中的数据作为TCP/UDP消息的Payload,通过IP网络层传输。

4.1.1 Limitation

        不支持SOME/IP消息的乱序段(segments)的重新排序。

4.1.2 Header

• Message ID (Service ID/Method ID) [32 Bits]

• Length [32 Bits] • Request ID (Client ID/Session ID) [32 Bits]

• Protocol Version [8Bits] • Interface Version [8 Bits] • Message Type [8 Bits] • Return Code [8 Bits]

[PRS_SOMEIP_00941] 在E2E的通信保护机制中,E2E的Header被放置在Reture Code(SOME/IP的Header的最后一个字节)后面,偏移长度是64bit,正好将E2E的Header放置在Return Code和Payload中间。

[PRS_SOMEIP_00031] 由于互操作性的原因(不同厂商的SOMEIP实现可以互相通信),不同厂商的SOME/IP协议栈的实现版本,其的Header的布局需要完全相同(按照上文的图示),Header中的字段的顺序是从上到下,从左到右。

4.1.2.1 Message ID [32 Bit]

[PRS_SOMEIP_00034] Message ID应当是一个32bit的标识符,用于标识:

• 标识SOME/IP应用中的一个方法 • 或者标识一个事件

Note: MessageID是由用户或者整个SOME/IP应用系统的设计者分配的,用来保证不同服务的不同方法/事件的MessageID是唯一的。

4.1.2.2 Method ID [16 Bit]

[PRS_SOMEIP_00245] MessageID字段应当是有16bit长度的ServiceID标识符(可以表示2的16次方个服务)和16bit长度的MethodID标识符组成(服务中最多可以有2的16次方的元素,包括方法和事件)。

Note: 一个通常的惯例和做法是将MethodID拆分为方法(Method)和事件(Event)/通知(Notifier),其中方法(Method)的MethodID的范围是 0x0000 - 0x7FFF (16bit的首位是0),而事件(Event)/通知(Notifier)的MethodID的范围是 0x8000 - 0x8FFF (16bit的首位是1) 。

 

        Eventgroup是一个包含事件(event)和通知(notifier)的逻辑组,这些事件或者通知同属于一个SOME/IP Service,并且允许其他应用订阅。

[PRS_SOMEIP_00365] 一个SOME/IP事件组至少包含一个事件(event)。

[PRS_SOMEIP_00366] 一个事件(event)至少映射到一个SOME/IP事件组。

4.1.2.3 Length [32 Bit]

[PRS_SOMEIP_00042] 长度字段从长度字段后面的Request ID/Client ID开始到该SOME/IP消息结尾部分的长度。

4.1.2.4 Request ID [32 Bit]

        Request ID让SOME/IP的服务端和客户端可以区分相同方法(method),属性(field)的设置方法(setter)和获取方法(getter)的不同调用(对于同一个ServiceID/MethodID的不同次调用)。

[PRS_SOMEIP_00043] 对于SOME/IP的request-response 类型的方法(method)的不同次调用,每次调用的requestresponse报文中的Request ID字段需要不同。

[PRS_SOMEIP_00704] Response报文中的Request ID需要和对应需要回复的Request报文中的Request ID一致。

Note: Request ID的机制让客户端可以将服务端的响应(response)映射到本地发出多个方法(method)的某次请求(request)上,即使存在某些请求还没有收到服务端响应的情况。

[PRS_SOMEIP_00044] 对于SOME/IP 服务的客户端来说,对于服务端方法(method)调用的Request报文,在没有收到服务端对该Request报文的对应的Response报文之前,后面对相同服务端方法(method)调用的Request报文不能使用还没有收到Response的Reqeuest报文中的Request。

        这样做是因为服务端还在处理之前的REQUEST,如果又收到同一个Request ID的Request报文,那么服务端就会困惑这次Response是应答客户端的哪一次Request了。

Request ID的结构:

Note:

        一个ECU的实现方可以根据需求定义SOME/IP客户端的Client ID,而SOME/IP的服务端不需要关心和客户端的Client ID,它只需要在回复Response报文的时候拷贝完整的Request ID就可以了。

[PRS_SOMEIP_00702] Client ID是ECU中一个SOME/IP客户端的唯一标识符,ECU通过Client ID区分同一个SOME/IP 方法的不同调用方。

[PRS_SOMEIP_00703] Session ID是用于区分来自同一个SOME/IP客户端/服务端发送的连续的消息或者请求(服务端也会主动发送Event/Notifier)。

        实际测试下来,对于Event/Notifier来说,因为是FF类型的通信,客户端不会有Response消息响应,因此对于一次事件变更/属性值变化,SOME/IP服务端进程发送出去的Notification(通知)报文,无论到达几个SOME/IP客户端,其Session ID是相同的,只有下一次发送该事件/属性的时候,Session ID才会递增+1。

[PRS_SOMEIP_00532] Client ID应当支持整车环境下的唯一性,可以通过配置ClientID前缀或者设置固定值的方式(例如,Client ID的最高位字节设置为诊断地址或者给特定应用程序/SWC配置的Client ID),例如:

[PRS_SOMEIP_00932] 在SOME/IP会话功能还未打开的时候,Session ID应该被设置为 0x00 (实际发送的SOMEIP报文中,是不存在Session ID等于0的报文的)。

[PRS_SOMEIP_00933] 在SOME/IP会话功能打开后,Session ID的范围在 0x01 - 0xFFFF

[PRS_SOMEIP_00934] 在SOME/IP会话功能打开后,Session ID应该在各自的应用场景内进行递增(关于应用场景的说明在formation about dedicat [PRS_SOMEIP_00533]和 (RS_SOMEIP_00027) 中)

[PRS_SOMEIP_00533] Request/Response方法应当使用Session ID来处理会话,Session ID应当在每次Request/Response调用对完成后递增(SOME/IP客户端发出Request报文,然后收到SOME/IP服务端响应的Response报文)。

[PRS_SOMEIP_00521] 当Session ID到达 0xFFFF后,需要从 0x01 重新开始。

[PRS_SOMEIP_00739] 对于Request/Response 类型的SOME/IP 方法,当客户端收到的Response报文中的Session ID和发送的Request报文中的Session ID不一致(例如找不到哪个Request报文中有该Session ID),那么客户端需要无视该Response报文。

[PRS_SOMEIP_00935] 对于SOME/IP Header中MessageType为Notificaiton消息来说,收到Notification消息的SOME/IP应用如果还没有打开会话功能,那么就应当无视收到的Notification消息。

[PRS_SOMEIP_00936] 对于SOME/IP Header中MessageType为Notificaiton消息来说,打开会话功能后的SOME/IP应用收到Notification消息后应当根据应用场景处理Session ID(具体的应用场景在[PRS_SOMEIP_00741])。

4.1.2.5 Protocol Version [8 Bit]

Protocol Version(协议版本号)可以确定SOME/IP消息Header部分的格式。

[PRS_SOMEIP_00052] Protocol Version应当是一个8bit的字段,包含了SOME/IP协议版本号。

[PRS_SOMEIP_00050] 当在SOME/IP Header中存在不兼容的修改时,Protocol Version应当递增,当使用旧协议版本(Protocol Version)来解析SOME/IP消息的应用去解析新版本的SOME/IP消息时,是无法正确解析,只能丢弃该消息。

Note:

SOME/IP消息处理和异常处理的行为在4.2.6.3章节定义。

Note:

Protocol Version是SOME/IP Header中的一个字段,因此其在Header中的位置是不能发生变化的。

Note:

SOME/IP payload部分格式的改动不会影响Protocol Version(只有SOME/IP Header部分的调整才会)。

[PRS_SOMEIP_00051] 当前Protocol Version的版本号值为 1。

4.1.2.6 Interface Version [8 Bit]

[PRS_SOMEIP_00053] Interface Version应当是一个8bit的字段,包含了SOME/IP Service中所包含接口的版本信息。

4.1.2.7 Message Type [8 Bit]

[PRS_SOMEIP_00055] Message Type字段值如下:

字段值定义描述
0x00REQUEST期待SOME/IP服务端返回RESONSE消息作为响应
0x01REQUEST_NO_RESPONSESOME/IP客户端发送,属于Fire&Forget请求,不期待服务端返回RESPONSE
0x02NOTIFICATIONSOME/IP服务端发送,带有通知(notification)/事件(event)数据的REQUEST请求,并且不期待客户端返回RESPONSE
0x80RESPONSERESPONSE消息,由SOME/IP服务端发送
0x81ERROR带有错误信息的RESPONSE消息,由SOME/IP服务端发送
0x20TP_REQUESTTP类型的REQUEST消息,并且期待SOME/IP服务端返回TP_RESONSE消息作为响应
0x21TP_REQUEST_NO_RESPONSETP类型的REQUEST消息,不期待服务端返回TP_RESPONSE
0x22TP_NOTIFICATIONSOME/IP服务端发送,带有通知(notification)/事件(event)数据的TP_REQUEST请求,并且不期待客户端返回TP_RESPONSE
0xa0TP_RESPONSETP_RESPONSE消息,由SOME/IP服务端发送
0xa1TP_ERROR带有错误信息的TP_RESPONSE消息,由SOME/IP服务端发送

[PRS_SOMEIP_00701] 通常一个REQUEST类型 (message type为0x00) 的消息应当有一个RESPONSE消息 (message type为0x80) 作为响应。如果SOME/IP的服务端应用在处理REQUEST消息时发生错误,那么会返回一个Error Message (message type为0x81) 给SOME/IP的客户端。

SOME/IP客户端可以发送一个不期待服务端响应的REQUEST报文(message type为0x01) 。SOME/IP的服务端可以发送通知消息 (message type为0x02) 来更新某个事件或者属性值给订阅的SOME/IP客户端。

[PRS_SOMEIP_00367] Message Type的第三个bit位代表的是TP-Flag,当前SOME/IP消息是一个某个数据段 (就是Payload被拆白的情况下,分为多个数据段发送) 时,TP-Flag被设置为1。

REQUEST (Message Type为0x00) 消息的某个TP segment,其Message Type为0x20,REQUEST_NO_RESPONSE (Message Type为0x21) 消息的某个TP segment,其Message Type 为0x21。

4.1.2.8 Return Code [8 Bit]

[PRS_SOMEIP_00058] Return Code被用于标识一个REQUEST消息是否被SOME/IP的服务端成功处理。为了简化SOME/IP Header的结构(不想让REQUEST和RESPONSE消息Header 格式不一样,个人理解),每一个SOME/IP消息的Header中都包含了Reture Code字段。Returen Code字段可选取的值如下:

[PRS_SOMEIP_00757] Return Codes

Message TypeAllowed Return Code
REQUESTREQUEST消息类型的报文中的Return Code字段不需要设置,固定位 0x00
REQUEST_NO_RETURNREQUEST_NO_RETURN消息类型的报文中的Return Code字段不需要设置,固定位 0x00
NOTIFICATIONNOTIFICATION消息类型的报文中的Return Code字段不需要设置,固定位 0x00
ESPONSEReturn Codes 参考[PRS_SOMEIP_00191] (4.6.2.1章节中) ,其中包括了具体的错误原因
ERRORReturn Codes 参考[PRS_SOMEIP_00191],并且不能设置为 0x00 (E_OK)

4.1.2.9 Payload [variable size]

Payload字段中存储要传输的具体业务参数,后面的章节会描述如何对要放入Payload中的具体各个参数做序列化操作。

SOME/IP的payload的大小取决于使用的传输层协议。对于UDP传输层协议,Payload的大小应该限制在1400字节。而TCP传输层协议自带对数据的分段功能,因此天然支持更大的Payload传输。

Payload由事件(event)的data数据成员或者方法(method)的参数组成。

4.1.3 Endianess

[PRS_SOMEIP_00368] 所有 SOME/IP Header内的字段(field)都需要按照网络字节序(大端字节序)进行编码。

[PRS_SOMEIP_00759] SOME/IP消息的payload中的下列字段需要按照大端字节序编码。

  • 结构体成员变量的长度信息需要按照大端字节序编码,长度字段的大小为8,16或者32bit,插入在结构体成员内容之前。

  • TLV Flag,结构化数据类型的长度,以及可选成员的参数的长度,这些都是需要按照大端字节序进行编码的。

  • 固定长度字符串的长度需要按照大端字节序进行编码。

  • 动态长度字符串的长度需要按照大端字节序进行编码。

  • 可拓展固定长度数组的长度字段需要按照大端字节序进行编码。

  • union类型成员的长度字段需要按照大端字节序进行编码。

    [PRS_SOMEIP_00369] Payload中的参数的字节序应当由配置来定义。一个例外就是TLV (在[PRS_SOMEIP_00202] and [PRS_SOMEIP_00203]中定义),它的字节序需要根据 [PRS_SOMEIP_00204][PRS_SOMEIP_00759] 来决定。

4.1.4 Serialization of Data Structures

序列化操作基于接口规范定义的参数列表,结构规范定义了PDU中所有数据成员的确切位置,并且这个位置是需要考虑内存对齐的。

内存对齐通过插入对齐元素在数据成员的后面来确保该成员后面的数据成员的起始地址是符合对齐系数的。

处理器的架构在访问数据成员的时候,如果该数据成员的起始地址是对齐系数的整数倍,那么处理器访问该数据成员的效率会比较高。(例如,对齐系数为32bit)

[PRS_SOMEIP_00611] 只要数据成员不是可序列化数据对象中的最后一个成员,那么就应当考虑在该数据成员的后面插入对齐元素用来实现后一个数据成员起始地址的内存对齐。(RS_SOMEIP_00028, RS_SOMEIP_00029)

Note:

需要注意的是对齐元素的值还没有定义(可以自行定义)。

[PRS_SOMEIP_00569] 内存对齐应当从SOME/IP报文的消息起始地址进行处理。 (RS_SOMEIP_00028, RS_SOMEIP_00029)

[PRS_SOMEIP_00612] 在固定长度数据元素的后面不需要有对齐元素。(RS_SOMEIP_00028, RS_SOMEIP_00029)

Note:

如果固定长度数据元素背后的数据需要填充,则必须在数据类型定义中明确考虑这一点。(RS_SOMEIP_00028, RS_SOMEIP_00029)

4.1.4.1 Basic Datatypes

[PRS_SOMEIP_00065] 支持的基础数据类型

(RS_SOMEIP_00030, RS_SOMEIP_00031, RS_SOMEIP_00032)

每个参数的字节序由配置决定。

[PRS_SOMEIP_00615] 对于boolean类型的值,只使用期最低位bit的值,其他bit位不使用。(RS_SOMEIP_00030, RS_SOMEIP_-00031, RS_SOMEIP_00032)

4.1.4.2 Structured Datatypes (structs)

结构体的序列化应当接近内存布局,这意味着,结构体中的参数成员需要按照顺序被序列化到缓存中。对于结构体对象的序列化还需要考虑正确的内存对齐。

[PRS_SOMEIP_00077] SOME/IP的实现应当不要去处理插入对齐数据这样的内存对齐工作。 (RS_SOMEIP_00033)

[PRS_SOMEIP_00079] 在结构体对象的前面会插入一个长度字段,这个长度字段占用8,16或者32bit。(RS_SOMEIP_00033, RS_SOMEIP_00040)

[PRS_SOMEIP_00370] 长度字段描述了该结构体在SOME/IP传输时占用的字节数。(RS_SOMEIP_00033, RS_SOMEIP_00040)

[PRS_SOMEIP_00371] 如果收到的Payload中的结构体的长度大于结构体的长度字段所定义的长度,接收方应该只处理长度字段所定义的长度,跳过剩余的字节。(RS_SOMEIP_00033)

[PRS_SOMEIP_00712] 结构体的序列化应当遵循深度遍历的规则来遍历所有的成员。(RS_SOMEIP_00028, RS_SOMEIP_00033)

4.1.4.3 Structured Datatypes and Arguments with Identifier and optional members (’TLV’)

为了实现兼容性,在结构体数据成员的前面可以额外增加Data ID。接收方根据这个Data ID可以忽略掉位置的成员(例如结构体版本升级后新增了成员)。有了Data ID,结构体中新增加的数据成员可以按插在结构体中的任意位置(因为解析的时候首先解析Data ID和长度,对于位置的Data ID,则跳过后面的长度的字节数读取下一个数据成员就可以了)。

此外,Data ID可以让结构体或者方法的参数中存在可选数据成员/可选参数。一个结构体的成员/函数参数是否可选是可以在结构体数据结构/函数定义中定义的。

一个可选的结构体成员/函数参数是否存在,需要再运行时判断,这个取决于使用的编程语言 (例如使用空指针)。

[PRS_SOMEIP_00201] 在结构体中的每个数据成员拥有唯一的Data ID。 (RS_SOMEIP_00050)

Note:

不同结构体中Data ID可以重复,就是一个Data ID可以出现在多个结构体(不同的函数的参数)中

Note:

需要注意的是目前AutoSAR方法论, AutoSAR CP RTE, AutoSAR AP ara::com都不支持可选数据成员或者参数。

[所以4.1.4.3剩下的章节就先不翻译了,因为TLV不太用的上的]

4.1.4.4 Strings

下面的描述对于固定长度字符串和可变长度长度字符串都是通用的。

[PRS_SOMEIP_00372] 支持UTF08,UTF-16BE和UTF-16LE这几种字符集编码。 (RS_SOMEIP_00038)

[PRS_SOMEIP_00948] UTF-8字符串应当以 '\0' 字符结尾,也就是字符串的最后一个字节是 0x00。 (RS_SOMEIP_00038)

[PRS_SOMEIP_00084] UTF-16LE和UTF-16BE字符串当以 '\0' 字符结尾,也就是字符串的最后两个字节是 0x00。 (RS_SOMEIP_00038)

[PRS_SOMEIP_00085] UTF-16LE和UTF-16BE字符串的长度应该是偶数的。 (RS_SOMEIP_00038)

[PRS_SOMEIP_00086] UTF-16LE和UTF-16BE字符串的长度如果是奇数的情况,字符串的最后一个字节可以忽略。 (RS_SOMEIP_00038)

[PRS_SOMEIP_00087] 字符串应当以一个BOM (Byte Order Mark)标记开始,对于UTF-8字符串,BOM的长度是3字节,UTF-16的情况BOM长度是2字节。 (RS_SOMEIP_00038),BOM放在数组的开始位置,后面就是字符串内容。BOM应当包含在固定长度字符串和可变长度长度字符串中,通过BMO可以知道字符串的编码。 (RS_SOMEIP_00038)

4.1.4.4.1 Strings (fixed length)

[PRS_SOMEIP_00760] 固定长度字符串前面的长度字段是可选的。(因为接收方明确知道字符串的长度和编码) (RS_SOMEIP_00038)

[PRS_SOMEIP_00373] 尽管是固定长度,但是字符串还是需要以 '\0' 字符结尾。(RS_SOMEIP_00038)

[PRS_SOMEIP_00374] 固定长度字符串的长度(包括最后的 '\0' 字符)需要在数据类型中指定。(RS_SOMEIP_00038)

[PRS_SOMEIP_00911] 如果字符串的实际长度大于数据类型中定义的长度,反序列化操作应当被终止,消息应当被视为格式错误。(RS_SOMEIP_00038)

[PRS_SOMEIP_00912] 如果字符串的实际长度小于数据类型中定义的长度,但是是以 '\0' 字符结尾的,那么还是应当被处理的。(RS_SOMEIP_00038)

[PRS_SOMEIP_00913] 如果字符串的实际长度小于数据类型中定义的长度,并且在长度范围内没有以 '\0' 字符结尾,反序列化操作应当被终止,消息应当被视为格式错误。(RS_SOMEIP_00038)

与通过BMO和'\0' 字符结尾的方式传输SOME/IP字符串的方式相比,还有一种方式可以用于传输动态长度字符串,这种方式不需要BMO和'\0' 字符结尾(参见 4.1.4.5.2 章节)。请注意这需要SOME/IP应用程序自己完整地处理字符串(例如大小端转换)。

4.1.4.4.2 Strings (dynamic length)

[PRS_SOMEIP_00089] 动态长度字符串必须以长度字段开始,长度的单位为字节。(RS_SOMEIP_00039)

[PRS_SOMEIP_00090] 字符串长度字段需要放置在BOM之前,并且BOM的长度也计算在字符串长度内 (也就是长度字段中的值 = BOM长度 + 字符串内容的长度)。(RS_SOMEIP_00039)

[PRS_SOMEIP_00091] 字符串需要以 '\0' 结尾。(RS_SOMEIP_00039)

Note:

动态长度字符串成员的最大长度需要在数据类型中定义。

[PRS_SOMEIP_00092] [PRS_SOMEIP_00084], [PRS_SOMEIP_00085] 和 [PRS_SOMEIP_00086] 对于动态长度字符串都是也是适用的。(RS_SOMEIP_00039)

[PRS_SOMEIP_00093] 动态长度字符串的长度字段的长度可能会是8,16和32bit,这个是可以配置的。(RS_SOMEIP_00039)

[PRS_SOMEIP_00094] 接上面一条,如果没有配置,默认的长度字段的长度是32bit。(RS_SOMEIP_00039,RS_SOMEIP_00040)

[PRS_SOMEIP_00095] 动态长度字符串的长度字段的大小不计算在动态长度字符串的长度(长度字段不计入自己的大小)。(RS_SOMEIP_00039)

[PRS_SOMEIP_00914] 如果动态长度字符串的实际内容长度大于预期 (根据数据类型中的定义),反序列化操作应当被终止,消息应当被视为格式错误。(RS_SOMEIP_00039)

4.1.4.5 Arrays
4.1.4.5.1 Arrays (fixed length)

固定长度数组在小型设备中比较实用,动态长度数组可能会在ECU上消耗更多的资源。

[PRS_SOMEIP_00944] 固定长度数组以一个可选的长度字段开始。(RS_SOMEIP_00036)

[PRS_SOMEIP_00917] 如果收到Payload中固定长度数组对象的长度比定义的大(例如Method接口定义了传一个8字节长度的数组,实际收到的REQUEST报文的Payload中,数组对象的长度有10个字节),那么只接收定义的长度的数组元素,剩下的数组中的内容全部忽视。(RS_SOMEIP_00036)

[PRS_SOMEIP_00918] 如果收到Payload中固定长度数组对象的长度比定义的小,并且丢失的部分对于数据接收方来说是不可替代的,反序列化操作应当被终止,消息应当被视为格式错误。(RS_SOMEIP_00036)

Note: 只有提供了长度字段,才可以检测固定长度数组是否发生溢出.

One-dimensional

[PRS_SOMEIP_00099] 固定长度 "n" 的一维数组应当精确的包含 "n" 个相同类型的元素。可选的长度字段在第一个数组元素之前。([PRS_SOMEIP_00944] ) (RS_SOMEIP_00035, RS_SOMEIP_00036)

Note: 如果长度字段被定义了,那么这个一维数组在总线上的表现形式是一个长度字段和后面相同数据类型的n个数据元素的组合。

Multidimensional

[PRS_SOMEIP_00101] 多维数组的序列化遵循C++语言中多维数组的内存布局 (row-major order 以行为主序 )。(RS_SOMEIP_00028, RS_SOMEIP_00035, RS_SOMEIP_00036)

Note: 如果长度字段被定义了,那么这个多维数组在总线上的表现形式是一个长度字段后后面 n个集合,每个集合又包含了一个长度字段和m个相同类型的元素。

4.1.4.5.2 Dynamic Length Arrays

[PRS_SOMEIP_00375] 动态长度数组的内存布局应当是基于静态长度数组的。(RS_SOMEIP_00037)

[PRS_SOMEIP_00376] 在动态长度数组的最开始应当有一个长度字段用于标识这个动态数组的长度(以字节为单位) (RS_SOMEIP_00037)

[PRS_SOMEIP_00107] 动态长度数组的长度字段是8,16和32Bit,取决于配置。 (RS_SOMEIP_00037)

[PRS_SOMEIP_00377] 动态长度数组的长度字段内的数组长度值不包括长度字段本身。 (RS_SOMEIP_00037)

Note:

如果长度字段内的长度值为0,则字段后面跟着的就是一个固定长度数组。

动态长度数组的布局图如下面两张(4.13和4.14)

图 4.13: 一维数组(动态长度)

一维数组只使用一个长度字段,长度字段中保存了整个数组所有元素的大小。

数组中元素的数量可以使用长度字段中的值除以每个元素的大小来获取。

如果动态数组中各个元素的长度不是固定的,那会导致无法直接计算总的元素数量,但是还是必须按照顺序解析每一个元素。

图4.14 展示了多维数组的布局结构

[PRS_SOMEIP_00114] 多维数组中每个子数组都有一个自己的长度字段。(RS_SOMEIP_00037)

如果需要使用静态缓冲区来分配数组的空间,那么数组的数据类型的定义需要定义每个维度的子数组的最大长度。

理由:在以字节为单位测量长度时,可以在反序列化过程中跳过复杂的多维数组。

SOME/IP同样支持不同列有不同的长度以及不同的行有不同的元素数量。在图4.14中 k_1和 k_2 就展示了这个特点,两个同维度的子数组的元素数量是不同的。每个动态长度数组的前面都需要带一个长度字段,无论对于外部数据还是内部子数组。

[PRS_SOMEIP_00919] 如果数组的实际长度大于数据类型中定义的该数组的长度,那么应当只读取定义的长度中字节数内容,忽略剩下字节数的内容。(RS_SOMEIP_00037)

[PRS_SOMEIP_00945] 如果没有配置长度字段的长度的话,默认长度字段的长度是32bit。(RS_SOMEIP_00037,RS_SOMEIP_00040)

4.1.4.6 Enumeration

[PRS_SOMEIP_00705] SOME/IP目前不支持枚举类型,枚举类型应当被当做无符号整数来处理。

4.1.4.7 Bitfield

[PRS_SOMEIP_00300] 位域类型被当做uint8/uint16/uint32/uint64类型无符号证书来处理。(RS_SOMEIP_00033, RS_SOMEIP_00030)

数据类型定义应当定义位域中每个比特的含义和值说明。

4.1.4.8 Union / Variant

在某些应用场景下,需要将数据定义为联合类型(union),这样在在网络传输中可以在相同的负载中传输更多不同的数据类型。

联合类型 (也称为variant) 内部可以容纳不同数据类型的数据,例如一个联合类型定义了一个uint8类型和uint16类型,那么这个联合类型的变量能够携带一个uint8类型的数据值,也可以携带一个uint16类型的数据值。

具体联合类型中传输的是什么类型的值取决于运行时,在这种情况下,不仅需要传输数据本身,还需要以 "元数据" 的方式将实际的数据类型添加上去。

通过添加 “元数据” 的方式,发送端可以表示发送的联合数据中的数据类型,让接收端可以正确地解析。

[PRS_SOMEIP_00118] 应当使用联合类型来发送带有不同数据类型的数据。(RS_SOMEIP_00034)

[PRS_SOMEIP_00119] Union联合类型(长度字段,类型信息和实际数据值)

[PRS_SOMEIP_00126] 长度字段的值只对应数据的大小,不包括长度字段和类型信息的大小。(RS_SOMEIP_00034)

Note: 根据联合类型的数据在序列化的数据流中的位置需要按照配置做内存对齐操作。

[PRS_SOMEIP_00121] 长度字段的大小根据配置可以是32,16,8或者0bit。(RS_SOMEIP_00034)

[PRS_SOMEIP_00122] 长度字段为0的情况就说明PDU中该联合类型没有长度字段。(RS_SOMEIP_00034)

[PRS_SOMEIP_00123] 长度字段为0的情况下,该联合类型中所有的类型应当都是相同的大小。(RS_SOMEIP_00034)

[PRS_SOMEIP_00129] 数据类型字段指明了当前联合类型数据中存放的数据的实际类型。(RS_SOMEIP_00034)

[PRS_SOMEIP_00127] 类型字段的长度应当是32,16,8bit。(RS_SOMEIP_00034)

[PRS_SOMEIP_00906] 每个联合类型中,类型字段的值的含义不同,根据业务配置定义。(RS_SOMEIP_00034)

[PRS_SOMEIP_00907] 类型字段的0值是为NULL类型预留的。(RS_SOMEIP_00024,RS_SOMEIP_00034)

Note:

[PRS_SOMEIP_00908] 联合类型中是否允许包含NULL值取决于配置。(RS_SOMEIP_00034)

[PRS_SOMEIP_00130] 联合类型的序列化的方式取决于类型字段中的类型。(RS_SOMEIP_00028,RS_SOMEIP_00034)

在下面的例子中,联合类型的长度是32bit,该联合类型支持一个uint8和一个uint16数据。按照32bit边界对齐。

当该联合类型的类型值为1 (uint8类型) 时,按照表格4.9进行序列化:

当该联合类型的类型值为2 (uint16类型) 时,按照表格4.10进行序列化:

[PRS_SOMEIP_00915] 不能超过联合类型对象中类型字段定义的类型的长度读取额外的字节 (例如类型字段中为uint16,那么只能在类型字段后面读取2个字节座位该联合类型对象的值),多余的字节应当被忽略。(RS_SOMEIP_00034)

4.2 Specification of SOME/IP Protocol

该章节描述了SOME/IP的远程过程调用 (RPC),事件通知 (Event Notifications) 和错误处理 (Error Handling)。

4.2.1 Transport Protocol Bindings

可以用于传输SOME/IP消息的传输层协议有多重,SOME/IP目前支持 UDPTCP 两种。这两种传输层绑定方式在后面的章节说明,并且第 6 章节为讨论如何选取合适的传输层协议。

[PRS_SOMEIP_00138] 如果服务端运行同一个服务的多个实例,那么不同实例的消息在服务端会被映射到传输层的不同端口上(个人理解就是一个SOME/IP 服务实例占用一个传输层端口)。 (RS_SOMEIP_00015)

更多的细节在 4.2.1.3 章节。

[PRS_SOMEIP_00535] SOME/IP所绑定的传输层应当支持传输多包 SOME/IP消息 (例如 UDP packet或者 TCP segment)。(RS_SOMEIP_00010)

[PRS_SOMEIP_00142] 接收SOME/IP消息的代码实现应当要能处理未对齐的通过TCP/UDP传输过来的SOME/IP消息。(RS_SOMEIP_00010)

理由:

当通过TCP/UDP传输多包SOME/IP消息时,只有在其中每一个SOME/IP消息都是对齐系数的倍数时,才能保证整个传输负载是对齐的。

[PRS_SOMEIP_00140] 由于存在SOME/IP的Header,因此在实际传输过程中,可以通过SOME/IP的Header完整的分割每一包SOME/IP消息。通过SOME/IP Header中的长度字段可以找到当前SOME/IP消息的结尾。根据数据包的长度字段,SOME/IP可以判断数据包是否还有更多的SOME/IP消息,这对于TCP和UDP都是适用的。(RS_SOMEIP_00010)

[PRS_SOMEIP_00141] 每个SOME/IP消息的负载都有它配对的SOME/IP Header。(RS_SOMEIP_00010, RS_SOMEIP_00027)

[PRS_SOMEIP_00940] 每一个SOME/IP的服务实例都可以通过下面的设置来建立它所有的方法,时间和通知的对外通信功能:

  • 最多一个TCP连接

  • 最多一个UDP单播连接

  • 最多一个UDP组播连接

    (RS_SOMEIP_00010, RS_SOMEIP_00027)

4.2.1.1 UDP Binding

[PRS_SOMEIP_00139] 在SOME/IP绑定UDP传输层时,SOME/IP的消息传输的实现依赖UDP数据包 (packet)。 (RS_SOMEIP_00010)

[PRS_SOMEIP_00137] SOME/IP协议不应当限制UDP的分片(fragment)【由于收到链路层MTU的限制,无论TCP还是UDP,当传输的数据大于MTU - IP Header - TCP/UDP Header的时候,都会面临分片发送的处理】。 (RS_SOMEIP_00010)

[PRS_SOMEIP_00943] 每个SOME/IP 服务-实例(Service-Instance)的客户端使用一个UDP单播连接服务端进行方法(method),事件(event)和通知(notification)的通信 (需要配置该服务实例使用UDP通信)。 (RS_SOMEIP_00010)

[PRS_SOMEIP_00942] 每个SOME/IP 服务-实例(Service-Instance)的客户端通过一个UDP组播地址和服务端进行通信。 (RS_SOMEIP_00010)

4.2.1.2 TCP Binding

相对于UDP 绑定方式,TCP的开销比较重。使用TCP可以传输更大的SOME/IP消息并且使用TCP的可靠性特性(丢失重传,重新排序等)。

为了降低传输延时,Nagle算法会被关闭(TCP_NODELAY)。

[PRS_SOMEIP_00706] 当TCP连接断开时,未完成的SOME/IP消息发送应当被当做超时来处理。(RS_SOMEIP_00010)

[PRS_SOMEIP_00707] SOME/IP的客户端和服务端使用单独的TCP连接处理每个服务-实例(Service-Instance)的方法,事件和通知 (需要配置该服务实例使用TCP通信)。(RS_SOMEIP_00010)

[PRS_SOMEIP_00708] 基于TCP连接的SOME/IP的服务实例,TCP连接应当由该服务实例的客户端发起,这个发起的时机点在客户端首次调用该服务实例的方法 (method) 或者客户端尝试从服务端获取该服务-实例的通知 (notification) 的时候。(RS_SOMEIP_00010)

SOME/IP的客户端程序需要再TCP 连接断开/失败的时候尝试重新连接。

[PRS_SOMEIP_00709] TCP连接的断开应当由SOME/IP的客户端发起,当SOME/IP的客户端和该连接另一端的SOME/IP Service-Instance没有实际通信需求的时候即可断开连接。(RS_SOMEIP_00010)

[PRS_SOMEIP_00710] 当所请求的SOME/IP的Service-Instance不在可用 (avaliable) 状态的时候,SOME/IP的客户端应当主动断开TCP连接。(RS_SOMEIP_00010)

[PRS_SOMEIP_00711] SOME/IP的Server端在停止所有Service的时候不应当断开TCP连接,而是应该留给客户端足够的时间去处理已经在TCP连接上传输的数据并且让客户端自己关闭TCP连接。(RS_SOMEIP_00010)

使用Magic Cookie与TCP流重新同步

[PRS_SOMEIP_00154] 为了让测试工具能够识别依赖TCP传输的SOME/IP消息的便捷,SOME/IP magic cookie消息会被定期插入SOME/IP消息的中间。(RS_SOMEIP_00010)

[PRS_SOMEIP_00160] Magic Cookie消息的布局应当有如下字段组成:

  • 对于从客户端发送SOME/IP消息到服务端的TCP通信

    • Message ID (Service ID/Method ID): 0xFFFF 0000

    • Length: 0x0000 0008

    • Request ID (Client ID/Session ID): 0xDEAD BEEF

    • Protocol Version: 0x01

    • Interface Version: 0x01

    • Message Type: 0x01

    • Return Code: 0x00

  • 对于从服务端发送SOME/IP消息到客户端的TCP通信

    • Message ID (Service ID/Method ID): 0xFFFF 8000

    • Length: 0x0000 0008

    • Request ID (Client ID/Session ID): 0xDEAD BEEF

    • Protocol Version: 0x01

    • Interface Version: 0x01

    • Message Type: 0x02

    • Return Code: 0x00

(RS_SOMEIP_00010)

Magic Cookie消息的布局如下图 4.15

4.2.1.3 Multiple Service-Instances

[PRS_SOMEIP_00162] 相同SOME/IP 服务 (Service) 的服务-实例 (Service-Instance) 应当使用不同的实例ID (instance ID)来区分。同一个ECU上有同一个服务的不同实例或者不同ECU上有同一个服务的不同实例都是支持的。(RS_SOMEIP_00015)

[PRS_SOMEIP_00163] 当不同的SOME/IP服务的不同服务实例在同一个ECU上被提供时,这些服务实例可以共用相同的传输层端口。当一个ECU上发布同一个SOME/IP服务的不同服务实例时,这些服务实例的提供进程必须使用不同的端口来发布实例。当一个ECU上有多个进程使用/消费了同一个SOME/IP服务的不同实例时,这些进程可以使用相同的端口来和该SOME/IP服务的不同实例进行通信。(RS_SOMEIP_00015)

理由: 普通的SOME/IP (不是SOME/IP-SD) 消息在SOME/IP的Header字段没有Service-Instance ID字段,因此,端口号被用于区分一个ECU上同一个SOME/IP Service的不同Instance。一个SOME/IP服务实例依靠Service ID和通信终结点的信息(传输协议/IP地址和端口)来表示标识,无论对于SOME/IP服务的客户端还是服务端,针对同一个SOME/IP Service的不同实例使用不同的端口号,这种方式是足够有效的,因为四元组<src IP, src port, dst IP, dst Port>就是一个足够可用的区分标志。服务端是实际发布各个SOME/IP 服务实例的消息的,因此这个区分的操作应当发生在服务端 => 服务端使用不同的端口提供同一个SOME/IP服务的不同实例。

建议: 对于具体某个SOME/IP的服务的实例来说,建议在配置通信终结点的时候,其TCP的终结点配置和UDP的中间点配置使用相同的端口。如果一个SOME/IP服务的实例使用UDP 端口 x,那么该SOME/IP服务的其他实例以及其他SOME/IP的服务的实例都不能使用TCP 端口 x。

4.2.1.4 Transporting large SOME/IP messages of UDP (SOME/IP-TP)

UDP绑定的传输方式只适合那种SOME/IP消息大小能够合适放入一个IP Packet中的情况,如果一个尺寸较大的SOME/IP消息 (例如 32Kb) 想通过UDP的方式传输,,那么需要使用到SOME/IP Transport procotol(SOME/IP-TP)。对于这些尺寸较大的并且需要通过UDP 传输层传输的SOME/IP消息被称为"original SOME/IP message" (原始SOME/IP消息),原始SOME/IP消息(original SOME/IP message)的片段(piece)被称为 "segments" 片段。

只有在需要传输较大的数据 ( > 1400字节 ) 并且不存在硬性延迟性指标要求的时候才适合使用TCP传世SOME/IP消息。

[PRS_SOMEIP_00720] SOME/IP消息使用SOME/IP-TP的前提是需要激活会话 (Session) 处理(每一个原始SOME/IP消息的Session ID必须是唯一的)。(RS_SOMEIP_00010,RS_SOMEIP_00012)

[PRS_SOMEIP_00721] 所有SOME/IP-TP消息都需要带上原始SOME/IP消息的Session ID字段,因此,这些SOME/IP的消息片段都有相同的Session ID。(RS_SOMEIP_00010,RS_SOMEIP_00012)

[PRS_SOMEIP_00722] SOME/IP-TP 片段(segment) 需要在SOME/IP的Header中设置TP-Flag为1。(RS_SOMEIP_00010,RS_SOMEIP_00011)

[PRS_SOMEIP_00723] SOME/IP-TP 片段(segment) 需要在SOME/IP的Header后面追加TP Header,TP Header的结构如下:

  • Offset [28 bits]

  • Reserved Flag [1 bit]

  • Reserved Flag [1 bit]

  • Reserved Flag [1 bit]

  • More Segments Flag [1 bit]

    (RS_SOMEIP_00010,RS_SOMEIP_00027)

SOME/IP-TP的Header的结构如下图 4.16

[PRS_SOMEIP_00931] SOME/IP-TP消息的消息Header部分应当使用网络字节序 (大端字节序) 进行编码。(RS_SOMEIP_00027)

[PRS_SOMEIP_00724] Offset偏移字段传输的是一个32字节证书的高28位,低思维固定为0。(RS_SOMEIP_00010, RS_- SOMEIP_00027)

Note:

        这意味着offset偏移字段的值是16的整数倍。

[PRS_SOMEIP_00725] SOME/IP-TP消息的Header中的Offset字段应当被设置为该SOME/IP-TP的payload在其原始SOME/IP消息的Payload中的偏移位置。(RS_SOMEIP_00010, RS_SOMEIP_00027)

[PRS_SOMEIP_00726] Reserved Flag(保留标志)应当设置为0,TP消息的发送段和接收端都不需要处理该标志。(RS_SOMEIP_00010, RS_SOMEIP_- 00027)

[PRS_SOMEIP_00727] More(更多TP Segment标记)在原始SOME/IP消息的所有SOME/IP-TP消息(除了最后一包SOME/IP-TP消息)中应当被设置为1,最后一包SOME/IP-TP消息中的More标志应当被设置为0。(RS_SOMEIP_00010, RS_SOMEIP_00027)

[PRS_SOMEIP_00728] SOME/IP消息的长度的用法和之前一样,表示的是从SOME/IP Header中长度字段后面的8个字节的内容(protocol version + interface version + messagetype + return code) ,SOME/IP-TP的Header部分 4个字节 (Offset + reserved + More flag)和后面SOME/IP-TP Segment的Payload部分的长度。

[PRS_SOMEIP_00729] SOME/IP-TP segment消息的offset字段的长度值是考虑了对齐处理的,因此,原始SOME/IP消息的所有TP Segment消息,除了最后一帧TP Segment消息,剩余的TP Segment消息的长度都是16的整数倍。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00730] SOME/IP-TP segment消息的最大长度【基于UDP传输的SOME/IP消息的长度限制是1400字节,去除UDP消息头的8个字节,因此segment消息的最大长度是1392字节】 。(RS_SOMEIP_00010, RS_SOMEIP_00029, RS_SOMEIP_00051)

[PRS_SOMEIP_00731] 同一个原始SOME/IP消息的所有SOME/IP-TP 消息都有相同的Message ID (Service ID/Method ID),Request ID (Client ID / Session ID),Protocol Version,Interface Version和Return Code,并且这些字段的值和原始SOME/IP消息中的一致。

SOME/IP-TP消息范例:

        下面这个范例阐述了一个payload长度为5880字节大小的原始SOME/IP消息是如何传输的,该原始SOME/IP消息的Header中长度字段的值是5880 + 8(SOME/IP Header长度字段后面的内容的长度)。

        原始SOME/IP消息会被分段为5个连续的SOME/IP段(segment),每一个段的payload含有1392字节。

        对于这些SOME/IP消息段,SOME/IP TP模块会添加额外的TP字段(下图中标红色的部分),SOME/IP消息的长度字段中的长度值包括了 Request IDProtocol VersionInterface VersionMessage TypeReturn Code这几个字段的长度(总共8个字节),另外由于带上了4个字节的TP字段,因此SOME/IP消息的长度字段中的长度值还要再加上4字节 (额外的SOME/IP TP字段)。

        下图上面这个SOME/IP原始消息分段后每个TP Segment的Header段的信息:

         

        注意:

        TP Header中的Offset字段的值是以16字节偏移为单位的,偏移值87代表的是当前TP-Segment中的payload在原始SOME/IP消息中的payload的偏移是1392字节 (87*16)。

        SOME/IP-TP segment消息的SOME/IP Header部分的详细情况如下图:

  • 前面4个SOME/IP-TP segment消息中,TP Header的More标志设置为1

        最后一个SOME/IP-TP segment消息中,TP Header中的More标志设置为0,同时其Payload中保存的是原始SOME/IP消息中的最后312个字节。

SOME/IP-TP消息发送方的约束:

[PRS_SOMEIP_00732] 是否对SOME/IP进行分片 (segment) 取决于用户配置。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00733] 一个原始SOME/IP消息的segment消息应当按照顺序进行发送。(RS_- SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00734] 所有TP Header中More 标记1的segment消息的大小应该一致。(RS_SOMEIP_00010, RS_- SOMEIP_00051)

[PRS_SOMEIP_00735] 发送方应该按照该SOME/IP协议规范所支持的最大的TP消息大小对原始SOME/IP的payload进行分段(segment)。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00736] 发送方不要重复发送相同的TP segment。(RS_SOMEIP_00010, RS_SOMEIP_00051)

SOME/IP-TP消息接收方的约束:

[PRS_SOMEIP_00738] SOME/IP消息的接收方应当根据根据Message ID,Protocol Version,Interface Version和Message Type(其中有TP Flag)来匹配并且重组收到的TP Segment消息。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00740] SOME/IP消息的接收方应当要能够并行支持处理并且重组不同的发送端(Sender IP, Sender port或Client ID不同)发送的相同Message ID的多包SOME/IP消息。

[PRS_SOMEIP_00741] TP Segment中的SessionID是用来下一个等待组装的原始SOME/IP消息的标志。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00742] TP Segment的接收方收到和上一包原始SOME/IP消息中Session ID不同的SOME/IP-TP消息时,就可以重新开始组装下一包SOME/IP消息了。(之前组装到一半的上一包原始SOME/IP消息就可以停止,之前收到的SOME/IP-TP segment就可以扔掉了)。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00743] 如果配置了组装缓存区的大小,那么接收方只能组装缓存区中已经收到的TP Segment,收到超过缓存区大小的TP segment内容要被忽略。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00744] 只有所有TP Segment都被正确组装完成的原始SOME/IP消息才能被回传给应用程序处理。(RS_SOMEIP_00010, RS_SOMEIP_00051)

Note:

这意味着必须确保SOME/IP消息的所有字节都是被正确接收并且组装的。计算非重叠字节数并且与总长度进行比较,可以作为一种有效的检查方法。

[PRS_SOMEIP_00745] 用于重组的最后一个TP Segment的返回码应用于重组的消息。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00746] 接收端收到通过组装TP Segment还原回原始SOME/IP消息时,应当将MessageType中的TP Flag进行调整并且设置为0。(RS_SOMEIP_00010, RS_SOMEIP_00051)

[PRS_SOMEIP_00747] 无论TP Segment的发送端按照升序或者降序的方式发送TP Segment,接收端应当都能支持进行组装。(RS_SOMEIP_00010, RS_SOMEIP_0051)

[PRS_SOMEIP_00749] 当接收端组装TP Segment消息时如果发现缺少了某个Segment,那么当前的原始SOME/IP消息组装动作应当立刻取消。(RS_SOMEIP_00010, RS_SOMEIP_0051)

[PRS_SOMEIP_00750] 不支持使用同一个组装缓冲区同时处理两个不同的分段消息(例如,仅Session ID和Payload不同)。 (RS_SOMEIP_00010, RS_SOMEIP_0051)

注意:

这可以防止当某些TP Segment被重新排序时,具有相同MessageID、IP地址、端口号和传输协议的相同事件消息以错误的顺序到达。

[PRS_SOMEIP_00751] 不需要对两个完全不同的原始SOME/IP消息的TP Segment进行重新排序,因为这些TP Segment属于不同的重组缓冲区。(RS_SOMEIP_00010, RS_SOMEIP_0051)

[PRS_SOMEIP_00752] 接收端应当基于原始SOME/IP消息的最后一包TP Segment后,通过覆盖的方式正确地重新组装重复或者重叠的TP Segments。 (RS_SOMEIP_00010, RS_SOMEIP_0051)

[PRS_SOMEIP_00753] 如果重复或者重叠的TP Segment已经写入重组缓冲区,那么消息接收端应该取消该TP Segment对应原始SOME/IP消息的重组。这个特性应该通过配置来开关。(RS_SOMEIP_00010, RS_SOMEIP_0051)

[PRS_SOMEIP_00754] 接收端应当能检测并且处理明显的错误,例如收到的TP 消息中Header的长度字段的值不是16的整数倍,则应当取消该TP消息对应原始SOME/IP消息的重组。(RS_SOMEIP_00010, RS_SOMEIP_0051)

4.2.2 Request/Response Communication

SOME/IP中最常见的通信方式就是Request/Response。SOME/IP的客户端发送Request消息会被SOME/IP的服务端应答。

[PRS_SOMEIP_00920] 对于SOME/IP的Request消息,客户端应用需要对消息的Payload和Header部分做如下处理:

  • 构建消息的Payload部分

  • 根据客户端想要调用的SOME/IP的服务和方法设置Message ID字段

  • 设置Header中的8字节长度字段(值为长度字段后面开始到Payload结束的大小)

  • 设置Header中的Request ID字段,这个字段必须(对于接收消息的客户端来说)是唯一值。

  • 根据[PRS_SOMEIP_00052] 要求设置Protocol Version字段

  • 根据SOME/IP服务的当前接口版本设置Interface Version字段

  • 设置Header中的Message Type字段为REQUEST (0x00)

  • 设置Header中的Return Code字段为0x00

    (RS_SOMEIP_00007)

[PRS_SOMEIP_00921] 为了构建Request消息的Payload部分,Request消息所对应的SOME/IP方法的所有的入参/输入输出参数应当按照方法的函数签名中所定义的顺序被序列化到Payload中。(RS_SOMEIP_00028, RS_SOMEIP_00007)

[PRS_SOMEIP_00922] SOME/IP的服务端基于从Client收到的Request消息构建Response消息的Header部分,完成如下工作:

  • 构建Response消息的Payload部分

  • 从关联的Request消息中提取Message ID字段用在Response消息的Message ID字段上

  • 设置长度字段

  • 从关联的Request消息中替换Request ID字段用在Response消息的Request ID字段上

  • 设置Response消息的Message Type值为RESPONSE (0x80) 或者ERROR (0x81)

  • 根据 [PRS_SOMEIP_00191] 设置Return Code字段

(RS_SOMEIP_00007)

Header中合法的Return Code的字段值参照 表 4.11

[PRS_SOMEIP_00923] 为了构建Response消息的Payload部分,Response消息所对应的SOME/IP方法的输出参数应当按照方法的函数签名中定义的顺序被序列化到Payload中。(RS_SOMEIP_00028, RS_SOMEIP_00007)

[PRS_SOMEIP_00927] SOME/IP的服务端只有在收到Request消息后才可以回复Response消息(必须要等到Request消息中的ReqeuestID)。(RS_SOMEIP_00007)

[PRS_SOMEIP_00928] 当收到服务端发送的Response消息中的Request ID不是当前客户端所发出的,客户端可以忽略该Response消息。(RS_SOMEIP_00007)

4.2.3 Fire&Forget Communication

客户单发送Reqeust消息给服务端,并且不需要服务端回应Response消息,这种通信方式称为Fire & Forget。

[PRS_SOMEIP_00924] 对于没有Response返回的Request消息,客户端需要对消息的Payload和Header部分做如下处理:

  • 构建消息的Payload部分

  • 根据客户端想要调用的SOME/IP的服务和方法设置Message ID字段

  • 设置Header中的8字节长度字段(值为长度字段后面开始到Payload结束的大小)

  • 设置Header中的Request ID字段,这个字段必须(对于接收消息的客户端来说)是唯一值。

  • 根据[PRS_SOMEIP_00052] 要求设置Protocol Version字段

  • 根据SOME/IP服务的当前接口版本设置Interface Version字段

  • 设置Header中的Message Type字段为REQUEST_NO_RETURN (0x01)

  • 设置Header中的Return Code字段为0x00

    (RS_SOMEIP_00006)

[PRS_SOMEIP_00171] Fire & Forget消息不应该返回错误,应用程序需要自己处理错误和返回错误代码。(RS_SOMEIP_00006)

4.2.4 Notification Events

通知这种通信方式描述的是发布订阅模式。通常服务端发布一个服务,而客户端订阅。一个明确的例子是当事件发生或者事件的内容发生变化的时候服务端发送一个事件给客户端。

SOME/IP协议只是用来传输事件的更新值,并不负责发布和订阅机制,发布和订阅机制由SOME/IP-SD协议来实现。

[PRS_SOMEIP_00925] 对于SOME/IP通知 (notification) 消息,服务端需要对消息的Payload和Header部分做如下处理:

  • 构建消息的Payload部分

  • 根据需要发送的Event的MethodID和ServiceID构建消息Header中的Message ID

  • 设置Header中的8字节长度字段(值为长度字段后面开始到Payload结束的大小)

  • 设置Client ID为0x00,根据[PRS_SOMEIP_00932], [PRS_SOMEIP_00933]和 [PRS_SOMEIP_00521] 规则设置Session ID

  • 根据[PRS_SOMEIP_00052] 要求设置Protocol Version字段

  • 根据SOME/IP服务的当前接口版本设置Interface Version字段

  • 设置Header中的Message Type字段为NOTIFICATION (0x02)

  • 设置Header中的Return Code字段为0x00

(RS_SOMEIP_00004)

[PRS_SOMEIP_00926] Notificaiton消息的Payload部分的内容应当由被序列化后event数据组成。(RS_SOMEIP_00004)

[PRS_SOMEIP_00930] 当同一个ECU上多个客户端订阅同一个event的时候,系统应当处理Notification消息的复制(复制给订阅的多个客户端)以节省传输带宽。(RS_SOMEIP_00042)

当使用组播的方式传输Notificaiton通知消息时,系统的复制功能是比较重要的。

4.2.4.1 Strategy for sending notifications

不同的使用场景下,发送通知消息的策略是不一样的,由如下几个常见策略:

  • 周期发送 - 按照固定的频率发送更新的值 (例如每100毫秒发送带有ALIVE标志的安全相关的消息)

  • 更新发送 - 当事件值发生变化时立刻发送 (例如门被打开)

  • 只有当event当前值相比last值变化大于一个比例后才会发送事件当前的更新值。

4.2.5 Fields

Field代表了一种状态,并且有一个有效的值。订阅Field后,会立刻获取该Field的值。

[PRS_SOMEIP_00179] 一个Field字段是由getter,setter和notification event组成的。(RS_SOMEIP_00009)

[PRS_SOMEIP_00180] Field字段至少包含getter,setter和notification event中的某一个或者多个。(RS_SOMEIP_00009)

[PRS_SOMEIP_00181] Field字段的getter方法是一个Request/Response调用,并且Request的Payload部分为空的,Resonse消息的Payload包含Field字段的当前值。(RS_SOMEIP_00009)

[PRS_SOMEIP_00182] Field字段的setter方法是一个Request/Response调用,在Request消息的Payload部分有要设置给Field字段的最新值,Response消息的Payload部分存有Field字段的最新值。(RS_SOMEIP_00009)

Note:

如果Setter的Request报文中payload中的值被Field采用了,那么Setter的Response报文中payload就存有该值。

[PRS_SOMEIP_00909] 当客户端订阅Field中的notifier时,Field的notifier会发送一个event消息给订阅端告知当前Field的值。

[PRS_SOMEIP_00183] Field的notifier应当发送event消息来传输当前Field的值,这个发送规则参照event的发送规则,发送策略包括4.2.4.1中的周期发送,更新发送和阈值发送(Field的值的变化比例超过阈值才发送)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值