VSOA AUTOSAR 简介
VSOA AUTOSAR 是 VSOA 针对汽车开放系统架构 AUTOSAR Classic Platform 推出的专用版本。
开发须知
AUTOSAR CP 使用的是非标准 socket 接口,采用标准 socket 接口开发的 VSOA 不能在 AUTOSAR CP 中运行,因此翼辉推出了 AUTOSAR CP 专用的 VSOA 版本。
基于 AUTOSAR CP 版本开发的 VSOA 服务端、客户端等可以与标准版本 VSOA 实现的客户端、服务端互联互通。在 VSOA AUTOSAR 中,也可支持客户端机器人、Stream、Datagram 等 VSOA 特有的高级功能。
环境搭建
本节以开源的 Tramponline AUTOSAR 为例,讲解 VSOA AUTOSAR 的使用。
AUTOSAR 对象
为了方便 VSOA AUTOSAR 在不同 AUTOSAR 版本上的使用,VSOA AUTOSAR 提供了便于移植的 vsoa_as_porting 实现,该实现可方便的将 VSOA AUTOSAR 使用的对象与 AUTOSAR 系统资源关联。
Task
在 VSOA AUTOSAR 中,需要新建至少两个 Task。其中一个用于执行 VSOA AUTOSAR 所需的定时器循环,另一个用于执行 VSOA 服务端或客户端的业务逻辑。
注意:
VSOA AUTOSAR 使用的 Task 因使用到了 Event,所以必须配置为 Extend Task。
Resource
在 VSOA AUTOSAR 中,使用 Resource 进行互斥访问,在 AUTOSAR 中提供了如下的接口进行 Resource 的获取和释放:
FUNC(StatusType, OS_CODE) GetResource(CONST(ResourceType, AUTOMATIC) res_id);
FUNC(StatusType, OS_CODE) ReleaseResource(CONST(ResourceType, AUTOMATIC) res_id);
访问临界区前调用 GetResource
获取该资源,临界区访问结束后调用 ReleaseResource
释放该资源。
Alarm
在 VSOA AUTOSAR 中,使用到 Alarm 作为定时器以及超时触发 Event 的功能。
Event
在 VSOA AUTOSAR 中,使用 Event 实现信号量功能。Event 会配合 Alarm 使用,相关函数如下:
函数 | 功能 |
---|---|
ClearEvent | 清空 Event |
SetRelAlarm | 设定一个 Alarm 到期时设置 Event |
WaitEvent | 等待 Event |
CancelAlarm | 取消 Alarm |
因为 WaitEvent
结束等待的情况有如下两种:
- 其他 Task 调用 SetEvent 设置该 Event;
- Alarm 到期设置该 Event。
基于以上的逻辑,相当于使用 Alarm 搭配 Event 实现了一个信号量超时等待的功能。
VSOA 初始化
初始化函数
VSOA AUTOSAR 提供了一个统一的系统初始化函数 vsoa_init
,该函数应当在任何 VSOA 函数被调用前优先执行。需注意该初始化函数只能被调用一次,该函数原型如下:
vsoa_init_res_t *vsoa_init(vsoa_init_arg_t *arg);
该初始化函数传入的参数类型如下,其中每一个变量都是 VSOA 运行所需 AUTOSAR 提供的一类系统资源,包括内存、事件管理、定时器、错误号等。
typedef struct {
/* cannot be less than VSOA_MIN_MEM_POOL_SZ */
void *mem_start;
size_t mem_length;
/* The following members must valid */
vsoa_mem_osl_t *mem_osl;
vsoa_event_osl_t *event_osl;
vsoa_timer_osl_t *timer_osl;
vsoa_server_svc_osl_t *server_osl;
vsoa_client_svc_osl_t *client_osl;
/* The following members are optional */
vsoa_errno_osl_t *errno_osl;
} vsoa_init_arg_t;
当初始化函数执行成功时,其将返回一个非空的函数指针,该函数指针需要放入一个独立的 Task 中运行,返回值类型如下:
typedef struct {
void (*timer_loop)(void);
} vsoa_init_res_t;
初始化示例
在 AUTOSAR 系统中建立一个名为
demo_task
的 Task,其 ID 指定为demo_task_id
。该 Task 同时需要关联 ID 为demo_task_alarm_id
的 Alarm 和 demo_task_timeout_mask 的Alarm Event,该 Alarm 到期后触发demo_task_timeout_mask
的 Event 唤醒 demo_task。在该 Task 中调用 vsoa_as_porting 实现的vsoa_as_task_register
接口,注册该 Task。说明:
Task ID、Alarm ID 和 Event Mask 的定义方式不同的 AUTOSAR 版本略有差异,通常通过工具或脚本的方式自动生成。
/* * 使用 VSOA 的任务需要定义一个 vsoa_as_task_t, 并使用 vsoa_as_task_register 注册 */ static vsoa_as_task_t vsoa_as_demo_task = { .task_id = demo_task_id, .alarm = demo_task_alarm_id, .alarm_event = demo_task_timeout_mask }; TASK(demo_task) { /* * 注册任务 */ vsoa_as_task_register(&vsoa_as_demo_task); }
在该 Task 中调用
vsoa_init
进行 VSOA AUTOSAR 的初始化。/* * VSOA 初始化参数与返回值 */ static vsoa_init_arg_t vsoa_init_arg = { .mem_start = vsoa_mem, .mem_length = VSOA_MEM_SIZE, .mem_osl = &vsoa_mem_osl, .timer_osl = &vsoa_as_timer_osl, .event_osl = &vsoa_as_event_osl, .server_osl = &vsoa_server_svc_osl, .client_osl = &vsoa_client_svc_osl, .errno_osl = &vsoa_errno_osl }; static vsoa_init_res_t *vsoa_init_res = NULL; /* * 使用 VSOA 的任务需要定义一个 vsoa_as_task_t, 并使用 vsoa_as_task_register 注册 */ static vsoa_as_task_t vsoa_as_demo_task = { .task_id = demo_task_id, .alarm = demo_task_alarm_id, .alarm_event = demo_task_timeout_mask }; TASK(demo_task) { /* * 注册任务 */ vsoa_as_task_register(&vsoa_as_demo_task); /* * 初始化 VSOA */ vsoa_init_res = vsoa_init(&vsoa_init_arg); while (1) { vsoa_init_res->timer_loop(); } TerminateTask(); }
完成
vsoa_init_arg
中内存资源的定义。其中vsoa_mem_osl
需要关联一个 ID 为vsoa_mem_lock_id
的 Resource 作为内存资源访问时的互斥控制。/* * VSOA 内存大小 */ #define VSOA_MEM_SIZE 256 * 1024 /* * 一个 vsoa_mem_osl_t 实现, 需要一个 Resource 作为 mutex */ static vsoa_mem_osl_t vsoa_mem_osl = { .ctx = (void *)(long)vsoa_mem_lock_id, .lock = vsoa_as_mem_lock, .unlock = vsoa_as_mem_unlock }; /* * VSOA memory */ static uint8_t vsoa_mem[VSOA_MEM_SIZE];
完成
vsoa_init_arg
中定时器资源的定义。其中vsoa_as_timer_ctx
需要关联一个 ID 为vsoa_timer_lock_id
的 Resource 作为定时器资源访问时的互斥控制,需要关联一个名为vsoa_timer_sem_event_mask
的 Event Mask 作为信号量使用。/* * 一个 vsoa_timer_osl_t 实现, 需要一个 vsoa_as_timer_ctx_t, * vsoa_as_timer_ctx_t 需要一个 Resource 和 Event 分别作 mutex 和 semaphore */ static vsoa_as_timer_ctx_t vsoa_as_timer_ctx = { .mutex = vsoa_timer_lock_id, .event = vsoa_timer_sem_event_mask, }; static vsoa_timer_osl_t vsoa_as_timer_osl = { .ctx = &vsoa_as_timer_ctx, .lock = vsoa_as_timer_lock, .unlock = vsoa_as_timer_unlock, .wait = vsoa_as_timer_wait, .post = vsoa_as_timer_post, .curtime = vsoa_as_timer_curtime };
完成
vsoa_init_arg
中事件管理资源的定义。其中vsoa_as_event_ctx
需要关联一个 ID 为vsoa_event_lock_id
的 Resource 作为事件管理资源访问时的互斥控制,需要关联一个名为vsoa_event_sem_event_mask
的 Event Mask 作为信号量使用。/* * 一个 vsoa_event_osl_t 实现, 需要一个 vsoa_as_event_ctx_t, * vsoa_as_event_ctx_t 需要一个 Resource 和 Event 分别作 mutex 和 semaphore */ static vsoa_as_event_ctx_t vsoa_as_event_ctx = { .mutex = vsoa_event_lock_id, .event = vsoa_event_sem_event_mask }; static vsoa_event_osl_t vsoa_as_event_osl = { .ctx = &vsoa_as_event_ctx, .lock = vsoa_as_event_lock, .unlock = vsoa_as_event_unlock, .wait = vsoa_as_event_wait, .post = vsoa_as_event_post, };
完成
vsoa_init_arg
中内建服务器管理资源的定义,该内建服务器管理结构用于管理 VSOA AUTOSAR 创建的服务器。其中vsoa_server_svc_osl
需要关联一个 ID 为vsoa_server_svc_lock_id
的 Resource 作为内建服务器管理资源访问时的互斥控制。/* * 一个 vsoa_server_svc_osl_t 实现, 需要一个 Resource 作为 mutex */ static vsoa_server_svc_osl_t vsoa_server_svc_osl = { .ctx = (void *)(long)vsoa_server_svc_lock_id, .lock = vsoa_as_server_svc_lock, .unlock = vsoa_as_server_svc_unlock };
完成
vsoa_init_arg
中内建客户端管理资源的定义,该内建客户端管理结构用于管理 VSOA AUTOSAR 创建的客户端。其中vsoa_client_svc_osl
需要关联一个 ID 为vsoa_client_svc_lock_id
的 Resource 作为内建客户端管理资源访问时的互斥控制。/* * 一个 vsoa_client_svc_osl 实现, 需要一个 Resource 作为 mutex */ static vsoa_client_svc_osl_t vsoa_client_svc_osl = { .ctx = (void *)(long)vsoa_client_svc_lock_id, .lock = vsoa_as_client_svc_lock, .unlock = vsoa_as_client_svc_unlock };
完成
vsoa_init_arg
中错误码管理资源的定义。/* * 一个 vsoa_errno_osl_t 实现 */ static vsoa_errno_osl_t vsoa_errno_osl = { .get = vsoa_as_errno_get, .set = vsoa_as_errno_set };
说明:
以上
vsoa_as_mem_lock
等接口实现,可参考 VSOA AUTOSAR 资料中的 "vsoa_as_porting.c" 等文件。