新闻  |   论坛  |   博客  |   在线研讨会
【RT-Thread 笔记】----使用消息队列发送不定长数据
电子禅石 | 2019-02-13 18:56:39    阅读:18977   发布文章

简介:

本文简要介绍如何使用RT-Thread 的消息队列 发送不定长数据的使用。数据比较经典的用法,可以在很多数据传输的场合应用。

知识点:

1.参考内容:

https://www.rt-thread.org/document/site/programming-manual/ipc2/ipc2/#_2

2.要点摘录:通过定义结构体:数据块首地址和数据块大小 来进行数据的传递。非常通用。

消息队列的使用场合

消息队列可以应用于发送不定长消息的场合,包括线程与线程间的消息交换,以及中断服务例程中给线程发送消息(中断服务例程不能接收消息)。下面分发送消息和同步消息两部分来介绍消息队列的使用。

发送消息

消息队列和邮箱的明显不同是消息的长度并不限定在 4 个字节以内;另外,消息队列也包括了一个发送紧急消息的函数接口。但是当创建的是一个所有消息的最大长度是 4 字节的消息队列时,消息队列对象将蜕化成邮箱。这个不限定长度的消息,也及时的反应到了代码编写的场合上,同样是类似邮箱的代码:

struct msg{
    rt_uint8_t *data_ptr;    /* 数据块首地址 */
    rt_uint32_t data_size;   /* 数据块大小   */};

和邮箱例子相同的消息结构定义,假设依然需要发送这样一个消息给接收线程。在邮箱例子中,这个结构只能够发送指向这个结构的指针(在函数指针被发送过去后,接收线程能够正确的访问指向这个地址的内容,通常这块数据需要留给接收线程来释放)。而使用消息队列的方式则大不相同:

void send_op(void *data, rt_size_t length){    struct msg msg_ptr;

    msg_ptr.data_ptr = data;  /* 指向相应的数据块地址 */
    msg_ptr.data_size = length; /* 数据块的长度 */

    /* 发送这个消息指针给 mq 消息队列 */
    rt_mq_send(mq, (void*)&msg_ptr, sizeof(struct msg));
}

注意,上面的代码中,是把一个局部变量的数据内容发送到了消息队列中。在接收线程中,同样也采用局部变量进行消息接收的结构体:

void message_handler(){    struct msg msg_ptr; /* 用于放置消息的局部变量 */

    /* 从消息队列中接收消息到 msg_ptr 中 */
    if (rt_mq_recv(mq, (void*)&msg_ptr, sizeof(struct msg)) == RT_EOK)
    {        /* 成功接收到消息,进行相应的数据处理 */
    }
}

因为消息队列是直接的数据内容复制,所以在上面的例子中,都采用了局部变量的方式保存消息结构体,这样也就免去动态内存分配的烦恼了(也就不用担心,接收线程在接收到消息时,消息内存空间已经被释放)。

例子说明:

下面例子是通过onenet 平台发送不定长命令,在开发板的命令响应回掉函数中 将数据发送到打印线程:

/* onenet mqtt command response callback function */
static void onenet_cmd_rsp_cb(uint8_t *recv_data, size_t recv_size, uint8_t **resp_data, size_t *resp_size)
{
    char res_buf[] = { "cmd is received!\n" };

    log_d("recv data is %.*s\n", recv_size, recv_data);
    rs485_transport(recv_data,recv_size);
    /* user have to malloc memory for response data */
    *resp_data = (uint8_t *) ONENET_MALLOC(strlen(res_buf));

    strncpy(*resp_data, res_buf, strlen(res_buf));

    *resp_size = strlen(res_buf);
        
}
static rt_uint8_t temp_data[20];
void rs485_transport(uint8_t *recv_data, size_t recv_size)
{
          int result;
                struct msg msg_ptr;
             //增加一句 先  把数据复制到静态变量中。
               strncpy(temp_data, recv_data, recv_size);
                msg_ptr.data_ptr = temp_data;//recv_data;
                msg_ptr.data_size = recv_size;
    rt_pin_write(RS485_RE_DE_Pin, PIN_HIGH);
/* 发送消息到消息队列中 */
            result = rt_mq_send(&mq,(void*)&msg_ptr,sizeof(struct msg));
            if (result != RT_EOK)
            {
                rt_kprintf("rt_mq_send ERR\n");
            }

            rt_kprintf("thread onenet: send message - %s\n", msg_ptr.data_ptr);
    //rt_pin_write(RS485_RE_DE_Pin, PIN_LOW);
}

接收处理:
static void serial_thread_entry(void *parameter)
{
    char buf;
    rt_uint8_t k;
        struct msg msg_prt;
    while (1)
    {

                      /* 从消息队列中接收消息 */

                if (rt_mq_recv(&mq, (void*)&msg_prt, sizeof(struct msg), RT_WAITING_FOREVER) == RT_EOK)
        {
        
                        rt_device_write(serial, 0, (void*)msg_prt.data_ptr, msg_prt.data_size);
        }
    
    }
}

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
属于自己的技术积累分享,成为嵌入式系统研发高手。
推荐文章
最近访客