首页 / 资讯中心 / 文章详情

AUTOSAR CP SoAd模块详解:从PDU到Socket的适配与车载以太网配置实践

AUTOSAR CP SoAd模块详解:从PDU到Socket的适配与车载以太网配置实践 ★ FEATURED ARTICLE
做AUTOSAR CP协议栈的同学对SoAd模块应该都不陌生但真正把它搞透的人不多。很多人看我之前写CanTp、CanNm的文章能在CAN网络上跑通基础通信一到车载以太网就卡壳核心问题就是搞不清SoAd到底在协议栈里承担什么角色、怎么配、怎么调。这篇我把SoAd这个模块拆开讲透。从它为什么存在、跟PDU和Socket的关系、静态动态连接怎么选到基于SOME/IP的UDP通信配置实操、收发链路、调试排障一次讲清楚。不管是刚入门AUTOSAR CP的新人还是已经在做以太网协议栈集成的工程师这篇都值得收藏慢慢看。1. 模块定位SoAd在AutoSar CP协议栈里到底解什么难题1.1 从CAN到车载以太网PDU与Socket之间的鸿沟传统CAN时代整个AUTOSAR CP的通信抽象都是围绕PDUProtocol Data Unit来设计的。上层COM、NM、Diagnostic发的是PDU中间PduR路由的是PDU下层CanIf、CanTp收发的也是PDU。PDU有固定ID、固定长度、固定的收发路径这套抽象在CAN、LIN、FlexRay上跑得非常好因为总线本身就是一个带ID寻址、面向报文的机制一个CAN报文天然对应一个PDU。但车载以太网不一样。以太网是典型的基于IP和Port寻址的包交换网络连接模型是Socket一个四元组源IP、源端口、目的IP、目的端口才能唯一定义一条通信通路。而且以太网报文的长度可变、内容没有“ID”的概念靠IP和端口来区分业务。你没法把一个CAN式的PDU直接丢到以太网上因为缺少地址映射、连接管理、报文边界还原这一整套机制。随便说一个场景某个服务实例监听在192.168.1.10的30490端口上层SD模块要往里发一条FindService消息它发的还是一帧PDU。这一帧PDU该送给哪个IP、哪个端口靠什么协议发UDP还是TCP这些都不是SD关心的事必须有人做一次“翻译”。SoAdSocket AdaptorSocket适配器就是做这个翻译的。它处在PduR和TcpIp之间对外承接上层PDU的收发接口对内操作TcpIp暴露的Socket接口。本质上SoAd把“基于PDU的AUTOSAR思维”和“基于Socket的以太网思维”缝合起来。配置好SoAd之后上层模块不需要知道IP和端口只需要按PDU ID发数据至于对应哪个Socket、走UDP还是TCP、发给谁全部由SoAd按静态配置或运行时动态逻辑去处理。这也是为什么我总跟团队说调试以太网协议栈问题不要一上来就怀疑TcpIp、怀疑EthIf先定位SoAd这层映射。很多时候报文发不出去、收不进来就是SoAd的Socket信息没对上。1.2 SoAd的边界哪些事归它管哪些事不归它管很多新人容易把SoAd当成一个万能的“以太网工具包”一出现问题就怀疑SoAd这不对。要彻底理解SoAd先划清楚职责边界。归SoAd管的PDU与Socket路由映射哪个PDU走哪个SocketConnection收发方向都能配。静态与动态Socket管理配置阶段固定下来的Socket或者运行期根据SOME/IP服务发现动态创建/删除的Socket。PDU报文边界还原尤其是TCP这类流式协议SoAd要负责把流数据还原成上层可识别的完整PDU这里就涉及SoAd的TPTransport Protocol处理。收发确认与错误通知成功发送后向上层回报TxConfirmation接收故障、远端断开时向上层报错误。连接状态的上报TCP连接建立/断开时通知相关模块或BswM做状态判断。不归SoAd管的IP栈本身IP报文的收发、路由选择、分片重组这些是TcpIp模块的活SoAd只是调用TcpIp的服务。物理层的协商、Link状态这是EthIf、EthTrcv甚至EthSwt的事情。PHY芯片没Link上SoAd再正常也发不出一个bit。SOME/IP的序列化和反序列化、服务发现逻辑这些是SD模块和应用层的事SoAd只负责把完整的SOME/IP报文当PDU搬运不做内容解析。你把一个SOME/IP订阅消息发出去SoAd不会去检查里面的Message ID正不正确。一句话总结SoAd是“路由枢纽下方的以太网适配层”它保证PDU在正确的时间、通过正确的Socket、到达正确的地址至于PDU里装的是什么业务语义它不管也不该管。2. 核心设计SocketConnection怎么把报文路由到正确的地方2.1 SocketConnection、本地地址、远端地址三方关系SoAd里面最关键的对象是SocketConnection它描述一条完整的通信连接定义。看AUTOSAR规范里的配置结构一个SocketConnection会引用一个本地地址SoAdSocketLocalAddress和一个远端地址SoAdSocketRemoteAddress。本地地址解决“从哪发、在哪收”需要配置本地IP和本地端口。对车载以太网来说ECU通常只有一到几个IP地址本地端口则是每个服务实例或每个Socket唯一标识。举个例子你的ECU要接收SOME/IP的FindService消息那就必须有一个本地监听端口30490这个端口就是通过SoAdSocketLocalAddress配置出来的。远端地址解决“发给谁、收谁的”配置远端IP和远端端口。想对192.168.1.2上的某个服务发诊断请求远端IP写192.168.1.2远端端口写服务的监听端口。在实际配置工具里这个关系特别直观。以Vector DaVinci Configurator为例生成的项目里可以清楚看到SoAdSocketLocalAddressLocalPort 30490, LocalAddr 本机IPSoAdSocketRemoteAddressRemoteAddr 对方IP, RemotePort 目标端口SoAdSocketConnectionConnectionId 1, RemoteAddress 上面的远端, LocalAddress 上面的本地, Protocol UDP/TCP, Type STATIC/DYNAMIC这里我特别提醒一句本地端口和远端端口不要配反了。这是新手最容易犯的错误尤其是一个ECU既要发请求又要收响应时本地端口写成了对方端口结果收发全乱。配置完先拿端口匹配关系过一遍你要发数据本地端口是你自己的源端口远端端口是对方监听端口你要收数据本地端口是你自己监听的端口。这两条千万别混。2.2 静态Socket与动态Socket的使用场景SoAdSocketConnection的Type参数有三个可选值STATIC、DYNAMIC_DONT_DELETE、DYNAMIC_AUTODELETE。很多人配的时候只看名字不理解背后的应用场景配出来问题一大堆。STATIC静态Socket连接在系统启动时就已经确定整个生命周期内不做变化。适合固定端口的通信比如DoIP的TCP端口13400、SOME/IP服务发现的UDP端口30490这种大家都约定好的固定通路用静态Socket最简单可靠。它不依赖运行时服务发现的结果配置完成就直接能用。DYNAMIC_DONT_DELETE动态但不自动删除Socket在运行时由SoAd动态创建但一旦创建之后会一直保留不随某个连接断开或服务实例消失而自动删除。适合那些“服务实例会动态出现但一旦建立就长期存在”的场景比如SOME/IP Event的周期性通信链路一旦订阅成功就一直复用这条连接。DYNAMIC_AUTODELETE动态且自动删除Socket在运行期创建并且在连接条件不再满足时自动释放。适合临时性的通信比如一次性的文件传输、按需建立的TCP会话当服务停止时连接自动拆除资源自动回收。怎么选我的经验是用最简原则能静态就静态长连接用DONT_DELETE纯粹临时会话用AUTODELETE。别一上来所有连接都配成AUTODELETE运行期频繁建链拆链调试起来非常痛苦动不动报文就丢了最后查下来是动态Socket生命周期管理出错。2.3 SocketGroup把整组Socket管起来的技巧再说一个不少工程师忽略的配置项——SocketGroup。它是SocketConnection的分组容器把多条连接捆绑到一个组里方便做批量操作。主要有两个典型用法。一是WakeUp唤醒相关逻辑。以太网唤醒时你希望一组相关的Socket一起被激活或者一起进入待命状态如果单条配置会非常疲惫用SocketGroup可以整体操作。二是在SoAd的起停控制里可以基于一组Socket做统一控制避免上层逐条调用减少状态机管理和错误分支。配置上SocketGroup就是一个Ref列表。需要注意的是同一个SocketConnection可以被多个Group引用但一个Group内部的连接关系要自己保证逻辑一致。比如把服务发现端口和Event端口放一个Group没问题但别把不同ECU相关的端口硬塞进同一个Group否则唤醒时会牵一发动全身。3. 配置实操搭一个可用的UDP SOME/IP通信链路3.1 前置条件TcpIp与EthIf的配置要点正式配SoAd之前必须先把底下的链路打通。很多项目里SoAd配置本身没毛病但TcpIp/EthIf配置有问题导致所有报文都静默丢失。EthIf与EthTrcv层面要确认PHY芯片的配置正确。比如现在很多以太网节点用TJA1145这类收发器需要在EthTrcv配置里配好PHY地址、工作模式比如Master/Slave、唤醒源等。物理层的Link状态没起来上层协议栈一切都是白搭。一个实用的小技巧调试时可以通过EthIf直接发送一个简单的测试帧验证物理链路是否打通再来调试上层SoAd这样问题隔离得最快。TcpIp层面要配置好IP地址、子网掩码、路由表并确保UDP/TCP模块使能。车载以太网最常见的IP段是192.168.1.x子网要发送的目标地址如果在同一子网走直连路由即可如果跨网段还要配置网关路由和必要的路由表项。TcpIp模块还需要为每个接口分配一个TcpIp Interface ID这个ID后面会出现在SoAd的底层控制模块引用里配错了SoAd会找不到可用的网络接口报文跟着就飞了。工程上我的建议是先在TcpIp层做一个最小自测通过TcpIp的API直接循环发送UDP测试报文到对端对端能通过Wireshark看到再动SoAd。跳过这步直接配SoAd出了问题时排查点太多效率非常低。3.2 SoAd实例配置完整步骤下面以一个最常见的场景为例ECU A要通过UDP向ECU B的SOME/IP服务发现端口30490发送FindService消息并且ECU A也能接收对端发送的OfferService响应。整个过程我按Vector DaVinci Configurator的常见操作路径走一遍其他工具大同小异。第一步创建SocketConnection。新建一个SoAdSocketConnection这里命名为SoAdCon_SD协议选择UDPType选择STATICConnectionId设置为一个唯一的数字工具一般会自动分配。第二步配置本地地址。新建SoAdSocketLocalAddressLocalPort填30490LocalAddr选择本机TcpIp接口的IP或者填0.0.0.0表示绑定到所有本地接口具体看工具支持。对SOME/IP SD来说本地监听端口就是30490因为AUTOSAR规范推荐SD服务发现固定使用这个端口。第三步配置远端地址。新建SoAdSocketRemoteAddressRemoteAddr填ECU B的IP比如192.168.1.2RemotePort填30490。如果SD通信要求支持动态对端地址也可以配置为通配地址和端口通过运行时信息覆盖但第一次调试尽量固定一个目标减少变量。第四步把Address挂到Connection下。在SoAdSocketConnection里引用刚才创建的SoAdSocketLocalAddress和SoAdSocketRemoteAddress。第五步创建收发PDU。新建SoAdSocketTxPdu和SoAdSocketRxPdu。TxPdu对应FindService请求会有一个PduId和长度上限RxPdu对应OfferService响应也要指定PduId和长度。这里重点确认长度一定要大于最大预期报文长度否则超过长度的报文会被丢弃。第六步PduR路由配置。在PduR里新增两条路由一条是SD模块的TxPdu路由到SoAd的TxPdu另一条是SoAd的RxPdu路由回SD模块的RxPdu。PduR里的PduId要和SoAd侧的PduId一一对应这是收发成功的前提。第七步SD模块绑定。在SD模块配置界面把SD的TX PDU Ref和RX PDU Ref分别指向PduR里的这两条路由对应的PDU并确保SD使能了服务发现功能。生成代码之后理论上这条链路就形成了SD模块发送FindService报文 → PduR → SoAd的TxPdu → SoAd根据SocketConnection映射到远端192.168.1.2:30490 → TcpIp → EthIf → 物理链路。反向同理。3.3 关键参数与经验取值配置过程中有几个参数很多人拿不准我这里直接给结论。PDU长度SoAdSocketTxPdu/RxPdu的MaxLength对于SOME/IP SD报文常见长度在300~1400字节之间取决于服务条目数量。建议配置时留80%的余量。比如预期报文最大300字节就配成512甚至1024宁可多花一点Buffer也不要到现场被长度限制坑了。TCP场景下大PDU更常见比如DoIP的大包能达到几KB甚至几十KB要考虑Buffer资源和分块传输的配合不能盲目把MaxLength设成几万字节。触发发送模式TriggerTransmit很多工具的SoAd PDU可以配置为TriggerTransmit模式。启用后SoAd不会直接从上层传入的PduInfoPtr里取数据而是回调上层接口让上层把数据拷贝到一个指定的发送Buffer里。这对超大PDU、TCP流式发送场景特别有用。第一次做一个小型SOME/IP项目如果不是特别需要可以先关掉TriggerTransmit直接由上层把数据写进来简化调试难度。同步发送模式SoAdSyncTransmitMode当配置为同步发送时SoAd调用TcpIp发送后会一直等到发送完成或失败才返回。配置为异步发送时SoAd只是把数据提交给TcpIp就返回了真正的发送完成靠回调通知。从工程稳定性来看默认保持异步即可同步模式虽然代码简单但会在关键路径上阻塞TCP的Backplane里还容易因为长时间占用导致其他通信得不到调度。4. 通信流程数据收发与TCP连接管理的运行时行为4.1 初始化与启动链路通信能用起来首先需要一套正确的初始化次序。AUTOSAR CP里模块初始化顺序通常由EcuM的启动配置决定常见的一个合理顺序是EcuM先初始化底层驱动然后初始化通信相关模块最终由BswM协调通信栈的启动。以车载以太网为例一般链路是EcuM启动到RUN状态 → BswM调用EthIf_Init、EthTrcv_Init、TcpIp_Init → 然后调用SoAd_Init → 等EthIf上报Link Up → TcpIp地址分配完成 → SoAd_StartUp → 上层SD、COM模块开始收发。SoAd在SoAd_Init完成静态SocketConnection的初始化在SoAd_StartUp完成启动状态切换之后上层才能正常收发。不同工具生成的代码里这两个API可能被BswM统一调用也可能分散在ComM的以太网通道状态回调里调用。关键是确保TcpIp_Init在SoAd_Init之前否则SoAd初始化的过程中访问底层Socket能力时可能拿到无效句柄。还有一个经常被忽视的点TCP连接不是配置完就自动建立的。UDP无连接直接发就行TCP需要先主动Connect、Listen、Accept完成三次握手后才能真正传数据。SoAd内部封装了这些Socket生命周期管理但具体行为受配置影响。有的配置项会让SoAd在StartUp时主动连接远端有的则需要上层触发某条连接后才建立会话。排查TCP场景下的“报文发不出去”问题时先看连接状态回调有没有被触发是最快定位手段。4.2 发送路径从上层PDU到Socket报文一条完整的发送路径是这样的上层模块比如SD调用PduR_SoAdIfTransmit请求发送一帧PDU。PduR按照路由表找到SoAd对应的发送接口最终调用到SoAd_Transmit(PduId, PduInfoPtr)。SoAd拿到PduId后先在配置表里找到对应的SoAdSocketTxPdu再通过TxPdu关联到所属的SocketConnection。SocketConnection里保存着本地地址、远端地址和协议类型SoAd据此把PDU的数据内容加上IP和端口信息转交给TcpIp的发送接口例如TcpIp_SoAdIfTransmit。UDP场景下比较直接因为UDP保留消息边界一帧PDU对一帧UDP报文。如果PDU长度超过UDP payload上限MTU减去IP和UDP头IP层会自动做分片接收端由IP层自动重组SoAd应用层不需要特殊处理只要把数据提交下去即可。TCP场景下要复杂得多。TCP没有消息边界它是字节流协议。SoAd必须在发送时先把完整的PDU缓冲起来提交给TcpIp后再等TcpIp把数据全部发送出去。接收端SoAd还得根据配置的TP信息把连续的字节流按PDU边界切分开来。这种流式处理正是SoAd的难题之一配置里涉及Tp Channel、TxBuffer、RxBuffer等参数。如果发现TCP传输大PDU时经常出现一半或错位的情况优先检查BP的分段策略与缓冲大小不要盲目认为是TCP不靠谱。4.3 接收路径从Socket报文到上层PDU接收路径反向理解TcpIp收到数据帧后会调用SoAd_IfRxIndication报文里带了本地地址、远端地址、端口信息。SoAd拿着这些信息匹配SocketConnection如果匹配上再根据Connection里配置的RxPdu信息找到上层对应的PDU接收回调最终通过PduR把数据交给上层。关键在于同一个SocketConnection上可以挂多个TxPdu和RxPdu吗可以但这也意味着SoAd需要额外的信息才能把报文和PDU对应上。在UDP场景下同一个本地端口对同一个远端端口收报文如果没有额外字段SoAd很难区分该交给哪个PDU。所以正常情况是一个SocketConnection对应一组确定收发的PDU配置多个的时候必须保证业务上报文的报送条件有另外的区分逻辑这时可能需要SOME/IP TP或者额外配置来控制否则就是一场配置灾难。接收路径还有一个容易被忽略的点很多工具生成的SoAd代码不允许在接收指示回调里做耗时操作。SoAd_IfRxIndication是在TcpIp上下文中被调用的如果上层在这个回调里执行了复杂的反序列化或者数据库读写操作会影响整个协议栈的响应时间。压测时发现的偶发丢包、超时问题很多就是这个原因导致的。正确做法是接收回调只做轻量拷贝和状态标记把耗时处理放到任务上下文或独立线程中去做。4.4 与SD模块一起工作服务发现和动态端口很多SOME/IP项目里SoAd报文的收发不是从头到尾走一个固定端口服务的Event、Method通信往往走服务实例动态分配的端口。这就是为什么静态Socket只是起步真正复杂的是SoAd和SD模块的动态协同。典型场景客户端要订阅一个服务实例的Event。客户端先在固定的SD端口30490发送SubscribeEventgroup消息服务端收到后在SD回应SubscriberAck之前或同时会通过SD配置信息告知客户端Event数据将来会从哪个端口发送。这个端口通常是服务实例启动时动态分配的客户端拿到这个端口后需要SoAd创建一个新的SocketConnection动态Socket并给这条新连接分配一个RxPdu把Event报文收上来。AUTOSAR CP里SD模块可以通过它的接口告诉SoAd创建或者删除动态Socket。SD会提供端口号、IP地址等信息SoAd据此完成动态连接管理。所以配置时必须保证SD模块与SoAd模块之间的动态连接管理和PDU映射配置完整。很多项目里Event收不到排查到最后就是动态Socket创建失败原因往往是SD模块的端口配置和SoAd的端口范围配置不一致。还有一点SOME/IP里多播MulticastEvent也很常见。SoAd也要支持多播报文的接收配置上需要让SocketConnection的本地地址指向多播组地址并且底层协议栈支持加入多播组。如果项目跑多播Event收不到先用抓包软件确认报文是否到了网卡再确认本地地址是否绑定了多播IP这个排查顺序很关键。5. 问题排查SoAd调试中我踩过的那些坑5.1 排查SoAd必备工具做SoAd相关调试三样工具几乎是必需品。Wireshark抓以太网报文。重点看IP、UDP/TCP端口、以及SOME/IP协议解析。客户端发出的报文、服务端应答的报文必须都能看到只要报文明面上在走问题就在协议栈内侧如果报文根本没从网卡出去那就往下层查。Vector的Ethernet报文注入/监控工具比如CANoe、vFlash/Ethernet相关功能可以对ECU直接发送构造好的以太网报文验证ECU的单向处理能力。这对定位“接收端SoAd是否正常回应”特别有价值。AUTOSAR协议栈自身的Trace工具比如Vector的DaVinci Runtime或Trace这类工具能显示SoAd、PduR、TcpIp各层之间的API调用、成功/失败返回值。我通常先用Trace定位是SoAd没收到数据、还是收到了但没路由上去再决定是否用Wireshark看底层报文。可以省去大量瞎猜的时间。5.2 高频问题速查表下面这个表是我在项目里总结的高频问题和排查方向按概率从高到低排。现象常见原因排查路径报文怎么都发不出去抓包看不到EthIf/Phy未Link或者TcpIp没初始化完成先看Link状态再用EthIf自测发送排除驱动问题SoAd接口返回发送失败TcpIp发送函数拒绝比如路由未使能、目标不可达看TcpIp模块的错误码确认IP地址和路由能发请求但收不到响应远端端口/本地端口不匹配或者接收PDU未配置核对SocketConnection的本地和远端端口核对RxPdu是否挂上收到的报文长度不对或被截断RxPdu的MaxLength设置过小调大接收PDU长度最好留余量TCP连接断断续续反复重连连接KeepAlive未配置或者动态连接生命周期管理有问题检查TcpIp KeepAlive设置检查SoAd动态Socket的删除时机SD服务发现正常但Event收不到动态Socket未创建多播地址未绑定抓包确认Event报文是否到达网卡检查SD与SoAd动态连接配置发送超大PDU时失败UDP分片在网关被丢弃或TCP Buffer不够对小网络分片策略做调整或增大TcpIp发送缓冲记住排查顺序永远是“物理链路 → 底层协议栈 → SoAd映射 → PduR路由 → 上层模块逻辑”不要跳层。不少人一上来就翻SoAd配置最后发现是PHY芯片没工作在正确模式下这种项目沟通成本和时间损耗我见得太多了。5.3 一个真实案例Event报文发不出去最后分享一个我印象很深的实际排障案例。当时是一个VCU项目SOME/IP服务能正常被发现服务端周期发Event客户端抓包能看到服务端已经向特定端口发出了Event报文但客户端应用层始终收不到通知。应用同学一度认为是SoAd接收坏了。我排查的路径是这样第一步拿Wireshark抓包确认服务端发的Event报文目标端口是动态分配的端口A目标IP是客户端IP说明发送链路是通的。第二步看客户端SoAd的接收端。结果发现客户端根本没有配置对应端口A的SocketConnection也没有SD动态创建Socket的触发条件。问题开始聚焦到SD与SoAd的动态连接协同上。第三步查SD模块的配置。发现SD模块虽然使能了Event订阅但Event接收PDU所对应的SocketConnection类型被配成了STATIC端口却写死成了30490而服务端实际用的是动态端口A。两边端口对不上Event自然收不到。解决方法是把该条SocketConnection改成DYNAMIC_DONT_DELETE并将SD模块的订阅成功回调中触发的动态创建逻辑配置完整让SD在收到SubscriberAck后把端口A信息传给SoAd动态创建新的接收通路。改完后Event立即就能上报了。这个案例给我的教训是SOME/IP通信出了兼容性问题先别急着怀疑SoAd底层往往是“动态端口映射”这个核心机制没有跟SD协同好。这也是SoAd最反直觉的地方表面看起来是“以太网收发”实际上考验的是对端口映射和服务发现的理解深度。6. 工程落地心得从配置到量产6.1 配置管理和版本控制SoAd这种配置驱动型模块最怕的就是配置乱。我刚入行时参与的一个项目SoAd配置由几个人分模块维护有人改了地址有人改了端口合并时不冲突但互相覆盖整整耽误了一天排查。血的教训。现在我的团队对SoAd配置包括TcpIp、EthIf、PduR相关配置有几条硬性纪律第一配置文件必须纳入版本管理任何修改都要有记录第二配置评审时必须有完整的端口清单和PDU清单每次只改一处改完立刻生成代码做冒烟测试第三SoAd模块相关的配置建议由一个人统一负责避免多人同时改。这样虽然看起来流程繁琐但比起在量产阶段追查一个莫名其妙的通信丢包事件这些前置成本非常低。6.2 最小闭环先行新平台、新硬件第一次调以太网时我强烈建议先搭一个“最小闭环”不跑SD、不跑SOME/IP、也不跑复杂诊断服务就从COM或直接测试代码周期发送一个简单的UDP报文到测试电脑电脑用Wireshark看到再原样回发一条让ECU接收。这个可以验证从“应用程序/SD → PduR → SoAd → TcpIp → EthIf → PHY”的完整收发管道是通的而且能把变量限制到最少。管道通了再逐步加SD服务发现、加SOME/IP方法和Event一层一层往上叠。每次只加一个功能模块出问题马上能判断是新增部分引发的不会出现一堆功能堆叠在一起、一崩全崩、根本不知道是哪一层的问题。6.3 与BswM/ComM联调的注意事项SoAd不是独立运行的它还跟整车的电源管理模式挂钩。热搜词里提到“BswM下电怎么配置”这个跟SoAd关系很密切。整车睡眠、唤醒、下电时BswM会调用SoAd_Stop或者SoAd相关的关闭接口释放Socket资源关闭连接甚至配合EthTrcv实现唤醒源配置。一个常见的坑是下电时SoAd先被关了但TcpIp还处于运行状态导致TcpIp层还有数据要往上送SoAd却已经注销了接收接口。结果是唤醒之后通信状态不稳定偶发丢包。正确的BswM下电序列应该是先停止上层通信SD、COM、DoIP等再关闭TcpIp最后关EthIf反向按启动顺序执行。SoAd的关闭要在TcpIp之前完成确保不会存在“底层还在收发上层已经睡过去”的状态。另外如果项目支持以太网唤醒SoAd相关的SocketConnection通常需要配置唤醒能力把唤醒相关的PDU和SocketGroup关联起来只有这样收到规定的唤醒报文后SoAd才能及时通知BswM把通信栈重新拉起来。这块配置不建议从零摸索直接参考BswM与SoAd、EthIf联合配置的官方示例工程最稳妥各个工具链都有参考样例先照搬再裁剪。根据我个人做多个量产项目的经验SoAd这个模块本身并不复杂真正的复杂度全在端口映射、动态连接和前后的时序配合上。把这一块想明白车载以太网在AUTOSAR CP这套体系里也就是“一个带连接管理功能的高级适配器”而已。遇到问题别慌按链路分层查用抓包定位突破口用Trace看返回值大多数问题都能在半天内收敛。最后再送大家一个小技巧第一次配置SoAd时把所有的回调函数、错误通知都接上并打Trace日志哪怕觉得没用也要接。等真正出了诡异问题这些日志就是你最快锁定病灶的雷达。
阅读完成 · 觉得有帮助?
咨询建站