编辑推荐: |
本文主要介绍了SOME/IP网络结构示例、SOME/IP基础概念解析、场景示例与SOME/IP信息格式等相关内容。希望对你的学习有帮助。
本文来自于微信公众号乔克普雷特,由火龙果软件Linda编辑,推荐。 |
|
SOME/IP的全称是Service-Oriented Middleware
over IP,它是基于IP通讯的,为面向服务的通讯架构(SOA)而设计的中间件。
1. 参考资料
本篇文章用到的参考资料主要有三个。其中AUTOSAR_PRS_SOMEIPProtocol.pdf【1】和AUTOSAR_PRS_SOMEIPServiceDiscoveryProtocol.pdf【2】可以从AUTOSAR官网下载。第三个是CANoe仿真SOMEIPSimMultimedia,安装CANoe程序后,在Sample
Configuration里可以找到。后续的介绍中,我们将基于该仿真,来逐步解析上述两份协议文档里的新概念。
2. SOME/IP网络结构示例
不管是什么样的通讯方式,它最终都是为了让ECU互相之间能够传递信息。在CAN网络里,CAN Matrix定义了CAN的网络结构;类似地,在SOME/IP里,XML文件定义了它的网络结构。
2.1 XML配置文件
从仿真的Database文件夹里,我们找到了配置文件FBX4_VECTOR_SOME_IP_MM.xml。将其折叠,我们大致可以拿到七个方面的信息。其中,
• Clusters定义了以太网的基本信息,如波特率100M/s、最大数据位长度1500bytes;
• ECUs定义了网络结构里包含的ECU,并给出了每个ECU的基本信息,如IP地址、端口号、SD参数;
• Service Interfaces里定义了网络里可见的服务,并给出了每个服务(Service)具体的信息,如服务的名称、服务的ID、服务里所包含的Methods、Events、Fields、Eventgroups等;
• Datatypes里定义了通用的和自定义的数据类型,比如Uint8、Struct;
• Codings里定义了数据的映射关系,即不同数值所对应的含义,比如1表示start,0表示stop。
2.2 服务表
尽管XML配置文件里的信息非常完备,但理解它并不直观。为此,我们将它转化成了下面这张服务表(这是笔者自己的叫法,非官方)。不难看出,一个交换机连接了四个ECU,分别是:Head
Unit——汽车里的中控、CD Changer——播放CD的卡盒、GPS Unit——车载GPS和TVReceiver——电视节目接收器。
进一步,这四个ECU都标注了NEP和AEP。NEP(Network Endpoint)其实是ECU的IP地址,比如192.168.1.10;而AEP(Application
Endpoint)其实是Socket地址,比如192.168.1.10:30500。
再进一步,每个ECU都声明了自己所提供的服务(Provided Service)以及该服务的ID(Service
ID),比如CD Changer提供名为CD Player的服务,它的ID是10。
最后,每个服务里又包含了子服务,分为Methods、Fields、Events和Eventgroups。其中有些子服务被标记为了x,表示该服务里不提供该子服务(子服务,和x的标记方式也是笔者自己的方法,非官方)。
有了这张服务表,我们便可以清楚地知道谁提供了什么样的服务。在接下来的介绍中,我们需要时不时地回到这张表进行查看。需要注意的是,这其实是一张简化了的服务表,比如Head
Unit并没有提供任何服务。真实的车载网络里肯定要比这个复杂的多的多。
3. SOME/IP基础概念解析
上述服务表里涉及了很多的新概念,接下来我们逐一解释下。
3.1 生产者和消费者
所有的商品都对应着一个制造它的人和消费它的人,类似地,所有的服务都有生产者(Producer)和消费者(Consumer)。有时候我们也把生产者称之为服务端(Server)或者提供者(Provider),把消费者称之为客户端(Client)或者订阅者(Subscriber)。本篇文章里我们统一使用生产者和消费者的说法。对于每个ECU,它的身份并不是固定的。也许在某个服务里,它是生产者,但是在另一个服务里它就变成了消费者。
生产者和消费者的交互方式,可以用以下三种情况来表示。即,
1. 消费者向生产者发出请求(Request),生产者未发出响应(Response);
2. 消费者向生产者发出请求,生产者向消费者发出响应;
3. 生产者主动向消费者发出请求(也可以理解成在没有请求时自发的响应)。
3.2 概念释义
交互的方式有且仅有以上三种,因此,在SOME/IP的官方协议里,方法(Methods)被定义为可被调用的(can
be invoked/called)对象,包含Request和Request/Response两种方式。只不过,Request有一个更高级的名字Fire
and Forget;Request/Response也有一个更高级的名字RPC(Remote Procedure
Call)。而事件(Events)被定义为从生产者向消费者的单向传输。
有时候交互不涉及修改状态(Status),它更像指令,比如Head Unit告诉TVReceiver开启电视信号。但有时候修改状态却是必不可少的,比如Head
Unit告诉CD Changer播放第四首歌曲,这里的第几首歌曲就是一种状态。类似这种涉及状态的交互,在SOME/IP里被称为字段(Fields)。字段与前述交互方式二相结合,就得到了Getter(获取状态),Setter(设置状态);与交互方式三相结合,就得到了Notifier(通知)。
回到官方协议里对服务的定义:服务由若干个方法、若干个事件和若干个字段构成,于是我们可以画出下边这张图。
A
logical combination of zero or more methods,
zero or more events, and zero or more fields.
|
另外事件和Notifier又可以组合成事件组(Eventgroup),以便发布(Publish)和订阅(Subscribe)。
A
logical grouping of events and notification
events of fields inside a service in order to
allow subscription. |
最后,实现服务的是具体的实例(Service Instance),同一个服务可以对应多个实例。
Software
implementation of the service interface, which
can exist more than once in the vehicle and
more than once on an ECU. |
不难看出,Getter和Setter实际上是从属于Methods的,而Notifier是Events的子类。不过为了与官方协议保持统一,对于具体的子服务,本文也将使用Method、Getter、Setter、Event、Notifier和Eventgroup等叫法。
4. 场景示例与SOME/IP信息格式
了解了SOME/IP里的基础概念,以及这些概念之间的关系,我们便可以回到具体的功能场景里。仿真的场景即可以加深对这些概念的理解,也可以帮助理解SOME/IP的信息格式(SOME/IP
Message Format)。
4.1 SOME/IP信息格式
介绍具体的功能场景之前,我们先大致了解下SOME/IP的信息格式,如下图所示。其中,
• Message ID指明了服务和服务里具体的元素(Service Elements),元素包括Methods和Events。官方推荐对他们分开编号,不过在本示例中并没有按照这个方式来。
• Length指明了从Request ID开始直至末尾的总长度。
• Request ID用来区分针对Methods(包含Getter和Setter)的并行调用。不同的消费者以Client
ID来区分;同一个消费者不同时序的调用以Session ID来区分。其中Session ID从1开始计数,直到超过最大值2^16-1时复位为1。不难看出,Request
ID不适用于Events(包含Notifier)。
• Protocol ID指明SOME/IP Header format的版本,默认是1。
• Interface Version指明了该服务接口(Service Interface)的大版本(Major
Version)。服务接口指的是记录所有服务的规格书,它的版本由大版本和小版本(Minor Version)构成。
Service
Interface: the formal specification of the service
including its methods, events, and fields. |
• Message Type指明该SOME/IP Message是什么类型,有以下几种:
• 0x00, Request, 与Response构成一对;
• 0x80, Response;
• 0x01, Request_No_Return, 即Fire&Forget;
• 0x02, Notification, 涵盖了Notifier和Event,无需Response的Request;
• 0x81, Error, 携带错误信息的Response。
• Return Code,用来给对应的Request做反馈。不难理解,Response里才需要填写Return
Code。不过为了统一格式,所有Request——包括Request、Fire&Forget和Notification,都把Return
Code默认设置为0x00。更多关于Return Code的选项及解释,请参考官方文档【1】。
4.2 场景-Method
查看2.2章节里的服务表,我们知道TVReceiver支持两个子服务,开始和停止电视节目,它们都不涉及修改状态。
借用仿真工程,模拟Head Unit请求开启电视节目,截取报文如下。Head Unit从AEP 192.168.1.10:30500向TVReceiver的AEP
192.168.1.13:30502发送Start请求。该Start请求旨在调用编号为21的Method,它归属于Service
TVReceiver,Service的ID是12。
收到请求后,TVReceiver做出了正反馈,报文如下。
4.3 场景-Getter
在CD Changer提供的服务里,有一个字段AudioDiskInfo支持Getter方法。它的功能是查看唱片机里的磁带(disk)信息,比如有哪几首歌曲,排序是怎么样的。这些信息不可更改,且没有必要实时查看,故设定为Getter最合适。
借用仿真工程,我们模拟Head Unit请求磁带信息,截取报文如下。Head Unit从AEP 192.168.1.10:30500向CD
Changer的AEP 192.168.1.11:30501发送Getter请求,并指定了服务ID为10,Method
ID为31(对应Fields里的AuidioDiskInfo)。
收到请求后,CD Changer做出响应,报文如下。该响应包含了所有唱片的信息,且采用了结构体(Struct)的数据类型(Datatypes)。
4.4 场景-Setter
同样是在CD Changer提供的服务里,我们还可以找到Setter,比如字段Active Disk。当然,除Setter方法外,该字段也支持Notifier。使用Setter,Head
Unit就可以指定当前播放的曲目;而基于Notifier,曲目跳转的信息也会通知到Head Unit。
于是我们通过仿真工程,来触发Head Unit设定当前播放的曲目,截取报文如下。在步骤A里,我们设定当前曲目为第六首,在步骤B里我们又改为第二首。
对应步骤A里,唱片机的响应如下所示。
4.5 场景-Event
在GPS Unit提供的服务里,我们仅找到了Event,名叫Position。为了能够实时获取GPS信息,Head
Unit需要提前订阅GPS Unit的服务。订阅的过程我们放到5.2.3章节里展开。在这里,我们仅需知道,每当GPS信息有更新,GPS
Unit就会把新的位置信息发送给Head Unit。
在GPS Unit节点的CAPL代码里, 可以看到GPS每隔1.3s就会变更位置。
{ // Property: CurrentPosition mstimer tPosition; const dword kPositionCycle = 1300; // update cycle for changing position }
on timer tPosition { $Position::longitude += 10; $Position::latitude += 100; $Position::altitude = $Position:: altitude - 1 + random(3);
setTimer(tPosition, kPositionCycle); }
|
因此我们预期每隔1.3s就会有Event信息发送给Head Unit。对比真实的报文,从A至E的确如此。再次提醒,Event没有相应的Response。
4.6 场景-Notifier
回到CD Changer提供的服务里,我们可以找到很多Notifier。同Event一样,当信息发生变更时,生产者就会通知到订阅了这些事件的消费者。你可能会问,“为啥不把Fileds里单纯是Notifier的类型定义为Event呢”?我当前的理解是,也许将来这些Fields需要被扩展Getter或Setter。
仿真场景的报文如下。
5. SOME/IP-SD
第四章节我们讲述了SOME/IP信息交互的场景,以及信息的格式。但有一个问题:ECU之间是怎么知道哪些服务可用的呢?
为了解决这个问题,SOME/IP额外补充了SOME/IP-SD,它的全称是Service-Oriented
Middleware over IP - Service Discovery【2】。该协议定义了寻找服务(Find
Service)、提供服务(Offer Service)、发布(Publish)和订阅(Subscribe)服务等过程。
SOME/IP Message与SOME/IP-SD Message最明显的区别在于,信息交互时使用的端口号(Port)不一样。下图中1指代SOME/IP-SD,不管是单播还是组播,用到的端口号都是30490。该端口号通常与参数SD-PORT绑定,30490为默认值。换句话说,这个端口是专门用来探索服务的(service
discovery)。而图中2指代的是SOME/IP Message,用到的都是应用程序所使用的端口号,无论是TCP还是UDP。
5.1 SOME/IP-SD信息格式
介绍服务的发布和订阅之前,我们先来看看SOME/IP-SD Message的格式。它其实是SOME/IP
Message的一个子集,也可以说是特例。
Header部分的格式与SOME/IP-SD Message一致,只不过红色字体所代表的属性是固定的。SD的部分由两个Flags开始,Reboot和Unicast,之后便是Entry
Array和Option Array。这里我们跳过对Flag的解释,直接介绍Entry和Option这两个概念。
5.1.1 Entry Array
Entry又细分为两大类,Service Entry和Eventgroup Entry。顾名思义,Service
Entry专门负责处理服务,Eventgroup Entry专门负责处理事件(需要注意的是,事件其实也是服务的一部分)。不同的Entry采用不同的格式,且支持不同的功能。
5.1.1.1 Service Entry
Service Entry的格式如下,其中,
• Type指定了Entry的功能类型,如:
• 0x00, 寻找服务(Find Service),当状态机里没有可用的服务时发出该信息(比如因为服务超时,或者生产者未提供该服务);
• 0x01, 提供服务(Offer Service),当生产者准备好了某项服务时发出该信息,并指定服务的有效期TTL,比如3s;
• 0x01, 停止服务(Stop Service),当生产者不再提供某项服务时,发出该信息,指定TTL=0表示停服。
5.1.1.2 Eventgroup Entry
Eventgroup Entry的格式如下,其中,
• Type指定了Entry的功能类型,如:
• 0x06, 订阅事件(Subscribe Eventgroup),只要某个消费者保持对某项服务的热情,那当它看到该服务的发布消息时,就会持续订阅;
as
long as the client is still interested in receiving
the notifications/events of this eventgroup.
|
• 0x06, 停止订阅(Stop Subscribe Eventgroup),其中TTL需要设置为0,进而与订阅事件进行区分;
• 0x07, 订阅成功应答(SubscribeAck),表示订阅成功;
• 0x07, 订阅失败应答(SubscribeEventgroupNACK), 表示订阅失败,其中TTL需要设置为0,进而与订阅成功应答进行区分。
5.1.2 Option Array
Options是对Entry的补充,提供额外的信息。
Options
are used to transport additional information
to the entries. |
官方协议里【2】定义了很多Options,比如Configuration、IPV4 Multicast、Load
Balancing。这里我们仅拿IPV4 Endpoint Option作为示例。它的格式如下,很明显,它补充说明了对该服务感兴趣的AEP。
如前所述,SOME/IP-SD的沟通都是在端口30490进行的。为此这部分补充显得非常必要。服务的生产者可以声明“哪个Socket提供了这个服务”,而服务的消费者可以声明“哪个Socket想要用到这个服务”。
示例中,该Option声明:在192.168.1.12:30002这个AEP,可以找到名为Navigation的服务。
5.1.3 Option Index
在SOME/IP-SD的信息格式里,Type之后还有一个部分叫Index,它为每条Entry指定了2组Options。我们假定某条SOME/IP-SD
Message里有3条Entry和5条Option,那么下边这张图的含义是:
1. Entry 1、2、3共用了一条Option,该Option在Option Array的位置是0,即OptionArray[0];
2. Entry 1还有1条Option,对应OptionArray[1];
3. Entry 2还有2条Option,对应OptionArray[2]和OptionArray[3];
4. Entry 3还有1条Option,对应OptionArray[4]。
5.2 服务场景
了解了SOME/IP-SD Message的格式,我们再来具体看看服务的场景和报文。
5.2.1 寻找服务
刚启动完毕,Head Unit广播寻找服务。该信息里包含了3条Find Service Entry,把3条放在一起主要是为了提高效率。
The
service discovery shall support multiple entries
that are combined in one service discovery message.
|
等到服务的生产者都准备就绪,且向外持续广播自己的服务,Head Unit就不再需要寻找服务了。
5.2.2 提供或发布服务
提供服务和发布服务都叫Offer Service。只不过,发布服务是针对Eventgoup的,因为只有事件(组)可以被订阅。下边的报文里,3个生产者分别广播了自己的服务。
仔细看你会发现,这些生产者每隔1秒就会发出报文,提供新的服务(主要是Session ID发生变化)。这其实是因为配置文件里规定了ANNOUNCE-CYCLIC-DELAY为1秒。
5.2.3 订阅服务与成功应答
订阅服务意味着消费者对于生产者提供的事件信息持续感兴趣。不难发现,订阅的行为是持续不间断的。但凡消费者对该服务依旧需要,只要新的发布服务的报文发出,消费者就会立即订阅。因为先前订阅的服务都是有时效性的,比如示例中都设定为了3秒。
订阅成功应答的报文如下。
5.2.5 停止订阅
当消费者不在需要某些服务时,它会发出停止订阅的报文。在仿真工程里,我们可以通过关停Head Unit来模拟停止订阅的行为,报文如下。
6. Why SOME/IP
至此我们对SOME/IP的机制已经有了非常全面的了解。问题是,我们为什么需要这样的通讯机制呢?
首先,相比于传统的通讯方式比如CAN,以太网支持更快的传输速率。其次,这是由基于信号的通讯方式(Signal-based
Communication)向基于服务的通讯方式(Service-based Communication)的转变【3】。在基于信号的方式里,但凡信号更新或者变化,该信号就会被传递;但在基于服务的方式里,只有当消费者需要时,生产者才会传递。更重要的是,在面向服务的通讯架构里,新的软件单元可以很容易就被集成进来,而不造成兼容性问题。
Powered
by Ethernet and SOME/IP, SOA models the entire
system as service interfaces. New software can
be easily added to the system without worrying
about the compatibility with others. |
以上便是本篇文章的全部内容,更多细节诸如数据系列化(Data Serialization)、数据结构(Datatypes)和SD状态机(State
Machines)等请参看官方协议。 |