ARTICLE DETAIL

资讯详情

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

Autosar体系架构 Compiler AbstractionPostbuild注释初始化

Autosar体系架构 Compiler AbstractionPostbuild注释初始化 目录Compiler Abstraction基本定义规则不同编译器不同语法Autosar框架下软件厂商编译抽象定义对比编译器抽象语法规则解析AUTOMATICTYPEDEFNULL_PTRINLINELOCAL_INLINEFUNC(rettype, memclass)VAR(vartype, memclass)CONST(type, memclass)P2VAR(ptrtype, memclass, ptrclass)P2CONST(ptrtype, memclass, ptrclass)CONSTP2VAR(ptrtype, memclass, ptrclass)常量指针与指针常量的区别CONSTP2CONST(ptrtype, memclass, ptrclass)P2FUNC(rettype, ptrclass, fctname)CONSTP2FUNC(rettype, ptrclass, fctname)FUNC_P2CONST(rettype, ptrclass, memclass)Autosar体系框架注释规则解析Autosar体系框架初始化解析总览速查表Compiler Abstraction基本定义规则在Autosar体系框架中其中一个共同性的规则就是编译抽象(Compiler Abstraction)规则该规则首先是为了同一工程适配不同编译器所制定因为不同的编译器有着不同的语法规则所以需要在软件工程中定义关键字宏通常其定义在Compiler.h跟ComPiler_Cfg.h文件中。然后具体定义内容如下所示。/* Compiler.h —— SIP 提供的静态代码 */ # define AUTOMATIC /* 局部指针用这里展开为空 */ # define TYPEDEF /* typedef 中无法加限定符时的占位 */ # define NULL_PTR ((void *)0) # define INLINE inline # define LOCAL_INLINE static inline # define FUNC(rettype, memclass) rettype /* 函数 */ # define VAR(vartype, memclass) vartype /* 变量 */ # define CONST(type, memclass) const type /* 常量 */ # define P2VAR(ptrtype, memclass, ptrclass) ptrtype* /* 指针→变量 */ # define P2CONST(ptrtype, memclass, ptrclass) const ptrtype* /* 指针→常量 */ # define CONSTP2VAR(ptrtype, memclass, ptrclass) ptrtype* const /* 常量指针→变量 */ # define CONSTP2CONST(ptrtype, memclass, ptrclass) const ptrtype* const # define FUNC_P2CONST(rettype, ptrclass, memclass) const rettype* /* 返回常量指针的函数 */ # define P2FUNC(rettype, ptrclass, fctname) rettype (* fctname) /* 函数指针 */ # define CONSTP2FUNC(rettype, ptrclass, fctname) rettype (* const fctname)不同编译器不同语法在Autosar体系中对于常见的编译器Ghs、Tasking、等有着自己的编译器处理规则具体不同的规则表格如下所示。编译器/平台far 指针写法中断函数写法Cosmic 16位far uint8*interrupt void f(void)Tasking__far uint8*__interrupt(5) void f(void)IAR__far uint8*__irq void f(void)Green Hills ARM就是普通指针普通函数 pragma如果代码中使用一种编译器的写法当更换编译器时当前工程需要替换对应的语法位置所以使用编译抽象的规则Vector 卖 SIP 给全世界客户同一份Dem.c有人用 IAR 编 S32K有人用 Tasking 编 TC3xx有人用 GHS 编 RH850——源码必须对编译器盲差异全部收敛到Compiler.h这一个文件里。Autosar框架下软件厂商编译抽象定义对比在Autosar框架体系下的厂商软件支持这套体系架构的软件常见的厂商有Davinci、EB、Etas、Nxp、ETAS具体软件创建工程编译抽象表格如下所示。宏Vector MICROSAREB tresosNXP MCALETAS RTA-BSWFUNC#define FUNC(rettype, memclass) rettype#define FUNC(type, memclass) type#define FUNC(rettype, memclass) rettype#define FUNC(rettype, memclass) rettypeP2VARptrtype*ptrtype *ptrtype *ptrtype *P2CONSTconst ptrtype*const ptrtype *const ptrtype *const ptrtype *CONSTP2VARptrtype* constptrtype * constptrtype * constptrtype * constCONSTP2CONSTconst ptrtype* constconst ptrtype * constconst ptrtype * constconst ptrtype * constP2FUNCrettype (* fctname)rettype (*fctname)rettype (*fctname)rettype (*fctname)厂商会了满足Autosar的体系架构文档都会使用相同的定义编译抽象只是其中的一部分内容。编译器抽象语法规则解析AUTOMATIC该宏通常被填写到FUNC中的memclass中用来表示存储到局部变量的代码位置具体如下所示。# define AUTOMATIC展开空什么都没有使用位置作为其他宏的 memclass 参数出现如P2VAR(uint8, AUTOMATIC, COM_APPL_DATA)表示局部/自动存储期的对象为什么存在C 语言本来有个古老关键字auto声明局部变量但没人写它因为局部变量默认就是 auto。AUTOSAR 保留这个宏槽位是因为在某些编译器上局部指针声明需要特殊处理如分段架构上栈指针的寻址类这时AUTOMATIC就会展开成对应关键字。32 位平台上展开为空但它占据语法位置保证宏调用参数个数恒定记忆AUTOMATIC 我是局部变量/局部指针一个语义标记阅读代码时告诉你这个指针不跨函数存活TYPEDEF# define TYPEDEF展开空使用位置用在typedef语句里如typedef P2FUNC(void, RTE_APPL_CODE, Rte_CallbackType)(void);为什么存在typedef是定义新类型名不是声明变量内存限定符无处安放类型本身不在内存里实例才在。但 AUTOSAR 要求代码风格统一所以在 typedef 语句需要填一个 memclass 但又不能真填的地方用TYPEDEF占位。它是对代码读者的提示此处本应有内存类但 typedef 豁免记忆typedef 专用占位符表示这里语法上不需要限定符留个标记NULL_PTR在Autosar体系架构中会有很多代码会写空指针保护防止使用的时候会有空指针存在所以就需要在代码中检查。# define NULL_PTR ((void *)0)展开((void *)0)使用位置if (ConfigPtr NULL_PTR)、指针初始化为什么不直接用NULLC 标准库的NULL在不同编译器/不同语言模式下定义不一致——C 里通常是((void*)0)C 里是0有的嵌入式编译器定义为0L。混用会有隐患把整数 0 传给变参函数如某些回调派发时0和(void*)0在 64 位平台上占的字节数可能不同行为未定义。AUTOSAR 统一规定空指针就是((void*)0)类型安全、处处一致记忆AUTOSAR 版的 NULL_PTR永远带 void* 类型INLINE被inline声明的函数在程序内调用的时候编译器运行到这个函数时不会进行跳转而是直接将inline声明的函数直接插入这个位置而不是在进行寄存器上的记地址然后跳转地址。# define INLINE inline展开inline使用位置INLINE uint32 Com_GetSignal(void) { ... }声明内联函数为什么用宏inline是 C99 才进标准的关键字而汽车嵌入式编译器对 C 标准的支持参差不齐老编译器用__inline、_Inline有的根本不支持内联。宏让每种编译器在自己的 Compiler.h 里映射到它认识的写法不支持的编译器干脆展开为空放弃内联优化功能不变。它把优化建议与代码正确性解耦——内联失败不影响编译通过记忆跨编译器的 inline 请求LOCAL_INLINE首先static关键字本身就有只在当前.c或.h中使用生效不能够在其他.c或者.h中引用生效然后statici inline 其含义就是当前声明函数只能够在当前.c中使用使用的时候会直接将函数整体内容给插入进去。# define LOCAL_INLINE static inline展开static inline使用位置模块内部小工具函数如LOCAL_INLINE uint8 Det_GetCoreId(void) { ... }为什么单独存在一个宏static inline两个关键字的组合顺序在不同编译器上有讲究——个别编译器要求inline static有的对组合写法有警告Compiler.h 原文注释就写了 Different compilers may require a different sequence of the keywords。而且static inline的语义是文件内私有的内联函数不产生外部符号可在头文件中定义不重复与单纯inline可能产生外部链接符号链接行为不同。所以 AUTOSAR 把内联文件私有这个常用组合单独做成一个宏这种inline声明的函数适合函数内容少的函数。记忆只在当前 .c/.h 内使用的内联函数专用FUNC(rettype, memclass)该宏通常用在声明一个函数的返回值其最终是将rettype作为函数的返回值类型返回同时需要注意的是memclass这个参数也就是存储类型这个参数的代表是返回值类型存储的存储地址空间位置。# define FUNC(rettype, memclass) rettype展开返回值类型本身本平台上 memclass 空转使用示例FUNC(Std_ReturnType, PORT_CODE) Port_Init(P2CONST(Port_ConfigType, AUTOMATIC, PORT_APPL_CONST) ConfigPtr); /* 展开后: Std_ReturnType Port_Init(const Port_ConfigType* ConfigPtr); */参数rettype 返回值类型memclass 函数代码的内存类PORT_CODE决定函数链到哪个段为什么这样设计函数声明里需要挂载的东西调用约定__near_func、中断属性、段放置 pragma在返回值类型前后的插入位置随编译器而变手写无法跨平台。用宏把返回值托底memclass 槽位留给各编译器的 Compiler.h 填扩展。同时 memclass 最终通过 MemMap.h 的段 pragma 生效——PORT_CODE段的函数统一链到 Flash 的 PORT 代码区注意它是 AUTOSAR BSW 里出现频率最高的宏几乎每个函数声明都用VAR(vartype, memclass)该宏通常和Memmap.h声明机制一起使用需要注意的是宏定义函数中的memclass 这个参数通常 是变量存储位置但是这个参数是显示声明只是告诉阅读的人放在什么位置通常也就是不是实际 执行者。# define VAR(vartype, memclass) vartype展开变量类型本身使用示例VAR(uint8, DIO_VAR_NOINIT) Dio_u8ChannelStatus; /* 展开: uint8 Dio_u8ChannelStatus; */ VAR(uint16, AUTOMATIC) u16Counter; /* 函数内局部变量 */然后是搭配Memmap.h机制使用的代码内容其中Start and Stop宏才是真正决定这个代码存放到那个段的实际生效机制Memmclass只是一个显示声明。#define DIO_START_SEC_CONFIG_DATA_UNSPECIFIED /* ① 段开关: 打开 */ #include Dio_MemMap.h extern CONST(Dio_ConfigType, DIO_CONST) Dio_ConfigPC; /* ② 声明宏: 贴标签 */ #define DIO_STOP_SEC_CONFIG_DATA_UNSPECIFIED /* ③ 段开关: 关闭 */ #include Dio_MemMap.h参数vartype 变量类型memclass 变量内存类——这是 VAR 的灵魂常见取值XXX_VAR_NOINIT不初始化区复位后保留值供 Dem 存故障、EcuM 存唤醒源用XXX_VAR_ZERO_INIT启动时清 0 区XXX_VAR_INIT带初值区XXX_VAR_PBCFGPostBuild 可重刷区XXX_VAR_UNCACHED绕过 cacheDMA 共用缓冲区必须为什么这样设计变量放哪在汽车 ECU 上极其讲究Noinit RAM 掉电保留、DMA 区域、核间共享区且每种放法的编译器写法不同#pragma、段属性__attribute__((section))、near/far 寻址。宏把这层差异全部吸收记忆VAR 这是个需要内存布局管理的变量CONST(type, memclass)该宏通常和Memmap.h声明机制一起使用需要注意的是宏定义函数中的memclass 这个参数通常是变量存储位置但是这个参数是显示声明只是告诉阅读的人放在什么位置通常也就是不是实际执行者。# define CONST(type, memclass) const type需要注意的是宏定义函数后面是多定义了一个const的展开const 类型使用示例CONST(uint16, PORT_CONST) Port_au16PinDescription[8][10] { ... }; /* 展开: const uint16 Port_au16PinDescription[8][10] {...}; */参数type 常量类型memclass 常量内存类XXX_CONST放普通 Flash 常量区、XXX_CONST_PBCFG放 PostBuild 可重刷 Flash 区为什么这样设计这里的const不只是只读语义——在汽车 ECU 上它物理上决定数据烧进 Flash 而非占用 RAM。CONST宏把这个意图显式化同时 memclass 让不同常量可以进不同的 Flash 分区普通配置 vs 可单独重刷的 PB 配置区记忆CONST 烧进 Flash 的只读数据P2VAR(ptrtype, memclass, ptrclass)该类型是声明一个函数指针然后P2是point to的缩写因为2与to谐音所以这里宏的名字就能够理解为指针指向变量后面的所有带P2缩写的编译器抽象都能够这么理解。# define P2VAR(ptrtype, memclass, ptrclass) ptrtype*展开类型*普通可变指针使用示例P2VAR(uint8, AUTOMATIC, DIO_APPL_DATA) Dio_pu8Buffer; /* 展开: uint8* Dio_pu8Buffer; —— 指针和内容都可改 */三个参数ptrtype 指向的类型memclass指针变量自己放哪段 RAMptrclass 指针的寻址距离类near/far16 位平台上展开为__far等关键字典型用途模块的输出参数Dio_ReadChannelGroup的结果缓冲区指针、运行期数据指针记忆两头都在 RAM完全可读写P2CONST(ptrtype, memclass, ptrclass)常量指针类型该宏首先名字是P2CONST就是声明一个常量指针具体原型如下所示。# define P2CONST(ptrtype, memclass, ptrclass) const ptrtype*展开const 类型*指向只读数据的可变指针使用示例你工程里最眼熟的FUNC(void, PORT_CODE) Port_Init(P2CONST(Port_ConfigType, AUTOMATIC, PORT_APPL_CONST) ConfigPtr); /* 展开: void Port_Init(const Port_ConfigType* ConfigPtr); */ /* 语义: Init 收到的配置表在Flash里,函数只许读;但允许换一张表传进来 */典型用途Init 函数的配置指针、只读输入缓冲区。这是整个 AUTOSAR 里第二高频的宏——配置在 Flash指针作参数传入是 AUTOSAR 所有模块 Init 的统一模式PostBuild 换配置不换代码换数据正靠指针可变、内容只读这个性质记忆RAM 里的指针 → Flash 里的数据CONSTP2VAR(ptrtype, memclass, ptrclass)指针常量在声明之后指向的内容是不能够更换的但是指向的地址中的内容能够进行修改然后指针常量、常量指针的作用是相反的。# define CONSTP2VAR(ptrtype, memclass, ptrclass) ptrtype* const展开类型* const指针本身烧死、指向内容可写使用示例CONSTP2VAR(uint8, DCM_CONST, DCM_APPL_DATA) Dcm_pu8TxBuffer Dcm_au8Buffer[0]; /* 展开: uint8* const Dcm_pu8TxBuffer ...; */ /* 语义: 这个指针永远指向那块发送缓冲区(指针在Flash不可改),但缓冲区内容(RAM)随便写 */典型用途固定绑定某块 RAM 缓冲区的句柄、安全关键场景禁止指针被篡改指针放 Flash运行期无法被跑飞的代码改写指向——这是功能安全手段记忆Flash 里的指针 → RAM 里的数据常量指针与指针常量的区别const ptrtype* p1; /* const 在 * 左边: 指向常量的指针 */ ptrtype* const p2; /* const 在 * 右边: 常量指针 */用从右往左读的方法翻译声明从右往左读指针本身能改指向通过它改内容const ptrtype* p1p1 是指针 → 指向constptrtype✅ 可以❌ 不行ptrtype* const p2p2 是const指针 → 指向 ptrtype❌ 不行✅ 可以uint8 bufferA[4] {0}; uint8 bufferB[4] {0}; /* ---- const ptrtype* : 内容被锁, 指针自由 ---- */ const uint8* p1 bufferA; p1 bufferB; /* ✅ 合法: 改指到别处 */ p1[0] 0x55; /* ❌ 编译错误: 不许通过它改内容 */ /* ---- ptrtype* const : 指针被锁, 内容自由 ---- */ uint8* const p2 bufferA; p2 bufferB; /* ❌ 编译错误: 指针被钉死, 不许改指 */ p2[0] 0x55; /* ✅ 合法: 内容随便写 */const 修饰谁谁就不能动const 挨着类型名星号左锁内容挨着变量名星号右锁指针。CONSTP2CONST(ptrtype, memclass, ptrclass)双重Const修饰该编译器抽象宏分别使用双const修饰变量与修饰指针名字按照const修饰谁谁就不能变的规则该指针中的内容、取地址都是不能变的其中的内容不能变指针指向也是不能变。# define CONSTP2CONST(ptrtype, memclass, ptrclass) const ptrtype* const展开const 类型* const两头全部钉死使用示例配置表内部的指针成员就是这个/* Port_PBcfg.c 里 PortConfigSet 结构体的表指针, 整块在Flash */ static CONST(Port_Port_Ci_PinConfigType, PORT_CONST) Port_aPinConfigDefault[...] {...}; /* 结构体里的: P2CONST(...) pUsedPadConfig —— 配置实例若整体const, 该成员实际等效于 */ /* const Port_Port_Ci_PinConfigType* const —— 指针和内容都不可改 */典型用途Flash 里的查找表/跳转表中的指针项、ROM 化配置结构体成员。整个配置树结构体表表内指针全部烧死在 Flash一个字节的 RAM 都不占——这正是 AUTOSAR 配置数据结构的默认形具体理解可以参考下面的结构图。CONSTP2CONST(uint8, DIO_CONST, DIO_APPL_CONST) Dio_pu8RomTable Dio_au8Cfg[0]; const uint8* const Dio_pu8RomTable Dio_au8Cfg[0]; const uint8 * const Dio_pu8RomTable Dio_au8Cfg[0]; │ │ │ │ │ └─ 初始化: 指向配置表首地址 │ │ │ │ └─ 变量名 │ │ │ └─ const#2: 在 * 右边 → 锁住【指针本身】, 永远指向这张表 │ │ └─ 指针声明符 │ └─ 指向的数据类型 └─ const#1: 在 * 左边 → 锁住【指向的内容】, 表里的数据只读P2FUNC(rettype, ptrclass, fctname)该编译器抽象宏返回的是函数指针类型因为该宏返回的是函数指针类型后面是没有变量参数的通常后面还要跟VAR类型然后形成一个完整的函数指针然后具体原型如下所示。# define P2FUNC(rettype, ptrclass, fctname) rettype (* fctname)展开返回类型 (* 名字)—— 注意这个宏把函数名也吃进去当参数使用示例P2FUNC(void, RTE_APPL_CODE, Rte_Notification) (void); /* 展开: void (* Rte_Notification) (void); —— 一个函数指针变量 */ typedef P2FUNC(void, CANIF_APPL_MSG_CODE, CanIf_TxConfirmationFctType) (VAR(PduIdType, AUTOMATIC) CanTxPduId); /* 展开: void (* CanIf_TxConfirmationFctType) (PduIdType CanTxPduId); 一个函数指针类型名因为是typedef定义的所以可以通过该类型名来声明相同类型的变量 */ typedef P2FUNC(void, CAN_APPL_CODE, Can_TxCbkType) (PduIdType); /* typedef 场景: void (* Can_TxCbkType) (PduIdType); 定义了回调类型 */为什么必须把名字做成参数C 的函数指针语法要求名字嵌在(* ... )中间。16 位平台上 far 关键字要插到星号旁边rettype (__far *name)(args)且插入点随编译器变。只有让宏吞下函数名各编译器的 Compiler.h 才能自由编排关键字/星号/名字三者的顺序典型用途RTE 的通知回调、Det 的错误钩子、所有用户注册回调给 BSW的场景记忆声明一个可以换指向的函数指针变量/类型CONSTP2FUNC(rettype, ptrclass, fctname)该编译器抽象宏以为是const修饰的是右边的变量名所以在实际运用的过程中变量名指向的变量中的内容是不能被改变的。# define CONSTP2FUNC(rettype, ptrclass, fctname) rettype (* const fctname)展开返回类型 (* const 名字)—— 指针本身 const 的函数指针使用示例CONSTP2FUNC(void, CAN_APPL_CODE, CanIf_TxConfirmationTable[8]) { Can_TxConf_0, ... }; /* 展开: void (* const CanIf_TxConfirmationTable[8]) {...}; */ /* 语义: 一张烧死在Flash里的回调跳转表, 运行期谁也改不了表项 */典型用途ROM 化跳转表/回调表——配置阶段确定的回调关系表项烧进 Flash。防止运行期函数指针被改写堆栈溢出、恶意注入都改不动同样是功能安全和信息安全的设计记忆Flash 里的函数跳转表FUNC_P2CONST(rettype, ptrclass, memclass)该编宏因为const修饰的是左边类型名所以该类型名实际指向的函数内容是不能够被改变的但是函数中的内容能够被改变。# define FUNC_P2CONST(rettype, ptrclass, memclass) const rettype*展开const 返回类型*—— 这是函数声明不是指针函数返回值是指向常量的指针使用示例FUNC_P2CONST(uint8, DCM_APPL_CONST, DCM_CODE) Dcm_GetRxBuffer(void); /* 展开: const uint8* Dcm_GetRxBuffer(void); */ /* 语义: 一个函数, 返回指向只读缓冲区的指针; 函数代码本身属于 DCM_CODE 段 */与 P2FUNC 的本质区别FUNC_P2CONST后面跟名字(参数)声明的是函数P2FUNC的fctname嵌在星号括号里声明的是指针。看展开式里有没有(*就能区分为什么需要宏返回指针的函数其 ptrclass 关键字要插在const rettype和*之间的特定位置各编译器不同手写不可移植规范里 Cosmic S12X 的例子展开为ptrclass rettype* memclass关键字全插进来了Autosar体系框架注释规则解析在Autosar体系框架中所有的代码注释都是/* */类型注释没有//类型注释其因为编译器不支持具体原因如下所示。/* ... */块注释——C90ISO/IEC 9899:1990即 ANSI C就有的语法//行注释——C99 才进入 C 标准此前是 C 的语法C 编译器只当厂商扩展支持当编译器被设置为严格 C90/ANSI 模式IAR 的--strict、Green Hills 的-ansi、Tasking 的--iso90、Keil 的--c90//就是非法 token直接报语法错误。因为在Autosar框架体系中要求所有的编译器的规范要求是所有BSW的代码要符合MISRA-C所以对应编译器就有限制然后在到代码中的限制。AUTOSAR 通用规范 (SWS_BSW_General / SRS_BSW) ↓ 要求: 所有 BSW 代码必须符合 MISRA-C MISRA-C:2004 Rule 1.1 (Required 级) ↓ 要求: 所有代码必须符合 ISO 9899:1990 (C90) 及其技术勘误 // 行注释不属于 C90 ↓ 违反 Rule 1.1 → 严格模式下编译报错 / 静态检查(QAC, Polyspace)判违规* Project : AUTOSAR 4.2 MCAL * Platform : ARM * Peripheral : GPIO * Autosar Version : 4.2.2 * SW Version : 1.0.1 * Build Version : S32K14x_MCAL_1_0_1_RTM_ASR_REL_4_2_REV_0002_20180713 * (c) Copyright 2006-2016 Freescale Semiconductor, Inc.这个文件的身份证。报 bug 给供应商时必须附上 Build VersionAutosar Version用于版本一致性检查你之前文档第 4 章学的#error Version Numbers are different核对的就是这套号的代码化版本。版权行是法律要求OEM 审核必查。* brief DIO channel level validation. * details Checks if the specified channel level is valid... * param[in] Level channel level parameter to be checked * return Std_ReturnType * pre p Port_Init() must have been called first. * api * implements Dio_HLD_unit标签含义brief/details一句话功能 / 详细描述param[in][out][in,out]参数及数据流向return返回值pre/post前置条件 / 后置条件如必须先调 Initapi标记这是 AUTOSAR 标准 API对应 SWS 文档条目implements追溯标记声明这段代码实现了哪个设计工件/需求条目addtogroup文档分组由Doxygen工具解析自动生成 HTML/PDF 模块文档。写法必须是/** ... */两个星号开头普通/* */Doxygen 会忽略——所以你能从注释开头判断它是不是文档注释。这是最容易看懵的一类它是文件头登记 现场指认的配套结构第一步文件头里登记违规清单* section Dio_Cfg_C_REF_1 * Violates MISRA 2004 Required Rule 1.4, The compiler/linker shall be * checked to ensure that 31 character significance... * The used compilers/linkers allow more than 31 characters...第二步在违规律代码现场打上回指标记#define DioConf_DioChannel_DioChannel_PTD16 ((uint16)0x0070U) /** violates ref Dio_Cfg_C_REF_1 The used compilers use more than 31 chars for identifiers. */这里我违反了 MISRA 规则 X违规编号Dio_Cfg_C_REF_1理由已在文件头登记。为什么要自首MISRA 允许少数 Required 规则偏离但前提是书面登记理由。静态检查工具QAC/Polyspace扫到这个标记就知道此处违规已备案不再报警审核人员拿着编号去文件头查理由。这是 ASPICE/功能安全流程的强制动作。# define FUNC(rettype, memclass) rettype /* PRQA S 3410 */ /* MD_Compiler_19.10 */ # define STATIC static /* PRQA S 3453 COMPILER_3453_TAG */ /* MD_MSR_19.7 */PRQA S 3410QACPerforce 出品的 MISRA 检查器PRQA 是公司旧名的告警编号。含义本行屏蔽 QAC 第 3410 号告警宏参数未加括号。QAC 扫到这行注释就跳过该告警MD_xxxMISRADeviationVector 的违规编号体系。MD_Compiler_19.10 本文件对 MISRA 规则 19.10 的偏离配套在供应商的偏离报告里登记MD_MSR_19.7 对规则 19.7该用函数而非函数式宏的偏离这类注释是工具指令人看不懂很正常——查 QAC 手册的告警号表才能知道具体含义。/* ##V_CFG_MANAGEMENT ##CQProject : CommonAsr_Arm32 CQComponent : Impl_CompAbstract_GreenHills */这是 Vector 内部配置管理系统类似 ClearCase/Synergy 的关键词展开的组件身份标记声明这个文件属于CommonAsr_Arm32 项目的 Impl_CompAbstract_GreenHills 组件。DaVinci/SIP 升级工具靠它识别这个文件属于哪个组件、升级时能不能安全替换。永远不要手改或删除否则 SIP 版本升级会合并冲突。Autosar体系框架初始化解析Autosar体系框架内中对于代码的初始化与配置都是有着固定的初始化结构的对于Autosar体系中的模块初始化配置模型(Module Initialization Configuration),称为ConfigPtr模式/根指针模式其对应的要求分别为。SRS_BSW_00414每个 BSW 模块的 Init 函数必须接收一个指向配置结构的指针——Xxx_Init(const Xxx_ConfigType* ConfigPtr)配置根Configuration Root那个被的全局结构体是 ECUC 里XxxConfigSet容器生成的配置树根节点NXP MCAL 里叫Xxx_PBCfgVariantPredefinedVector 里常叫Xxx_Config模块级全局配置指针Init 把指针存进模块全局变量之后所有 API 只通过它间接访问配置——这就是配置三种变体PreCompile / LinkTime /PostBuild能成立的机制基础Autosar工程代码中首先是声明全局配置指针。P2CONST(Port_ConfigType, PORT_VAR, PORT_APPL_CONST) Port_pConfig NULL_PTR; /* 指向配置根的全局指针, 初始为 NULL —— NULL 本身就是模块未初始化的状态标记 */然后在工程中地址root配置结构体将结构体中的配置数据存放到init结构体指针中进行使用。#if (STD_ON PORT_PRECOMPILE_SUPPORT) ConfigPtr Port_PBCfgVariantPredefined; /* ← 你说的那个写法 */ #endif Port_Ipw_Init(ConfigPtr); /* Save configuration pointer in global variable */ Port_pConfig ConfigPtr; /* 存进全局, 供后续所有API使用 */在程序中判断Init结构体中对应的参数通过判断参数的数据类型来选择是否出发配置。if (NULL_PTR Port_pConfig) /* 用指针判未初始化 → DET */ { (void)Det_ReportError(..., PORT_E_UNINIT); } else if (Pin (Port_PinType)Port_pConfig-u16NumPins) /* 用配置里的引脚总数做边界检查 */ { (void)Det_ReportError(..., PORT_E_PARAM_PIN); } else { ErrStatus Port_Ipw_SetPinDirection(Pin, Direction, Port_pConfig); /* 一路传给硬件层 */ }总览速查表宏展开形态声明对象一句话AUTOMATIC空占位局部对象标记TYPEDEF空占位typedef 豁免标记NULL_PTR((void*)0)常量类型安全的空指针INLINEinline函数修饰跨编译器内联请求LOCAL_INLINEstatic inline函数修饰文件私有内联FUNCrettype函数挂载代码段/调用约定VARtype变量挂载 RAM 分区CONSTconst type常量烧进 FlashP2VART*数据指针RAM→RAMP2CONSTconst T*数据指针RAM→FlashInit 配置指针CONSTP2VART* const数据指针Flash→RAM钉死句柄CONSTP2CONSTconst T* const数据指针Flash→FlashROM 配置树P2FUNCret (*name)函数指针可换指向的回调CONSTP2FUNCret (* const name)函数指针Flash 跳转表FUNC_P2CONSTconst ret*函数返回指针返回只读缓冲区的函数希望对你有所帮助
返回列表