3.1. 【TDA4 C71】函数回调实现 —— RemoteService

1,559 阅读3分钟

1. 什么是 Remote Service

Remote ServicePSDKVisionApps 层实现的一套 远程调用模型,允许用户通过简易的 API 实现通过 IPC 调用远程核心上的函数或服务。这些函数或服务是控制类而不是执行实时算法。
Remote Service 服务命令在单个线程中执行,因此对同一个 CPU(包含异构芯片和MPU) 的多个请求将被序列化。一旦 Remote Service 的一个服务命令开始执行,就会运行到完成状态,然后才会转移到另一个服务命令。
Remote ServiceAPI 的重点是简单性,而不是低延迟和效率。开发者想获得最佳通信性能,应该调用 IPC 本身。 IPC 本身的介绍在本栏其他专题中。

2. 代码库中 Remote Service 的实现在哪里?

基于vision_apps中的remote_service工程 vision_apps/utils/remote_service

每个源码文件的功能

COMMONapp_remote_service_test.c关于测试程序的回调注册
SYSBIOS\FREERTOS\QNXapp_remote_service.c依赖相关系统的API的实现。这里包含的芯片有 C6x,C7x
LINUXapp_remote_service_linux.c依赖Linux IPC实现,支持MPU,MCU,DSP的远程通信。这里包含的芯片有A72,X86,X86_64

这里重点总结 Linux + sysbiosRemote Service 的实现逻辑。

3. 执行过程 —— Linux Remote Service

3.1. 底层关键实现 —— RPMSG CHAR

此部分具体说明间 psdk_rtos/docs/user_guide/developer_notes_ipc.html

RPMSG 是顶层 API 实现,具体工作依赖 IPC 驱动程序和 VRING。
VRING 是一段芯片间的共享内存,用于保存 Message
Hardware - Mailbox 主要提供基于硬件中断 (interrupt) 的事件。本质上是持有 VRING ID 的很小的 HW 队列。
RPMSG CHARRPMSG 在用户空间的 API。提供一个文件 IO 接口 (/dev/rpmsgX) 用于读写 Message 。提供如 Select 的操作 Wait 接口,提供 RPMSG_char_helper 等简化接口。

参考API ti_rpmsg_char.h

3.2. 调用RPMSG CHAR —— Remote Service

RX==receive,接收,从开启到现在接收封包的情况,是下行流量。 TX==Transmit,发送,从开启到现在发送封包的情况,是上行流量。

  1. appRemoteServiceInit
    1. init pthread mutex and lock
    2. create tx. rpmsg_char_open wiht rpmsg_cpu_id,get file discriptor and local end point addr
  2. appRemoteServiceRegister
    1. save app_remote_service_handler_t with service_name at app_remote_service_obj_t
  3. appRemoteServiceRun
    1. copy content from input buffer to app_remote_service_obj_t→rpmsg_tx_msg_buf
    2. write app_remote_service_obj_t→rpmsg_tx_msg_buf to file discriptor , self cpu → dst cpu
    3. if APP_REMOTE_SERVICE_FLAG_NO_WAIT_ACK, return. else next.
    4. wait and read message form file discriptor to app_remote_service_obj_t→rpmsg_tx_msg_buf. dst cpu → self cpu
    5. write app_remote_service_obj_t→rpmsg_tx_msg_buf to input buffer
  4. appRemoteServiceUnRegister
    1. remove app_remote_service_handler_t with service_name from app_remote_service_obj_t
  5. appRemoteServiceDeInit
    1. delete pthread mutex and lock
    2. rpmsg_char_close with rpmsg handler

4. 执行过程 —— Sysbios Remote Service

编译依赖 CORE=c7x_1 相关编译文件 pdk_jacinto_08_00_00_37/packages/ti/osal/src/src_common_nonos.mk

VisionAppsSysbios Remote Service 实现有一个迷惑行为。在同一的 IPC 接口下实现一套 Sysbios ( c7x , c6x 等设备上运行的版本 ) 的版本 ( 具体见 vision_apps/utils/ipc/src/app_ipc_rtos.c ),同时在 Remote Service 接口下实现 Sysbios 版本时并未引用前者的 IPC 实现转而直接调用底层设备的 IPC 实现( 具体见 pdk_jacinto_08_00_00_37/packages/ti/drv/ipc )。故,这里主要描述调用逻辑。

4.1. 调用设备IPC的过程

Task 是rtos的线程模型。 Semaphore 是rtos的信号量模型

  1. appRemoteServiceInit
    1. init semaphore
    2. create tx and rx ipc.
    3. create rx task
      1. start thread → loop
        1. recv rx message
        2. call app_remote_service_handler_t
      2. register perf task
    4. init test and printf
  2. appRemoteServiceCreateRpmsgRxTask
    1. save app_remote_service_handler_t with service_name at app_remote_service_obj_t
  3. appRemoteServiceRun
    1. copy content from input buffer to app_remote_service_obj_t→rpmsg_tx_msg_buf
    2. ipc send app_remote_service_obj_t→rpmsg_tx_msg_buf to tx
    3. if APP_REMOTE_SERVICE_FLAG_NO_WAIT_ACK, return. else next.
    4. ipc recv and write app_remote_service_obj_t→rpmsg_tx_msg_buf
  4. appRemoteServiceUnRegister
    1. remove app_remote_service_handler_t with service_name from app_remote_service_obj_t
  5. appRemoteServiceDeInit
    1. deinit test
    2. stop and delete task
    3. delete tx rx ipc
    4. delete semaphore

5. 两种系统的remote service实现有什么不同

目前看来,sysbios实现在不开启APP_REMOTE_SERVICE_FLAG_NO_WAIT_ACK情况下可做到异步调用,而linux实现完全是同步的。
有待实际验证。