VSOA AUTOSAR 服务端
本节内容介绍 VSOA AUTOSAR 服务端开发方法。
开发须知
- VSOA AUTOSAR 服务端需以一个独立 Task 的方式运行,且因该 Task 使用到 AUTOSAR Event 资源,需配置为 Extend Task。
- 在 VSOA AUTOSAR 服务端运行前,需完成 VSOA 初始化流程。
开发示例
步骤 1:初始化 VSOA
参考 VSOA 初始化 建立执行 VSOA 定时器的 Task,在此例中可将该 Task 命名为 timer_task
:
/*
* 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_timer_task = {
.task_id = timer_task_id,
.alarm = timer_task_alarm_id,
.alarm_event = timer_task_timeout_mask
};
TASK(timer_task) {
/*
* 注册任务
*/
vsoa_as_task_register(&vsoa_as_timer_task);
/*
* 初始化 VSOA
*/
vsoa_init_res = vsoa_init(&vsoa_init_arg);
while (1) {
vsoa_init_res->timer_loop();
}
TerminateTask();
}
步骤 2:新建 Server Task
新建
vsoa_server_task
,在该 Task 中需等待 VSOA 初始化完成。Server Task 需要与一个 Alarm 关联,该 Alarm 用于该 Task 中的信号量超时等操作。/* * 使用 VSOA 的任务需要定义一个 vsoa_as_task_t, 并使用 vsoa_as_task_register 注册 */ static vsoa_as_task_t vsoa_server_task = { .task_id = vsoa_server_task_id, .alarm = vsoa_server_task_alarm_id, .alarm_event = vsoa_server_task_timeout_mask, }; TASK(vsoa_server_task) { /* * 注册任务 */ vsoa_as_task_register(&vsoa_server_task); /* * 等待 VSOA 初始化完成 */ while (!vsoa_init_res) { vsoa_as_task_sleep(ONE_MS); } TerminateTask(); }
在
vsoa_server_task
中创建 VSOA 服务端。与标准 VSOA 不同在于 VSOA AUTOSAR 版本的vsoa_server_create
需要多传入一个vsoa_server_osl_t
类型的参数,该参数中定义了 Server Task 所需的 Resource 与 Event 资源。/* * 一个 vsoa_server_osl_t 实现, 需要一个 vsoa_as_server_ctx_t, * vsoa_as_server_ctx_t 需要一个 Resource 和 Event 分别作 mutex 和 semaphore */ static vsoa_as_server_ctx_t my_server_ctx = { .event = my_server_event_mask, .mutex = my_server_lock_id }; static vsoa_server_osl_t my_server_osl = { .ctx = &my_server_ctx, .lock = vsoa_as_server_lock, .unlock = vsoa_as_server_unlock, .wait = vsoa_as_server_wait, .post = vsoa_as_server_post, .sleep = vsoa_as_server_sleep }; /* My server type */ typedef struct { vsoa_server_t *server; struct data data; } my_server_t; /* My server */ static my_server_t my_server; /* My server password */ #define MY_SERVER_PASSWD "123456" /* * 使用 VSOA 的任务需要定义一个 vsoa_as_task_t, 并使用 vsoa_as_task_register 注册 */ static vsoa_as_task_t vsoa_server_task = { .task_id = vsoa_server_task_id, .alarm = vsoa_server_task_alarm_id, .alarm_event = vsoa_server_task_timeout_mask, }; TASK(vsoa_server_task) { /* * 注册任务 */ vsoa_as_task_register(&vsoa_server_task); /* * 等待 VSOA 初始化完成 */ while (!vsoa_init_res) { vsoa_as_task_sleep(ONE_MS); } /* * 创建 VSOA server */ my_server.server = vsoa_server_create(&my_server_osl, "{\"name\":\"C language VSOA server\"}"); /* * 设置 VSOA server 密码 */ #ifdef MY_SERVER_PASSWD vsoa_server_passwd(my_server.server, MY_SERVER_PASSWD); #endif TerminateTask(); }
步骤 3:增加 RPC 、发布等业务
同标准 VSOA 的使用方式,可以对客户端的连接情况进行监控,可以增加 RPC 监听。
TASK(vsoa_server_task) { …… /* * 创建 VSOA server */ my_server.server = vsoa_server_create(&my_server_osl, "{\"name\":\"C language VSOA server\"}"); vsoa_server_on_cli(my_server.server, on_client, NULL); /* * VSOA server add listener */ vsoa_url_t url; url.url = "/foo"; url.url_len = strlen(url.url); vsoa_server_add_listener(my_server.server, &url, command_foo, NULL); TerminateTask(); }
同标准 VSOA 的使用方式,可以使用 VSOA Timer 定期进行 “发布” 或 “快速发布” 操作。
static void qpub_timer_handler(void *arg, vsoa_timer_t *timer, void *custom) { vsoa_url_t url; vsoa_payload_t payload; url.url = "/foo"; url.url_len = strlen(url.url); if (!vsoa_server_is_subscribed(my_server.server, &url)) { return; } payload.data = NULL; payload.data_len = 0; payload.param = "{\"foo\":0}"; payload.param_len = strlen(payload.param); /* *此处调用快速发布接口 */ vsoa_server_quick_publish(my_server.server, &url, &payload); } TASK(vsoa_server_task) { …… /* * 创建定时器 */ vsoa_timer_t *qpub_timer = vsoa_timer_create(); vsoa_timer_start_ms(qpub_timer, 1000, 1000, qpub_timer_handler, NULL); TerminateTask(); }
步骤 4:启动 VSOA 服务
在 vsoa_server_task
中启动 VSOA 服务端,调用 vsoa_server_start
,该接口需静态指定一个地址 ID (地址 ID 序号与具体 AUTOSAR 系统配置相关)。
/*
* 本例中服务器的地址 ID 可以选择 0 和 1, 0 为本地回环地址, 1 为 en1 的 IP 地址
*/
#define SERVER_ADDR_ID 1
#define SERVER_PORT 3001
TASK(vsoa_server_task) {
……
/*
* VSOA server add listener
*/
……
url.url = "/foo";
url.url_len = strlen(url.url);
vsoa_server_add_listener(my_server.server, &url, command_foo, NULL);
/*
* 启动 VSOA server
*/
vsoa_server_start(my_server.server, SERVER_ADDR_ID, TCPIP_AF_INET, SERVER_PORT);
TerminateTask();
}
步骤 5:执行 Server 事件循环
同标准 VSOA,Server Task 也需执行事件循环用于处理所有与 Server 相关的事件。在 VSOA AUTOSAR 中,该事件循环过程都已在 vsoa_server_event_loop
接口内容实现。因此只需在 Server Task 最后的循环内调用该接口即可。
TASK(vsoa_server_task) {
……
/*
* VSOA server add listener
*/
……
url.url = "/foo";
url.url_len = strlen(url.url);
vsoa_server_add_listener(my_server.server, &url, command_foo, NULL);
/*
* 启动 VSOA server
*/
vsoa_server_start(my_server.server, SERVER_ADDR_ID, TCPIP_AF_INET, SERVER_PORT);
while (1) {
vsoa_server_event_loop(my_server.server);
}
TerminateTask();
}
验证执行
以开源的 Tramponline AUTOSAR 为例,以上 VSOA Server 运行后,结果如下: