ARTICLE DETAIL

资讯详情

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

【TriCore-OS】IOC

【TriCore-OS】IOC 文章目录1. IOC概念与定位1.1 与其他通信机制的对比1.2 IOC的两种工作模式2. 数据结构层级2.1 核心配置类型2.2 发送方/接收方配置2.3 数据类型支持2.4 队列节点仅Send/Receive模式3. 锁机制核间同步核心3.1 跨核锁的实现3.2 释放顺序4. 四种API接口梳理4.1 API总览4.2 公共 API 层含内存保护4.3 Write/Read 内部实现单值模式4.4 Send/Receive 内部实现队列模式4.5 队列操作的宏实现5. 跨核消息传递完整流程5.1 跨核 Send 场景时序5.2 关键设计点6. 初始化流程7. 错误码与状态机7.1 错误码定义7.2 丢失状态机1. IOC概念与定位IOCInter OS-Application Communication应用间通信 是 AUTOSAR OS 提供的轻量级数据通信机制用于在不同 OS-Application 之间含跨核的 OS-Application传递数据。1.1 与其他通信机制的对比机制适用场景是否阻塞是否跨核依赖OS资源Event同核任务间同步可阻塞否TaskIOC应用间数据传递含跨核非阻塞支持App 权限 可选 SpinlockCounter/Alarm定时触发非阻塞否CounterMessage(COM)RTE 层消息含 DLC、超时可阻塞支持COM模块IOC 的核心定位OS 层提供的、非阻塞的、支持跨核的、类型安全的数据搬运通道不依赖 RTE适合 BSW 内部或应用层直接使用。1.2 IOC的两种工作模式模式API缓冲结构场景Write/Read单值模式Os_Ioc_Write / Os_Ioc_Read单个变量缓冲dataType-buffer最新值覆盖无队列Send/Receive队列模式Os_Ioc_Send / Os_Ioc_Receive环形队列Os_QueueType_*FIFO 缓冲支持丢包标记2. 数据结构层级2.1 核心配置类型┌──────────────────────────────────────────────────────────────────┐ │Os_IocCfgType(每个 IOC 的静态配置)│ ├──────────────────────────────────────────────────────────────────┤ │ boolean sysCall 是否需走 SysCall内存保护场景 │ │ Os_IocDataType*dataType ──→{dataType,dataSize,buffer}│ │ uint8 dataTypeCnt 数据类型组数Write/Read 用 │ │ uint8 lockType IOC_LOCKTYPE_NONE/INT/INT_SPINLOCK │ │ SpinlockIdType spinlockId 跨核时用的 Spinlock ID │ │ uint32 bufferLength 队列长度 │ │ Os_IocTxCfgType*iocTxCfg ──→{accessingApps,callBack}[]│ │ uint32 senderCnt 发送方数量 │ │ Os_IocRxCfgType*iocRxCfg ──→{accessingApps}│ │ Os_IocDynType*iocDyn ────→{iocState}运行态丢失标志 │ │ IocQueueInit func 队列初始化回调NULL非队列模式 │ └──────────────────────────────────────────────────────────────────┘2.2 发送方/接收方配置Os_IocTxCfgType(每个发送方)Os_IocRxCfgType(接收方)┌──────────────────────────┐ ┌──────────────────────────┐ │ uint32 accessingApps │ │ uint32 accessingApps │ │ ReceiverPullCB callBack │ └──────────────────────────┘ └──────────────────────────┘accessingApps 是 App 位图发送/接收时 OS 会检查 OS_CORE_GETAPPID(coreId) 是否在此位图中实现访问权限控制。2.3 数据类型支持IOC_DATATYPE_BL(0)booleanIOC_DATATYPE_S8(5)sint8IOC_DATATYPE_U8(1)uint8IOC_DATATYPE_S16(6)sint16IOC_DATATYPE_U16(2)uint16IOC_DATATYPE_S32(7)sint32IOC_DATATYPE_U32(3)uint32IOC_DATATYPE_S64(8)sint64IOC_DATATYPE_U64(4)uint64IOC_DATATYPE_FL(9)float32IOC_DATATYPE_DB(10)float64IOC_DATATYPE_PTR(11)自定义结构按字节拷贝2.4 队列节点仅Send/Receive模式每种数据类型对应一个 Os_QueueType_* 结构 本质是环形队列typedefstruct{uint16 writeId;// 写位置uint16 readId;// 读位置uint16 size;// 队列容量T*data;// 数据缓冲指针}Os_QueueType_T;3. 锁机制核间同步核心IOC 的跨核同步完全依赖 Os_Ioc_Lock/ULock 的三种锁策略锁类型值适用场景实现IOC_LOCKTYPE_NONE0单核单发送方、无并发风险无锁IOC_LOCKTYPE_INT1同核多任务、单核内同步Os_Arch_IntDisable/EnableIOC_LOCKTYPE_INT_SPINLOCK2跨核场景关中断 Spinlock3.1 跨核锁的实现staticFUNC(void,OS_CODE)Os_Ioc_Lock(...){if(IOC_LOCKTYPE_INTiocCfg-lockType){Os_Arch_IntDisable(intState);// 仅关本核中断}elseif(IOC_LOCKTYPE_INT_SPINLOCKiocCfg-lockType){Os_Arch_IntDisable(intState);// 1. 先关本核中断Os_Spinlock_IntlGetSpinlock(iocCfg-spinlockId,coreId);// 2. 获取自旋锁}}为什么需要先关中断再获取 Spinlock防止本核 ISR 抢占任务后再次尝试获取同一 Spinlock 导致自死锁Spinlock 本身是跨核互斥但关中断是本核操作二者配合保证原子性3.2 释放顺序staticFUNC(void,OS_CODE)Os_Ioc_ULock(...){if(IOC_LOCKTYPE_INT_SPINLOCKiocCfg-lockType){Os_Arch_IntEnable(*intState);// 1. 先释放 SpinlockOs_Spinlock_IntlReleaseSpinlock(iocCfg-spinlockId,coreId);}elseif(IOC_LOCKTYPE_INTiocCfg-lockType){Os_Arch_IntEnable(*intState);// 2. 再开中断}}Note代码中 ULock 的 Spinlock 路径里先 IntEnable 再 ReleaseSpinlock这与 Lock 的顺序相反是有意的保证在持有 Spinlock 期间恢复中断状态避免不必要的关中断时间过长。4. 四种API接口梳理4.1 API总览API模式方向缓冲行为Os_Ioc_WriteWrite/Read发送方→缓冲覆盖最新值Os_Ioc_ReadWrite/Read缓冲→接收方读取当前值Os_Ioc_SendSend/Receive发送方→队列入队 FIFOOs_Ioc_ReceiveSend/Receive队列→接收方出队 FIFOOs_Ioc_EmptyQueueSend/Receive-清空队列Os_Ioc_Init通用-初始化Os_Ioc_ClearQueue内部-清空队列实现4.2 公共 API 层含内存保护以 Os_Ioc_Write 为例FUNC(Std_ReturnType,OS_CODE)Os_Ioc_Write(iocCfg,senderId,data){// 1. 参数检查if((NULL_PTR!iocCfg)(NULL_PTR!data)(senderIdiocCfg-senderCnt)){// 2. 内存保护场景走 SysCall#if(OS_MEMORY_PROTECTIONSTD_ON)if(TRUEiocCfg-sysCall){Os_SysCallParamType sysCallParam;sysCallParam.Os_IocWrite.iocCfgiocCfg;sysCallParam.Os_IocWrite.senderIdsenderId;sysCallParam.Os_IocWrite.datadata;Os_SysCall(Os_Syscall_IocWrite_ID,sysCallParam);// ★ 陷入内核态retsysCallParam.Os_IocWrite.retVal;}else#endif{// 3. 非内存保护或可信 App直接调用retOs_Ioc_IntlWrite(iocCfg,senderId,data);}}}SysCall 路径staticFUNC(void,OS_CODE)Os_SysCall_IocWrite(parameter){iocCfgparameter-Os_IocWrite.iocCfg;senderIdparameter-Os_IocWrite.senderId;dataparameter-Os_IocWrite.data;retOs_Ioc_IntlWrite(iocCfg,senderId,data);// 最终也调到内部函数parameter-Os_IocWrite.retValret;}为什么需要 SysCall非信任 App 访问 IOC 时IOC 缓冲区属于其他 App 或系统区需切换到特权模式才能访问共享内存。SysCall 通过 trap 指令进入特权态执行。4.3 Write/Read 内部实现单值模式Os_Ioc_IntlWrite 流程1.获取 coreId2.检查 App 权限OS_APPMATCH(accessingApps,currentAppId)├─ 不匹配 → IOC_E_NOK └─ 匹配 → 继续3.加锁Os_Ioc_Lock()4.遍历 dataTypeCnt 个数据类型 ├─ 按 dataType 分支直接赋值标量或逐字节拷贝PTR └─*buffer*dataSrc5.解锁Os_Ioc_ULock()6.返回 IOC_E_OK特点直接覆盖缓冲区最新值无队列无满/空判断适用于最新值生效的场景如传感器数据。4.4 Send/Receive 内部实现队列模式Os_Ioc_IntlSend 流程1.获取 coreId2.检查 App 权限3.加锁4.检查队列满OS_QUEUE_ISFULL()├─ 满 → retIOC_E_LIMIT,iocStateIOC_STATE_LOST ★ 标记丢失 └─ 未满 →OS_QUEUE_PUSH()5.解锁6.返回Os_Ioc_IntlReceive 流程1.获取 coreId2.检查 App 权限3.加锁4.检查丢失标志if(IOC_STATE_LOSTiocDyn-iocState)└─ retIOC_E_LOST_DATA ★ 告知接收方有数据丢失5.检查队列空OS_QUEUE_ISEMPTY()├─ 空 → retIOC_E_NO_DATA └─ 非空 →OS_QUEUE_POP()6.清除丢失标志iocStateIOC_STATE_OK ★ 一次丢失只报告一次7.解锁8.返回关键设计数据丢失检测发送满时标记 IOC_STATE_LOST接收时优先返回 IOC_E_LOST_DATA接收成功后清除标志返回值层次IOC_E_LOST_DATA(64) IOC_E_NO_DATA(131) IOC_E_OK(0)4.5 队列操作的宏实现/* 入队 */#defineOS_QUEUE_PUSH(name,value)\do{\*(name-dataname-writeId)value;\name-writeId;\if(name-writeIdname-size)\name-writeIdOS_QUEUE_INIT;/* 环形回绕 */\}while(0)/* 出队 */#defineOS_QUEUE_POP(name,value)\do{\*(value)(name-data[name-readId]);\name-readId;\if(name-readIdname-size)\name-readIdOS_QUEUE_INIT;/* 环形回绕 */\}while(0)/* 判空读写指针相等 */#defineOS_QUEUE_ISEMPTY(name)(name-readIdname-writeId)/* 判满写指针追上读指针差1 */#defineOS_QUEUE_ISFULL(name)(((readId0)(writeIdsize-1))||(readId-writeId1))环形队列容量实际可用容量 size - 1保留一个空位以区分满和空5. 跨核消息传递完整流程5.1 跨核 Send 场景时序假设Core0 的 TaskA属于 App0向 Core1 的 TaskB属于 App1发送数据。Core0(发送方)Core1(接收方)───────────── ───────────── TaskA 调用Ioc_Send(iocId,senderId,data)│ ▼Os_Ioc_Send()├─ 参数检查 ├─ sysCalltrue →Os_SysCall(IocSend_ID)│ │ │ ▼ Trap #6│Os_SysCall_IocSend()│ │ │ ▼ │Os_Ioc_IntlSend()│ ├─ App 权限检查App0 in accessingApps? │ ├─Os_Ioc_Lock()★ 关本核中断获取 Spinlock │ │ ├─Os_Arch_IntDisable()│ │ └─Os_Spinlock_IntlGetSpinlock(spinlockId,0)│ │ └─ 忙等待直到 Core1 释放若被占用 │ ├─OS_QUEUE_ISFULL()?│ │ ├─ 满 → iocStateLOST,retE_LIMIT │ │ └─ 未满 →OS_QUEUE_PUSH()★ 写入共享内存 │ └─Os_Ioc_ULock()│ ├─Os_Arch_IntEnable()│ └─Os_Spinlock_IntlReleaseSpinlock()★ 释放 Spinlock └─ 返回 TaskB 调用Ioc_Receive(iocId,data)│ ▼Os_Ioc_Receive()├─ sysCall →Os_SysCall(IocReceive_ID)│ │ │ ▼ │Os_Ioc_IntlReceive()│ ├─ App 权限检查App1 in accessingApps? │ ├─Os_Ioc_Lock()★ 关本核中断Spinlock │ ├─if(IOC_STATE_LOST)→ E_LOST_DATA │ ├─OS_QUEUE_ISEMPTY()?│ │ ├─ 空 → E_NO_DATA │ │ └─ 非空 →OS_QUEUE_POP()★ 从共享内存读 │ ├─ iocStateOK │ └─Os_Ioc_ULock()└─ 返回5.2 关键设计点共享内存要求IOC 的 buffer 必须位于多核共享的非缓存内存区OS_START_SEC_GLOBAL_NOCACHE_VAR见 Os_Ioc_Lcfg.c:48。NOCACHE 是关键若缓存Core0 写入 Core1 看不到。Spinlock 是唯一跨核同步原语IOC 跨核场景必须配置 lockType IOC_LOCKTYPE_INT_SPINLOCK复用 OS 的 Spinlock 机制之前梳理过的 Os_Spinlock 模块。非阻塞设计所有 IOC API 都不阻塞调用者发送满返回 E_LIMIT接收空返回 E_NO_DATA调用者需自行重试或处理。无主动通知IOC 不主动通知接收方有数据到达接收方需轮询或配合 Alarm/Task 周期性调用 Receive。callBack 字段虽定义但代码中未见调用属于预留接口。多发送方支持iocTxCfg[] 数组支持多个发送方每个发送方有独立权限位图和 senderId适用于多核多任务向同一 IOC 写入的发布订阅场景。6. 初始化流程主核负责初始化所有 IOC#if(OS_CFG_IOC_ENABLESTD_ON)if(TRUEcoreCfg-coreIfMaster){for(objectIdxOS_ZERO_VALUE;objectIdxIOC_CFG_COUNTER;objectIdx){Os_Ioc_Init(Os_IocCfg[objectIdx]);}}#endif1.iocStateIOC_STATE_OK// 清丢失标志2.if(func!NULL)iocInitFunc();// 队列模式调用生成的初始化函数// 设置 writeIdreadId0, size队列长度, dataBuffer7. 错误码与状态机7.1 错误码定义错误码值含义IOC_E_OK0成功IOC_E_NOK1参数错误或权限错误IOC_E_LOST_DATA64接收成功但有数据丢失过IOC_E_LIMIT130发送时队列满IOC_E_NO_DATA131接收时队列空7.2 丢失状态机Send(队列满)OK ──────────────────→ LOST ↑ │ │ │Receive(返回E_LOST_DATA后)└───────────────────────┘
返回列表