ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Simulink AUTOSAR冗余数据类型顽固生成?从引用链排查到彻底解决

Simulink AUTOSAR冗余数据类型顽固生成?从引用链排查到彻底解决 搞AUTOSAR代码生成的朋友十有八九都碰过这种怪病模型里明明已经把某个数据类型删干净了重新生成代码后Rte_Type.h里还是会出现一个名字几乎一模一样的typedefARXML 里也总跟着一个多余的IMPLEMENTATION-DATA-TYPE。我前阵子处理一个VCU控制器的模型时就被这个“Simulink AUTOSAR 冗余数据类型顽固生成问题”折腾了两天删了生成、生成又回来最后发现根子不在表面那几行代码而在模型、数据字典、ARXML合并链路里一堆看不见的引用。这篇文章就是把这次排查和解决过程完整复盘一遍。我会先讲清楚冗余数据类型是怎么从Simulink一路跑到ARXML里的再拆四个最容易被忽略的根因最后给出一套可以直接照着做的清理流程顺带把现场踩过的坑和验证方法也交代了。无论你是刚接手AUTOSAR模型生成的新手还是被遗留模型折磨的集成工程师这套思路应该都用得上。1. 先从现象入手到底什么算冗余数据类型1.1 一种典型的报错现场先说一个最典型的现场。模型名就叫VCU_PowerCtrl我打开生成的Rte_Type.h一眼看到两行几乎重复的定义typedef uint16 VoltageSensorRaw_T; typedef uint16 VoltageSensorRaw_T_1;端口上明明只用了VoltageSensorRaw_T那个VoltageSensorRaw_T_1到底是谁再看ARXML发现IMPLEMENTATION-DATA-TYPE包里面也躺着两个短名一个是VoltageSensorRaw一个是VoltageSensorRaw_1。它们在生成的A2L文件里也会各自生成一个测量/标定对象集成方那边一看就懵为什么同一个物理量会有两份数据对象更麻烦的是我试着在AUTOSAR Dictionary里把VoltageSensorRaw_1删掉保存重新生成它又回来了。这种删不干净、重新生成又出现的类型就是标题里说的顽固生成的冗余数据类型。它不是简单的模型里多了一个Signal对象而是生成链路里某个环节还在持续引用这个类型导致代码生成器每次做类型收敛时都把它当作活跃类型再生成一遍。1.2 为什么不能睁一只眼闭一只眼有些工程师觉得反正只是多一个typedef编译能过RTE能生成先不管了。但实际危害比想象的严重。第一多出来的类型会进RTE和基础软件配置工具。你用达芬奇或者其它AUTOSAR配置工具导入ARXML时如果发现同样的类型短名出现两份轻则告警重则直接报duplicated short name错误。尤其当冗余类型引用了一个错误的CompuMethod或DataConstr时整个生成代码的变量语义都会被带偏。第二它是典型的技术债发酵点。现在不去查后面只要有人动一次数据类型映射这个冗余类型就可能变成正式引用甚至和新的同名类型撞车。到那时候就不是删一个字典条目能解决的了。第三它会影响CI自动化集成。很多团队已经跑批处理构建ARXML一多重复类型会把下游工具链卡住。所以遇到这种问题还是趁早挖根因。2. 数据类型生成链路拆解冗余是从哪儿冒出来的2.1 AUTOSAR类型体系速览要理解冗余类型为什么顽固得先看懂Simulink生成AUTOSAR代码时的类型体系。AUTOSAR里和数据类型相关的概念大致分四层Application Data TypeADT描述应用语义比如电压传感器原始值不关心底层内存长度。Implementation Data TypeIDT描述具体实现比如用uint16表示带CompuMethod、DataConstr、Unit等属性。Base Type描述真正的C语言基础类型比如uint16、sint32。CompuMethod / DataConstr / Unit虽然不算数据类型但会挂在IDT的SW-DATA-DEF-PROPS下面A2L和配置工具靠它们做量纲和值域解释。在Simulink模型里你看到的端口信号是Simulink数据类型比如uint16、single或者一个Simulink.AliasType。通过Code Mappings里面的AUTOSAR DataType映射这些Simulink类型会被指定到AUTOSAR字典里的某个IDT再由IDT关联到ADT和Base Type。生成代码时Embedded Coder会把这个映射链以类型定义的形式写进ARXML和Rte_Type.h。2.2 Simulink侧对应的几个仓库很多人在模型里删了一个数据类型就觉得万事大吉但类型信息其实存在多个地方AUTOSAR Dictionary模型关联的AUTOSAR字典里面保存ADT、IDT、CompuMethod等定义。这是冗余类型最常见的老巢。Simulink数据字典.sldd保存Simulink.Signal、Simulink.Parameter、Simulink.Bus、Simulink.AliasType等对象。这些对象的DataType属性可能指向某个AUTOSAR IDT。基础工作区模型如果没把变量存进.sldd那就在MATLAB基础工作区里加载模型时自动加载它们。存量ARXML有些项目是先把已存在的ARXML作为系统模板导入生成时再做合并。如果输入ARXML里本来就带着旧类型定义Simulink生成的类型就会和它们叠加。只要上述任何一个仓库里还留着对这个类型的引用代码生成器做类型遍历时就会误以为这个类型还需要于是重新生成。你把字典里的类型条目删了但另一个.sldd里还挂着一个Simulink.Parameter它的DataType字符串还指向那个IDT短名那生成器自然会想办法把这个IDT重新补出来。2.3 看不见的引用是顽固的根这里要特别强调一个概念不是只有端口信号才叫引用。代码生成器在做类型收敛时会扫描的范围包括但不限于Inport/Outport端口的数据类型内部Signal线的数据类型Simulink.Signal对象含Signal name must resolve to signal object场景Simulink.Parameter对象标定量、输入量Simulink.Bus对象的嵌套元素类型Stateflow图表里的事件、数据Data Store Memory/Data Store Read/WriteModel Reference接口Test Harness里遗留的映射。很多冗余类型都是在删除了某个源对象但对应的映射条目还残留在Code Mappings或字典里这种半残状态下产生的。你看模型图找不到这个类型被谁在用但生成器的内部依赖表里还记着它。这种引用不会高亮显示只能靠工具去查。3. 四个高频根因为什么每次删完又会回来3.1 根因一Code Mappings里残留了孤儿映射最常见的顽固生成原因是Code Mappings里的数据类型映射没有跟着源对象一起删除。举个例子你原来有个Data Store Memory名字叫RawVoltageStore给它做了AUTOSAR数据类型映射指向IDTVoltageSensorRaw_T。后来你把整个Data Store Memory相关逻辑删了换成了普通的信号线但Code Mappings面板里那个RawVoltageStore - VoltageSensorRaw_T的映射条目仍然在。很多版本里直接删除模型块并不会自动删除Code Mappings里已经生成的映射记录。下次生成代码时映射条目还在生成器就会认为VoltageSensorRaw_T仍然是活跃类型于是重新写出这个IDT。你以为删了字典里的类型就完了其实映射还在给它续命。处理方式也很简单打开Code Mappings面板找到对应的数据项右键选择删除映射/清除映射。注意要区分Remove mapping和Delete有些版本里Delete会把映射和字典条目一起删而Remove mapping只是把关联关系断开字典条目还在。需要根据实际情况选择拿不准就两个都做一遍然后看字典里是否还残留短名。3.2 根因二数据字典与基础工作区之间存在同名变量覆盖第二种根因在多人协作项目里非常常见。模型加载时基础工作区里有一堆变量同时模型又关联了一个.sldd。按照Simulink数据字典的优先级.sldd里的Design Data会覆盖基础工作区同名变量。于是你打开模型看到的是一个来自.sldd的类型映射但某些旧的m脚本或初始化脚本会在build之前往基础工作区写入同名变量把类型定义改成旧版本。这种情况下表现出的行为很邪门你在AUTOSAR Dictionary里删掉某个类型保存模型关闭MATLAB重新打开它又回来了。原因可能不是字典没保存而是加载顺序有问题——.sldd里的对象被旧的基础工作区变量影响或者有一个Simulink.AliasType在load回调里被重新创建。排查思路是把基础工作区清空后再加载模型看看冗余类型还在不在。如果清空后问题消失那就重点检查模型的InitFcn、PreLoadFcn、StartFcn以及项目启动脚本里是否有create对象/赋值DataType的代码。不要小看这些回调函数我曾经见过一个PreLoadFcn里用evalin(base,xxx Simulink.AliasType;)创建了一堆旧类型导致谁删都没用。3.3 根因三Bus对象/参数对象内部还嵌着旧类型引用第三种根因更隐蔽因为被删的对象可能看起来和冗余类型毫无关系。比如你删除了某个AUTOSAR端口信号但模型里还有一个Simulink.Bus对象这个Bus对象的一个元素DataType还写成VoltageSensorRaw_T。这个Bus对象可能被某个不参与生成代码的Test Harness引用也可能只是被某个常量参数对象引用。但生成器扫描数据依赖时只要发现Bus对象里的元素类型指向这个IDT就会把它保留下来。同样Simulink.Parameter对象的DataType属性也有可能指向一个旧IDT。尤其当该参数对象被设置成Signal或Parameter角色并且参与代码生成时生成器会把这个IDT重新生成到RTE和ARXML里。定位这类引用推荐用Simulink.findVars配合正则搜索。大致思路是这样% 找出模型中所有引用指定变量名的对象 h Simulink.findVars(mdl, Name, VoltageSensorRaw_T); disp(h);对于Simulink.Bus里嵌套的元素类型需要用Simulink.Bus对象递归扫描。可以写一个小脚本遍历所有总线的Elements看一下DataType字段里是否包含目标IDT短名。这一步虽然麻烦但往往能直接命中顽固类型的幕后黑手。3.4 根因四存量ARXML合并时把尸体又捞了回来第四种根因是项目集成的特殊姿势导致的你用的不是Simulink凭空生成整套ARXML而是和供应商/基础软件团队给的一份存量ARXML做合并。比如你的工具链配置是先生成一个组件ARXML再和一个系统模板ARXML合并成最终交付物。这时候系统模板ARXML里如果本身就带着一份旧的类型定义那无论你怎么清理Simulink侧合并后的最终ARXML里还是会有那个类型。这种情况下冗余类型不是Simulink生成的而是合并时被保出来的。它特别像顽固生成因为你会看到每次重新集成旧类型都会出现在最终文件的同一个位置。唯一不同的是你在字典里删除它之后下次合并它照样出现因为源头在另一份文件里。处理方式需要先确认合并链路。看生成后的ARXML搜索冗余类型的短名判断它是来自slprj目录下Simulink生成的文件还是来自你作为输入的模板文件。如果是输入模板里的就用工具或文本方式删除模板中对应AR-PACKAGE里的类型定义然后重新合并。这里有个坑直接改文本容易破坏ARXML结构最好用支持ARXML schema的编辑器或脚本保证SHORT-NAME和引用一致性。4. 排查与修复一步步把顽固类型揪出来4.1 先建类型清点清单我处理这类问题有个习惯先不急着删先拿出一份完整的类型清单把活跃类型和字典类型对比一下。很多冗余问题就是被我以为这个类型没用了这种印象迷惑的。在Simulink里可以通过AUTOSAR Dictionary导出现有类型定义也可以从生成后的ARXML反查。具体操作上我一般用MATLAB脚本把字典里的数据类型先拉出来% 打开模型关联的数据字典示意具体API以当前MATLAB版本为准 dd Simulink.data.dictionary.open(VCU_PowerCtrl.sldd); dDataSect getSection(dd, Design Data); % 找到所有类型对象 typeNames find(dDataSect, -value, -regexp, name, .*_T$);这个脚本只是开胃菜重点是先把类型名单拿到再和模型实际端口、信号、参数里引用的类型做差集。差集里的那些往往就是可疑冗余类型。不要盲目相信差集就是垃圾因为有些类型虽然不在端口上用但可能被A2L标定或外部接口引用需要确认后再删。4.2 清理顺序很重要从引用到定义清理的先后顺序如果错了很容易出现删一个报一堆错误的情况。我推荐按这个顺序来先打开Code Mappings把所有数据项信号、参数、状态、Data Store逐个检查删除不需要的映射。这是切断源头。再搜索模型内部变量引用用Simulink.findVars或脚本检查冗余类型短名是否还被Simulink.Signal、Simulink.Parameter、Simulink.Bus引用。如果有引用把引用对象的DataType改成别的有效类型或者直接删除这些对象。没有引用之后再去AUTOSAR Dictionary里删除对应的IDT和ADT。如果字典条目还依赖CompuMethod或DataConstr也要一起确认是否保留。最后清理生成目录。把slprj下当前模型对应的生成目录删掉重新执行slbuild。不删生成目录的话某些编译器依赖的旧头文件可能会让问题看起来像没解决。这五步里第5步最容易被忽略。实际遇到的情况是字典已经干净了但slprj里还有上一次生成的Rte_Type.h构建脚本又没做全量重建结果编译器读到旧头文件报错还是同一个。这个锅不该让AUTOSAR类型系统背纯粹是构建缓存问题。4.3 重建模型字典引用的核弹级方案如果以上方法都试过冗余类型还在那就要考虑核弹级方案把词典和模型引用重建一遍。我处理过最顽固的一次最后就是靠新建字典解决的。具体做法是先把模型当前的代码映射信息导出备份然后把模型关联的.sldd解除关联新建一个空的.sldd再手动把需要的AUTOSAR数据字典配置导入回去最后重新建立Code Mappings。这种方法能把所有隐藏的残留引用一次性清掉因为新字典里只有你明确导入的类型定义没有任何历史包袱。不过这么做风险也不小。要确保导出的映射信息完整尤其是AUTOSAR字典里的CompuMethod、DataConstr、Unit、端口接口定义。操作前记得做版本控制或者导出一份完整的ARXML做备份。别把模型搞到一半回头发现丢了整套SWC接口定义。4.4 修改ARXML生成/合并方式如果你确认问题出在ARXML合并那需要从生成选项和合并策略上做文章。一般来说生成ARXML时有覆盖和合并两种模式。如果设成了合并模式Simulink会尽量保留输入ARXML里的内容旧的冗余类型自然也就被保留了。这时候要么改成覆盖模式要么先把输入模板里的旧类型删掉。如果你的构建链路里有自定义脚本比如用apply、import或merge系列命令处理ARXML那就要在脚本里加一道类型白名单过滤逻辑。可以写一个简单的文本级约束最终生成的ARXML里SHORT-NAME不能出现带_1、_2后缀的重复类型。一旦CI集成脚本发现这种迹象直接fail build这样就不会让冗余类型在项目里继续潜伏。5. 现场实录一次顽固uint16_T的完整清除过程5.1 现象现场还原回到前面说的VCU_PowerCtrl模型。我接手时集成同事反馈Rte_Type.h里重复定义了两个类型而且无论如何删除AUTOSAR Dictionary里的条目重新生成后都会复现。他们也试过在模型里搜索相关信号结果一个都搜不到所以判断是编译器或工具链bug。我第一件事不是信这个结论而是把生成后的ARXML打开用搜索功能看VoltageSensorRaw_T_1出现在哪些地方。结果发现它不仅出现在IMPLEMENTATION-DATA-TYPE的元素列表里还出现在一个CompuMethod的引用位置。说明它虽然没被端口用但被某条SW-DATA-DEF-PROPS引用着。这个引用链如果不断删IDT必然失败或重新生成。5.2 一步一步追溯引用链我先用Simulink.findVars搜索VoltageSensorRaw_T_1搜索结果只有一个指向一个数据字典里的Simulink.Parameter对象。这个参数对象叫RawVoltageScale看起来是标定量但模型里没有任何模块引用它。成了一个孤儿参数。再查RawVoltageScale是从哪里来的。发现它在.sldd里由某个初始化脚本生成脚本在模型加载时会写一堆历史标定参数其中就包括这个已经废弃的参数。因为生成脚本一直存在所以每次模型加载参数对象都会重建而Code Mappings里又有这个参数到旧IDT的映射记录。这就形成了完整的闭环加载脚本创建参数对象 → Code Mappings映射保留 → 生成器认为IDT活跃 → 生成冗余类型 → 手动删除了参数对象和映射 → 下一次加载脚本又创建。解决方式很直接在初始化脚本里删掉这段创建RawVoltageScale的代码然后从.sldd中删除该参数对象再删掉Code Mappings中对应的映射最后删除AUTOSAR Dictionary中对应的IDT和ADT。清理完之后重新生成Rte_Type.h里只剩一个VoltageSensorRaw_T。5.3 事后复盘这个案例的关键不是工具操作有多难而是排查思路要跳开模型图本身。冗余类型虽然在RTE和ARXML里表现为代码生成问题但它的生命线往往在模型外部的脚本、数据字典和工程历史里。你要做的不是硬删而是沿着类型短名→定义来源→引用来源→生成来源这条链一直追。另外这个案例还让我养成了一个习惯每次构建完成后用文本搜索对照生成文件的类型短名一旦发现_1、_2这类自动改名的类型第一时间通过构建日志定位是哪个对象引用的。不要等到集成工具报错再回头看那时上下文早丢了。6. 常见问题速查与实操心得6.1 常见问题速查表为了方便后面排查我把遇到过的典型情况整理成了一张表可以直接拿来当排查手册现象可能原因处理办法字典里删了IDT重新生成又回来Code Mappings里还残留映射打开Code Mappings删除对应数据项的映射基础工作区存在同名类型对象初始化脚本或回调函数重新创建了对象清空基础工作区加载模型检查PreLoadFcn/InitFcn端口上找不到引用但ARXML里有Simulink.Bus或Parameter对象内部引用了旧类型用Simulink.findVars和总线元素遍历定位引用生成代码目录更新后问题还在slprj里有旧缓存头文件删除生成目录全量重新构建合并后的ARXML永远有冗余类型输入模板ARXML里本来就带着旧类型删除模板中的旧类型定义或改成覆盖模式删除字典条目时报类型被引用软件组件端口/数据映射仍指向该类型删除或修改对应的映射后再删字典条目这张表里的场景不是互斥的一个项目可能同时命中好几条。排查时建议按照第4章的流程一步步来不要跳步。6.2 常规文档不会写的心得关于冗余数据类型清理我再分享几个常规文档里看不到的经验。第一删除顺序千万别反。如果你先删ADT再删IDT工具一定会报IDT还在引用ADT但如果你先删Code Mappings里的映射再删IDT最后删ADT整个过程会顺利很多。因为映射是引用链的根根被砍了下面的节点才好删。第二别动不动就批量清空字典。AUTOSAR字典里很多类型虽然当前模型没用但可能是给后面对接的BSW或标定工具预留的。我见过有人为了省事把字典里所有未引用的类型一键清掉结果下一轮集成时系统模板里引用这些类型的部分全部报错。稳妥的做法是一次只处理一个冗余类型处理完立即生成代码验证。第三善用版本控制做前后对比。清理之前先把当前版本的ARXML和Rte_Type.h提交到版本库清理并重新生成后用diff工具看差异。如果差异里干干净净只有那几个冗余类型消失说明清理成功如果发现其他类型也变了要立刻回滚审视防止误删。第四CI脚本里加一道命名后缀检查很有用。自动改名产生_1、_2后缀本身是代码生成器的一种保护机制但如果在持续集成里出现绝大多数情况下意味着有冗余或冲突。你可以在构建脚本里加入一条正则检查grep -E typedef .*_1[ ;] Rte_Type.h echo found redundant type exit 1如果构建服务器能抓到这类问题冗余类型基本活不过当天。第五遇到怎么删都删不掉的情况先怀疑外部脚本再怀疑工具bug。Simulink和AUTOSAR Blockset的字典机制总体上是可靠的但工程里各种自定义回调脚本、外部m函数、数据字典依赖关系才是真正不可控的地方。把问题定位到脚本层往往比反复在GUI里点击删除要高效得多。最后再分享一个小技巧处理完这类问题后最好顺手把模型里所有映射数据导出一份Excel或文本清单放到项目文档里。下次再有人问这个类型是干嘛的为什么不能删直接翻清单就能回答。AUTOSAR的数据类型管理说到底就是引用和语义的管理把引用理清了顽固生成的问题自然就根治了。
返回列表