RISCV_RPMsg使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0
  • Initial release
  • 12/10/2022

    1. RPMSG说明

    1.1. 概述

    RPMSG英文全称是(Remote processor Messaging),是一种开放式的多核间通讯协议。Linux Kernel内置RPMSG协议的实现。

    1.2. 流程框图

    Sigmastar RPMsg userspace driver 对接kernel内置RPMsg协议实现,并提供了创建RPMsg endpoint的接口,Linux userspace app可以使用这些endpoints和FreeRTOS下的app进行通信。

    Rpmsg userspace driver会生成设备节点/dev/rpmsg_ctrl0,userspace app通过其ioctl接口,可以创建用于通信的Endpoint设备节点(如:/dev/rpmsg0),创建节点时,需要指定本地地址和远端的通信地址,如在Linux userspace app上指定src address Src1和dst address Dst1,在FreeRTOS下就要使用Dst1作为src address创建endpoint,并且发送数据时制定Src1作为dst address,这样Linux userspace app创建的Endpoint就可以和FreeRTOS创建的Endpoint进行通信了。

    1.2.1. Linux端的架构图

    1.2.2. FreeRTOS端的架构图

    2. RPMsg Userspace API参考

    API名 功能
    SS_RPMSG_CREATE_EPT_IOCTL 创建RPMsg Endpoint设备节点
    SS_RPMSG_DESTROY_EPT_IOCTL 销毁RPMsg Endpoint设备节点
    SS_RPMSG_DEVICES_INFO_IOCTL 获取当前连接上的RISCV列表
    read 接收数据
    write 发送数据

    2.1. SS_RPMSG_CREATE_EPT_IOCTL

    • 功能

      创建和target chip通信的RPMsg Endpoint设备节点

    • 语法

      struct ss_rpmsg_endpoint_info info;
      
      ioctl(fd, SS_RPMSG_CREATE_EPT_IOCTL, &info);
      
    • 形参

      参数名称 参数含义 输入/输出
      fd /dev/rpmsg_ctrl0的文件句柄。 输入
      info RPMsg Endpoint的属性。 输入,输出
    • 返回值

      • 0: 表示成功。

      • -1: 表示失败,查看errno获取原因。

    • 依赖

      • 头文件:drivers/sstar/include/sstar_rpmsg.h & errno.h

      • 库文件

    • 注意

      • 每次ioctl都会新建一个/dev/rpmsgX节点(如:rpmsg0),表示一个虚拟的通信通道。

      • 每个RC口或EP口长出来的RPMsg bus,其地址空间是独立的,不同mode&target_id组合表示一个独立的RPMsg bus,所以不同mode&target_id组合可以使用一样的src address。

      • 可以使用完全相同的struct ss_rpmsg_endpoint_info多次调用,创建多个/dev/rpmsgX节点,但是当这些节点中的一个被open后,其他都会open失败,同一时间只会允许一个处于open状态。

      • /dev/rpmsgX里面的X由struct ss_rpmsg_endpoint_info里面的id返回。

      • 如使用mdev,则ioctl返回后,/dev/rpmsgX节点可能会还没有被mdev建立,会有延迟。

      • 在合法的src&dst address空间内可以创建任意多个/dev/rpmsgX节点。

    • 举例

      Linux userspace app

    • 相关主题

      SS_RPMSG_DESTROY_EPT_IOCTL

    2.2. SS_RPMSG_DESTROY_EPT_IOCTL

    • 功能

      销毁掉对应的RPMsg Endpoint设备节点。

    • 语法

      ioctl(fd, SS_RPMSG_DESTROY_EPT_IOCTL);
      
    • 形参

      参数名称 参数含义 输入/输出
      fd /dev/rpmsgX(如rpmsg0)的文件句柄。 输入
    • 返回值

      • 0: 表示成功。

      • -1: 表示失败,查看errno获取原因。

    • 依赖

      • 头文件:drivers/sstar/include/sstar_rpmsg.h & errno.h

      • 库文件

    • 注意

      • 创建RPMsg Endpoint(/dev/rpmsgX)使用的是/dev/rpmsg_ctrl0文件句柄,而销毁/dev/rpmsgX节点的ioctl使用的是/dev/rpmsgX文件句柄,在调用SS_RPMSG_DESTROY_EPT_IOCTL后,对应的RPMsg Endpoint设备节点会在其最后一个文件句柄被close后销毁。

      • RPMsg Endpoint的创建/销毁和open/close是独立的,open后开始read/write使用,close后,可以重新open再次使用(read/write),如无其他需求,不必每次都重新创建。当不再需要了,可以调用SS_RPMSG_DESTROY_EPT_IOCTL进行销毁。

    • 举例

      参见SS_RPMSG_CREATE_EPT_IOCTL举例。

    • 相关主题

      SS_RPMSG_CREATE_EPT_IOCTL

    2.3. SS_RPMSG_DEVICES_INFO_IOCTL

    • 功能

      查询当前通过RPMsg有和Linux系统连接的RISCV列表,返回个数和target_id列表。

    • 语法

      int ioctl(int fd, SS_RPMSG_DEVICES_INFO_IOCTL, struct rpmsg_devices_info *info);
      
    • 形参

      参数名称 参数含义 输入/输出
      fd /dev/rpmsg_ctrl0的文件句柄。 输入
      info 指定查询的设备类型,并提供存储返回值的buffer。 输入,输出
    • 返回值

      • 0: 表示成功。

      • -1: 表示失败,查看errno获取原因。

    • 依赖

      • 头文件:drivers/sstar/include/sstar_rpmsg.h & errno.h

      • 库文件

    • 注意

      • 查询RISCV是否有通过RPMsg连接到Linux。
    • 举例(RC端)

      struct rpmsg_devices_info info;
      unsigned short *pTargetIDs;
      
      info.mode = RPMSG_MODE_RISCV;
      info.count = 1;
      info.buffer = (unsigned long long)malloc(1 * sizeof(unsigned int));
      
      fd = open("/dev/rpmsg_ctrl0", O_RDWR);
      if (fd < 0)
          return -1;
      
      if (ioctl(fd, SS_RPMSG_DEVICES_INFO_IOCTL, &info) < 0) {
          close(fd);
          return -1;
      }
      printf(“Current %d connected RISCV: \n”, info.count);
      pTargetIDs = (unsigned short *)info.buffer;
      for (int i = 0; i < info.count; i++)
      printf(“target_id %hu\n”, pTargetIDs [i]);
      free(info.buffer);
      close(fd);
      
    • 相关主题

    2.4. read

    • 功能

      接收数据。

    • 语法

      ssize_t read(int fd, void *buf, size_t count);
      
    • 形参

      参数名称 参数含义 输入/输出
      fd /dev/rpmsgX(如:rpmsg0)的文件句柄。 输入
      buf buffer地址,用于存放读取到的数据 输出
      count buffer的size 输入
    • 返回值

      • >= 0: 读取到的bytes个数。

      • -1: 失败,检查errno获取原因。

    • 依赖

      • 头文件:unistd.h & errno.h

      • 库文件

    • 注意

      • 支持使用Linux select/poll/epoll接口监视/dev/rpmsgX的文件句柄(fd),检查有待读取的数据。
    • 举例

      参见SS_RPMSG_CREATE_EPT_IOCTL举例。

    • 相关主题

      SS_RPMSG_CREATE_EPT_IOCTL

    2.5. write

    • 功能

      发送数据。

    • 语法

      ssize_t write(int fd, const void *buf, size_t count);
      
    • 形参

      参数名称 参数含义 输入/输出
      fd /dev/rpmsgX(如:rpmsg0)的文件句柄。 输入
      buf buffer地址,存放要发送的数据。 输入
      count 待发送数据的字节数。 输入
    • 返回值

      • >= 0: 已发送的字节数。

      • -1: 失败,检查errno获取原因。

    • 依赖

      • 头文件:unistd.h & errno.h

      • 库文件

    • 注意

      • 一次write,会使用一个RPMsg 数据包发送,最多携带496个bytes,所以需要检查返回值,当返回值不是-1时,并且小于count时,可以多次调用write来完成剩下数据的发送。
    • 举例

      参见SS_RPMSG_CREATE_EPT_IOCTL举例。

    • 相关主题

      SS_RPMSG_CREATE_EPT_IOCTL

    3. RPMsg Userspace接口数据类型

    相关数据类型、数据结构定义如下:

    数据类型 定义
    RPMSG_MODE_RISCV 表示target所连接的RPMsg bus是由riscv virtio device driver 创建的
    RPMSG_MODE_UNKNOWN 表示未知RPMsg bus模式
    EPT_TYPE_CUSTOMER 表示客户使用的(非Sigmastar使用)RPMsg Endpoint地址
    EPT_TYPE_SIGMASTAR 表示非客户使用的(Sigmastar使用)RPMsg Endpoint地址
    EPT_TYPE 定义RPMsg Endpoint地址所属类型的宏
    EPT_ADDR_MACRO 定义RPMsg Endpoint地址的宏。
    struct ss_rpmsg_endpoint_info 定义RPMsg Endpoint属性信息,如地址信息。
    struct ss_rpmsg_devices_info 定义连接设备查询条件的结构体

    3.1. RPMSG_MODE_RISCV

    • 说明

      表示target所在的RPMsg bus是由RISCV virtio device driver 创建的。

    • 定义

      #define RPMSG_MODE_RISCV  5
      
    • 成员

    • 注意事项

    • 相关数据类型及接口

    3.2. RPMSG_MODE_UNKNOWN

    • 说明

      表示未知的RPMsg bus模式。

    • 定义

      #define RPMSG_MODE_UNKNOWN  255
      
    • 成员

    • 注意事项

    • 相关数据类型及接口

    3.3. EPT_TYPE_CUSTOMER

    • 说明

      表示客户使用的(非Sigmastar使用)RPMsg Endpoint地址。

    • 定义

      #define EPT_TYPE_CUSTOMER    0x1
      
    • 成员

    • 注意事项

    • 相关数据类型及接口

    3.4. EPT_TYPE_SIGMASTAR

    • 说明

      表示非客户使用的(Sigmastar使用)RPMsg Endpoint地址。

    • 定义

      #define EPT_TYPE_SIGMASTAR   0x0
      
    • 成员

    • 注意事项

      客户进行应用开发时,不得使用这种类型的RPMsg Endpoint。

    • 相关数据类型及接口

    3.5. EPT_TYPE

    • 说明

      定义RPMsg Endpoint地址所属类型的宏。

    • 定义

      #define EPT_TYPE(x)       ((x & 0x1) << 30)
      
    • 成员

    • 注意事项

      参数成员为EPT_TYPE_CUSTOMER或者EPT_TYPE_SIGMASTAR

    • 相关数据类型及接口

      EPT_TYPE_CUSTOMER

      EPT_TYPE_SIGMASTAR

    3.6. EPT_ADDR_MACRO

    • 说明

      定义RPMsg Endpoint地址的宏。

    • 定义

      #define EPT_ADDR_MACRO(t, c)  (EPT_TYPE(t) | (c & 0x3fffffff))
      
    • 成员

    • 注意事项

      t表示地址类型,EPT_TYPE_CUSTOERM或者EPT_TYPE_SIGMASTAR

      c表示地址的值,在使用EPT_TYPE_CUSTOMER时,可以是任意数字

    • 相关数据类型及接口

      EPT_TYPE

      EPT_TYPE_CUSTOMER

      EPT_TYPE_SIGMASTAR

      SS_RPMSG_CREATE_EPT_IOCTL

    3.7. struct ss_rpmsg_endpoint_info

    • 说明

      定义创建的RPMsg Endpoint属性结构体。

    • 定义

      struct ss_rpmsg_endpoint_info {
              char name[32];
              __u32 src;
              __u32 dst;
              __u32 id;
              __u32 mode;
          __u16 target_id;
      };
      
    • 成员

      成员名称 描述
      name RPMsg Endpoint的名字
      src RPMsg Endpoint的本地地址,远端要发信息给这个Endpoint,其dst地址就要填写这个值。
      dst RPMsg Endpoint的信息发送目标地址,write Endpoint时,信息会被发送到这个地址。
      id ioctl的返回值,表示RPMsg Endpoint节点/dev/rpmsgX后面X的值。
      mode Target所在RPMsg bus的模式,其值固定为: RPMSG_MODE_RISCV
      target_id 只有一个RISCV核,所以固定为0
    • 注意事项

      无。

    • 相关数据类型及接口

      EPT_TYPE_CUSTOMER

      EPT_TYPE_SIGMASTAR

      EPT_TYPE

      EPT_ADDR_MACRO

    3.8. struct ss_rpmsg_devices_info

    • 说明

      定义devices列表的查询条件。

    • 定义

      struct ss_rpmsg_devices_info {
              __u32 mode;
              __u32 count;
              __u64 buffer;
      };
      
    • 成员

      成员名称 描述
      mode Target所在RPMsg bus的模式,其值为: RPMSG_MODE_RISCV
      count 作为输入,表示buffer最多可以存几个target_id, 作为输出,返回值表示buffer里有几个target_id。
      buffer Userspace buffer地址,kernel会往里面填写当前已连接RISCV的target_id列表。
    • 注意事项

      无。

    • 相关数据类型及接口

      RPMSG_MODE_RISCV

    4. RPMsg FreeRTOS API参考

    API名 功能
    rpmsg_dualos_get_instance 获取RPMsg设备实例指针
    rpmsg_queue_create 创建queue用于存储RPMsg驱动接收到的数据
    rpmsg_lite_create_ept 创建RPMsg endpoint
    rpmsg_queue_recv 从RPMsg endpoint中获取接收到的数据
    rpmsg_lite_send 通过RPMsg endpoint把数据发给远端的RPMsg endpoint
    rpmsg_queue_destroy 销毁queue
    rpmsg_lite_destroy_ept 销毁RPMsg endpoint

    4.1. rpmsg_dualos_get_instance

    • 功能

      获取FreeRTOS下RPMsg设备实例指针,这个句柄是许多其他API(如:rpmsg_create_queue, rpsmg_lite_create_ept等)的参数。

    • 语法

      struct rpmsg_lite_instance *rpmsg_dualos_get_instance(int soc_id, int os_id);
      
    • 形参

      参数名称 参数含义 输入/输出
      soc_id 固定传入EPT_SOC_DEFAULT 输入
      os_id 固定传入EPT_OS_LINUX 输入
    • 返回值

      • 非NULL: 成功。

      • NULL: 表示RPMsg driver还没有初始化好。

    • 依赖

      • 头文件:rpmsg_dualos.h

      • 库文件

    4.2. rpmsg_queue_create

    • 功能

      创建存放消息的queue,RPMsg driver会将接收到的,发往对应endpoint的数据存放创建endpoint时指定的queue中。

    • 语法

      rpmsg_queue_handle rpmsg_queue_create(struct rpmsg_lite_instance *rpmsg_lite_dev);
      
    • 形参

      参数名称 参数含义 输入/输出
      rpmsg_lite_dev RPMsg设备实例指针 输入
    • 返回值

      • 非RL_NULL: 成功。

      • RL_NULL: 表示创建失败

    • 依赖

      • 头文件:rpmsg_dualos.h

      • 库文件

    4.3. rpmsg_lite_create_ept

    • 功能

      创建用于RPMsg通信的endpoint。

    • 语法

      struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev,
      unsigned long addr,
      rl_ept_rx_cb_t rx_cb,
      void *rx_cb_data);
      
    • 形参

      参数名称 参数含义 输入/输出
      rpmsg_lite_dev RPMsg设备实例指针 输入
      addr endpoint的source address地址 输入
      rx_cb RPMsg驱动收到发往addr的数据包,会调用这callback函数,进行处理 输入
      data RPMsg驱动在调用rx_cb函数时,作为priv参数的值传给rx_cb 输入
    • 返回值

      • 非RL_NULL: 成功。

      • RL_NULL: 表示创建失败。

    • 依赖

      • 头文件:rpmsg_dualos.h

      • 库文件

    4.4. rpmsg_queue_recv

    • 功能

      用于从queue中获取接收到的数据。

    • 语法

      int rpmsg_queue_recv( struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_queue_handle q, unsigned long *src, char *data,
      int maxlen, int *len, unsigned long timeout);
      
    • 形参

      参数名称 参数含义 输入/输出
      rpmsg_lite_dev RPMsg设备实例指针 输入
      q queue句柄 输入
      src 返回数据的发送方endpoint地址 输出
      data buffer地址,用于存储数据包 输入
      maxlen buffer的size 输入
      len 返回接收到的数据包size 输出
      timeout 超时时间 输入
    • 返回值

      • RL_SUCCESS: 成功

      • RL_ERR_PARAM: 错误参数

      • RL_ERR_BUF_SIZE: 数据大于buffer size

      • RL_ERR_NO_BUFF: 没有数据

    • 依赖

      • 头文件:rpmsg_dualos.h

      • 库文件

    4.5. rpmsg_lite_send

    • 功能

      发送数据到指定地址的远端RPMsg endpoint。

    • 语法

      int rpmsg_lite_send( struct rpmsg_lite_instance *rpmsg_lite_dev,
      struct rpmsg_lite_endpoint *ept,
      unsigned long dst, char *data,
      unsigned long size, unsigned long timeout);
      
    • 形参

      参数名称 参数含义 输入/输出
      rpmsg_lite_dev RPMsg设备实例指针 输入
      ept RPMsg endpoint实例指针 输入
      dst 远端RPMsg endpoint的地址 输入
      data 需要发送数据的buffer地址 输入
      size 需要发送数据的size 输入
      len 返回接收到的数据包size 输入
      timeout 超时时间 输入
    • 返回值

      • RL_SUCCESS: 成功

      • RL_ERR_PARAM: 错误参数

      • RL_ERR_BUF_SIZE: 数据大于单个RPMsg数据包允许的最大payload size(496 bytes)

      • RL_ERR_NO_MEM: 没有空间用于发送数据

    • 依赖

      • 头文件:rpmsg_dualos.h

      • 库文件

    4.6. rpmsg_queue_destroy

    • 功能

      销毁rpmsg_queue_create()创建的queue。

    • 语法

      int rpmsg_queue_destroy( struct rpmsg_lite_instance
      *rpmsg_lite_dev, rpmsg_queue_handle q);
      
    • 形参

      参数名称 参数含义 输入/输出
      rpmsg_lite_dev RPMsg设备实例指针 输入
      q queue句柄 输入
    • 返回值

      • RL_SUCCESS: 成功

      • RL_ERR_PARAM: 错误参数

    • 依赖

      • 头文件:rpmsg_dualos.h

      • 库文件

    4.7. rpmsg_lite_destroy_ept

    • 功能

      销毁rpmsg_lite_create_create()创建的RPMsg endpoint。

    • 语法

      int rpmsg_lite_destroy_ept( struct rpmsg_lite_instance *rpmsg_lite_dev, struct rpmsg_lite_endpoint *rl_ept);
      
    • 形参

      参数名称 参数含义 输入/输出
      rpmsg_lite_dev RPMsg设备实例指针 输入
      rl_ept RPMsg endpoint指针 输入
    • 返回值

      • RL_SUCCESS: 成功

      • RL_ERR_PARAM: 错误参数

    • 依赖

      • 头文件:rpmsg_dualos.h

      • 库文件

    5. RPMsg Demo说明

    5.1. RPMsg Demo简介

    RPMsg demo由两部分组成,一个是linux userspace app,一个是FreeRTOS下的app,两个app间使用RPMsg进行通信。

    Linux userspace app向FreeRTOS app不断的发送带上编号的”hello,world”信息,然后读取FreeRTOS app的应答并打印出来。

    FreeRTOS app则是循环等待linux userspace app发送数据过来,然后把数据不做修改的发送回去。

    5.2. Linux userspace app

    5.2.1. 代码

    1.    #include <stdio.h>
    2.    #include <string.h>
    3.    #include <unistd.h>
    4.    #include <sys/types.h>
    5.    #include <sys/stat.h>
    6.    #include <sys/ioctl.h>
    7.    #include <fcntl.h>
    8.    #include <stdint.h>
    9.
    10.    #include "sstar_rpmsg.h"
    11.
    12.    int main(void)
    13.    {
    14.        struct ss_rpmsg_endpoint_info info;
    15.        char buffer[512];
    16.        char data[512];
    17.        int ret;
    18.        char devPath[256];
    19.        int fd, eptFd;
    20.        unsigned int index = 0x0;
    21.
    22.        memset(&info, 0, sizeof(info));
    23.        info.src = EPT_ADDR_MACRO(EPT_TYPE_CUSTOMER, 1);
    24.        info.dst = EPT_ADDR_MACRO(EPT_TYPE_CUSTOMER, 2);
    25.        snprintf(info.name, sizeof(info.name), "demo");
    26.        info.mode = RPMSG_MODE_RISCV;
    27.        info.target_id = 0;
    28.
    29.        fd = open("/dev/rpmsg_ctrl0", O_RDWR);
    30.        if (fd < 0)
    31.        {
    32.            perror("open");
    33.            return 0;
    34.        }
    35.
    36.        if (ioctl(fd, SS_RPMSG_CREATE_EPT_IOCTL, &info) < 0)
    37.        {
    38.            perror("ioctl");
    39.            return 0;
    40.        }
    41.
    42.        sleep(2);
    43.
    44.        snprintf(devPath, sizeof(devPath),  "/dev/rpmsg%d", info.id);
    45.        eptFd = open(devPath, O_RDWR);
    46.
    47.        if (eptFd < 0)
    48.        {
    49.            fprintf(stderr, "Failed to open endpoint!\n");
    50.            return 0;
    51.        }
    52.
    53.        while (1)
    54.        {
    55.            snprintf(buffer, sizeof(buffer), "hello,world:0x%x\n", index++);
    56.            ret = write(eptFd, buffer, strlen(buffer) + 1);
    57.
    58.            memset(data, 0, sizeof(data));
    59.            ret = read(eptFd, data, sizeof(data));
    60.            if (ret > 0)
    61.                printf("read ept:%d, %s\n", ret, data);
    62.            else
    63.                printf("read ept error:%d\n", ret);
    64.        }
    65.        return 0;
    66.    }
    

    5.2.2. 注释

    1) 第42行sleep()函数调用,是为了避免mdev还没有创建好rpmsg endpoint节点

    5.3. FreeRTOS app

    5.3.1. 代码

    RISCV sdk中的路径:

    sc/application/rpmsg_app

    1.    #include "ms_platform.h"
    2.    #include "cam_os_wrapper.h"
    3.    #include "initcall.h"
    4.    #include "rpmsg_dualos.h"
    5.
    6.    static struct rpmsg_lite_instance *rpmsg_instance;
    7.    static CamOsThread rpmsg_test_thread;
    8.
    9.    static void* rpmsg_test(void *arg)
    10.    {
    11.        struct rpmsg_lite_endpoint *test_ept;
    12.        rpmsg_queue_handle test_ept_q;
    13.        int test_ept_addr;
    14.
    15.        int recved = 0;
    16.        int ret;
    17.        unsigned long src;
    18.        char buf[256];
    19.
    20.        CamOsPrintf("Running rpmsg_test_task ...\n");
    21.
    22.        while (1) {
    23.            rpmsg_instance = rpmsg_dualos_get_instance(EPT_SOC_DEFAULT, EPT_OS_LINUX);
    24.            if (rpmsg_instance)
    25.                break;
    26.            CamOsMsSleep(1);
    27.        }
    28.
    29.        test_ept_q = rpmsg_queue_create(rpmsg_instance);
    30.        if (test_ept_q == NULL) {
    31.            CamOsPrintf("rpmsg_test: failed to create queue\n");
    32.            return NULL;
    33.        }
    34.
    35.        test_ept_addr = EPT_ADDR_MACRO(EPT_TYPE_CUSTOMER, 2);
    36.        test_ept = rpmsg_lite_create_ept(rpmsg_instance, test_ept_addr, rpmsg_queue_rx_cb, test_ept_q);
    37.        if (test_ept == NULL) {
    38.            CamOsPrintf("rpmsg_test: failed to create ept\n");
    39.            rpmsg_queue_destroy(rpmsg_instance, test_ept_q);
    40.            return NULL;
    41.        }
    42.
    43.        while (1) {
    44.            recved = 0x0;
    45.            rpmsg_queue_recv(rpmsg_instance, test_ept_q, &src, (char *)&buf, 256, &recved, RL_BLOCK);
    46.
    47.            if (recved > 0) {
    48.                ret = rpmsg_lite_send(rpmsg_instance, test_ept, src, (char *)buf, recved, 5*1000);
    49.                if (ret != RL_SUCCESS) {
    50.                    CamOsPrintf("rpmsg_test: rpmsg_lite_send return %d\n", ret);
    51.                }
    52.            }
    53.        }
    54.        return NULL;
    55.    }
    56.
    57.    void RPMsgAppMainEntry(void)
    58.    {
    59.        CamOsThreadAttrb_t attr = {
    60.            .nStackSize = 2048
    61.        };
    62.
    63.        attr.szName = "rpmsg_test";
    64.        CamOsThreadCreate(&rpmsg_test_thread, &attr, rpmsg_test, NULL);
    65.    }
    66.
    67.    rtos_application_initcall(RPMsgAppMainEntry, 0);
    

    5.3.2. 注释

    1) 22-27行循环调用rpmsg_dualos_get_instance() 获取rpmsg instance,是为了等待FreeRTOS中的RPMsg驱动准备好

    2) 29行创建一个queue,RPMsg驱动在收到发往对应endpoint的数据时,会调用回调函数rpmsg_queue_rx_cb,将数据放到这个queue中

    3) 36行调用rpmsg_lite_create_ept()创建RPMsg endpoint,这里会传入src address,回调函数rpmsg_queue_rx_cb,以及29行创建的queue

    4) 45行调用rpmsg_queue_recv()接收数据,创建好RPMsg endpoint后,RPMsg驱动就可以接收发往对应src address的数据了,rpmsg_queue_recv()最后一个参数RL_BLOCK表示blocked,即如果没有数据就阻塞,直到有数据才返回,如果收到数据,其第二个参数会返回发送方的地址

    5) 48行是调用rpmsg_lite_send()函数把数据发回给发送方