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:新建 Client Task
新建
vsoa_client_task
,在该 Task 中需等待 VSOA 初始化完成。Client Task 需要与一个 Alarm 关联,该 Alarm 用于该 Task 中的信号量超时等操作。/* * 使用 VSOA 的任务需要定义一个 vsoa_as_task_t, 并使用 vsoa_as_task_register 注册 */ static vsoa_as_task_t vsoa_client_task = { .task_id = vsoa_client_task_id, .alarm = vsoa_client_task_alarm_id, .alarm_event = vsoa_client_task_timeout_mask, }; TASK(vsoa_client_task) { /* * 注册任务 */ vsoa_as_task_register(&vsoa_client_task); /* * 等待 VSOA 初始化完成 */ while (!vsoa_init_res) { vsoa_as_task_sleep(ONE_MS); } TerminateTask(); }
在
vsoa_client_task
中创建 VSOA 客户端。与标准 VSOA 不同在于 VSOA AUTOSAR 版本的vsoa_client_create
需要多传入一个vsoa_client_osl_t
类型的参数,该参数中定义了 Client Task 所需的 Resource 与 Event 资源。/* * 一个 vsoa_client_osl_t 实现, 需要一个 vsoa_as_client_ctx_t, * vsoa_as_client_ctx_t 需要一个 Resource 和 Event 分别作 mutex 和 semaphore */ static vsoa_as_client_ctx_t my_client_ctx = { .event = my_client_event_mask, .mutex = my_client_lock_id }; static vsoa_client_osl_t my_client_osl = { .ctx = &my_client_ctx, .lock = vsoa_as_client_lock, .unlock = vsoa_as_client_unlock, .wait = vsoa_as_client_wait, .post = vsoa_as_client_post, .sleep = vsoa_as_client_sleep }; /* My client */ static vsoa_client_t *my_client; /* My client password */ #define MY_SERVER_PASSWD "123456" /* * 使用 VSOA 的任务需要定义一个 vsoa_as_task_t, 并使用 vsoa_as_task_register 注册 */ static vsoa_as_task_t vsoa_client_task = { .task_id = vsoa_client_task_id, .alarm = vsoa_client_task_alarm_id, .alarm_event = vsoa_client_task_timeout_mask, }; TASK(vsoa_client_task) { /* * 注册任务 */ vsoa_as_task_register(&vsoa_client_task); /* * 等待 VSOA 初始化完成 */ while (!vsoa_init_res) { vsoa_as_task_sleep(ONE_MS); } /* * 创建 VSOA client */ my_client = vsoa_client_create(&my_client_osl, onmessage, NULL); vsoa_client_linger(my_client, true); vsoa_client_send_timeout(my_client, 1 * ONE_S); TerminateTask(); }
步骤 3:连接 VSOA 服务
在 vsoa_client_task
中连接 VSOA 服务端,调用 vsoa_client_connect
,该接口需静态指定一个地址 ID (地址 ID 序号与具体 AUTOSAR 系统配置相关)。
/*
* 本例中服务器的地址 ID 可以选择 0 和 1, 0 为本地回环地址, 1 为 en1 的 IP 地址
* 本例中服务端的 IP 地址为 192.168.7.55
*/
#define CLIENT_ADDR_ID 1
#define CLIENT_SERVER_IP IP4_ADDR_CHR_TO_UINT32(192,168,7,55)
#define CLIENT_SERVER_PORT 3001
TASK(vsoa_client_task) {
……
/*
* 连接 VSOA 服务器
*/
char info[256];
TcpIp_SockAddrType addr;
addr.domain = TCPIP_AF_INET;
addr.port = CLIENT_SERVER_PORT;
#if (CPU_BYTE_ORDER == LOW_BYTE_FIRST)
addr.addr[0] = (CLIENT_SERVER_IP >> 0) & 0xff;
addr.addr[1] = (CLIENT_SERVER_IP >> 8) & 0xff;
addr.addr[2] = (CLIENT_SERVER_IP >> 16) & 0xff;
addr.addr[3] = (CLIENT_SERVER_IP >> 24) & 0xff;
#else
addr.addr[0] = (CLIENT_SERVER_IP >> 24) & 0xff;
addr.addr[1] = (CLIENT_SERVER_IP >> 16) & 0xff;
addr.addr[2] = (CLIENT_SERVER_IP >> 8) & 0xff;
addr.addr[3] = (CLIENT_SERVER_IP >> 0) & 0xff;
#endif
if (!vsoa_client_connect(my_client, CLIENT_ADDR_ID, &addr, ONE_S, MY_SERVER_PASSWD, info, sizeof(info))) {
TerminateTask();
}
TerminateTask();
}
步骤 4:调用 RPC 、订阅等业务
同标准 VSOA 的使用方式,客户端可以订阅服务端发布的信息。
TASK(vsoa_client_task) { …… /* * 创建 VSOA client */ my_client = vsoa_client_create(&my_client_osl, onmessage, NULL); …… /* * 连接 VSOA server */ if (!vsoa_client_connect(my_client, CLIENT_ADDR_ID, &addr, ONE_S, MY_SERVER_PASSWD, info, sizeof(info))) { TerminateTask(); } /* * 订阅 URL */ vsoa_url_t url; url.url = "/foo"; url.url_len = strlen(url.url); vsoa_client_subscribe(my_client, &url, NULL, NULL, 0); TerminateTask(); }
同标准 VSOA 的使用方式,可以向 VSOA 服务端发起 RPC 调用。
static void my_client_timer_handler(void *arg, vsoa_timer_t *timer, void *custom) { vsoa_url_t url; url.url = "/foo"; url.url_len = strlen(url.url); vsoa_client_call(my_client, VSOA_CLIENT_RPC_METHOD_GET, &url, NULL, get_foo, NULL, ONE_S); } TASK(vsoa_client_task) { …… /* * 创建定时器进行 RPC 调用 */ vsoa_timer_t *timer = vsoa_timer_create(); vsoa_timer_start_ms(timer, 1000, 1000, my_client_timer_handler, NULL); TerminateTask(); }
步骤 5:执行 Client 事件循环
同标准 VSOA,Client Task 也需执行事件循环用于处理所有与 Client 相关的事件。在 VSOA AUTOSAR 中,该事件循环过程都已在 vsoa_client_event_loop
接口内容实现。因此只需在 Client Task 最后的循环内调用该接口即可。
TASK(vsoa_client_task) {
……
/*
* 创建定时器进行 RPC 调用
*/
vsoa_timer_t *timer = vsoa_timer_create();
vsoa_timer_start_ms(timer, 1000, 1000, my_client_timer_handler, NULL);
while (1) {
vsoa_client_event_loop(my_client);
}
TerminateTask();
}
验证执行
以开源的 Tramponline AUTOSAR 为例,以上 VSOA Client 运行后,结果如下: