RT-Thread Getting Started Study Notes-Familiar with the use of message queues

background

  • RT-Thread's message queue is used for communication between threads, transmission of commands and data, which is very convenient
  • Message queues are more convenient to use than mailboxes, and transmit shorter and variable length data without dynamically applying for memory
  • Message queue receiving requires threads
  • The message queue can be sent in interrupt callback, thread, shell cmd.

 

What can the message queue do

  • The transmission of data and commands between threads, the realization of the state machine, and the queue cache, will not lose operations
  • Message queue, the content can be variable length, it can be not a global variable, the message queue will back up the transmitted data
  • The message queue can transmit commands and data. For complex data, you can use a custom message body.

 

Operation example

  • Define the message body of the message queue user
#ifndef MAX_PHONE_MSG_MQ_SIZE
#define MAX_PHONE_MSG_MQ_SIZE   32
#endif

/* messagequeue struct */
struct mq_msg
{
    rt_uint32_t cmd; /* command or event, msg id */
    rt_uint32_t dat; /* mq load data */
    rt_uint32_t len; /* mq load buffer length */
    char *buf;       /* mq load buffer pointer */
};

enum PHONE_MSG_
{
    MSG_PHONE_OPEN_DIAL = 0,
    MSG_PHONE_INCOMING,
    MSG_PHONE_ANSWER,
    MSG_PHONE_END_DIAL,
};
  • Initialize the message queue, note that before using it, you need to initialize the message queue
static rt_err_t phone_mq_init(void)
{
    rt_err_t ret = RT_EOK;

    ret = rt_mq_init(&phone_mq, "phone_mq", &phone_msg_buf,
        sizeof(struct mq_msg), sizeof(phone_msg_buf), RT_IPC_FLAG_FIFO);

    if (ret != RT_EOK)
    {
        LOG_E("%s : error!", __func__);
        return -RT_ERROR;
    }

    return ret;
}
  • Create the receiving processing thread of the message queue. The receiving is blocked and needs to be placed in the thread
static void phone_task_entry(void *param)
{
    struct mq_msg recv_msg = { 0 };

    while(1)
    {
        if (rt_mq_recv(&phone_mq, &recv_msg, sizeof(recv_msg), RT_WAITING_FOREVER) == RT_EOK)
        {
            switch (recv_msg.cmd)
            {
                case MSG_PHONE_OPEN_DIAL:
                    LOG_D("%s: MSG_PHONE_OPEN_DIAL.", __func__);
                    break;
                case MSG_PHONE_INCOMING:
                    LOG_D("%s: MSG_PHONE_INCOMING.", __func__);
                    break;
                case MSG_PHONE_END_DIAL:
                    LOG_D("%s: MSG_PHONE_END_DIAL.", __func__);
                    break;
                case MSG_PHONE_ANSWER:
                    LOG_D("%s: MSG_PHONE_ANSWER.", __func__);
                    break;
                default:
                    break;
            }
        }
        phone_mq_free(&recv_msg);
    }
}

/* 消息队列接收线程初始化 */
int phone_task_init(void)
{
    rt_thread_t tid;
    phone_mq_init();

    tid = rt_thread_create("phone", phone_task_entry, RT_NULL, 2048, 10, 20);
    if (tid != RT_NULL)
    {
        rt_thread_startup(tid);
        LOG_D("%s: end.", __func__);
        return 0;
    }
    else
    {
        LOG_E("%s: error!", __func__);
        return -1;
    }
}

INIT_APP_EXPORT(phone_task_init);
  • To send messages, shell commands are used here. Sending can be placed in threads, interrupts, and callbacks. Be careful not to apply for memory in interrupts.
/* 发送消息 */
rt_err_t phone_send_msg(struct mq_msg *msg)
{
    if (msg == RT_NULL)
        return -RT_ERROR;

    return rt_mq_send(&phone_mq, msg, sizeof(struct mq_msg));
}

/* 消息中free掉用户动态申请的内存【按需】 */
static void phone_mq_free(struct mq_msg *msg)
{
    if (msg)
    {
        if (msg->buf)
        {
            rt_free(msg->buf);
            msg->buf = RT_NULL;
        }
    }
}

/* shell命令,用于验证发送命令 */
void phone_open_dial(void)
{
    struct mq_msg msg = { 0 };

    msg.cmd = MSG_PHONE_OPEN_DIAL;
    phone_send_msg(&msg);
}

void phone_end_dial(void)
{
    struct mq_msg msg = { 0 };

    msg.cmd = MSG_PHONE_END_DIAL;
    phone_send_msg(&msg);
}

void phone_answer_dial(void)
{
    struct mq_msg msg = { 0 };

    msg.cmd = MSG_PHONE_ANSWER;
    phone_send_msg(&msg);
}

MSH_CMD_EXPORT(phone_open_dial, phone_open_dial);
MSH_CMD_EXPORT(phone_end_dial, phone_end_dial);
MSH_CMD_EXPORT(phone_answer_dial, phone_answer_dial);

Compile, download and functional verification

  • Use STM32L4 platform, or PC simulator
  • list_thread view message queue receiving thread
msh >list_thread
thread   pri  status      sp     stack size max used left tick  error
-------- ---  ------- ---------- ----------  ------  ---------- ---
tshell    20  running 0x00000088 0x00001000    12%   0x00000005 000
phone     10  suspend 0x000000ac 0x00000800    08%   0x00000005 000
tidle0    31  ready   0x00000080 0x00000400    12%   0x00000003 000
main      10  suspend 0x0000008c 0x00000800    13%   0x00000009 000
  • send messages
msh >phone_open_dial
[D/phone] phone_task_entry: MSG_PHONE_OPEN_DIAL.
msh >phone_end_dial
[D/phone] phone_task_entry: MSG_PHONE_END_DIAL.
msh >phone_answer_dial
[D/phone] phone_task_entry: MSG_PHONE_ANSWER.

 

summary of a problem

  • The message queue can only be used after it is initialized. If you use an emulator, the automatic initialization function may fail and you need to initialize it manually.
  • The rt_mq_recv receiving function needs to judge whether the execution is successful, == RT_EOK cannot be omitted, otherwise the message is received successfully, and the judgement fails and the message is not processed.
if (rt_mq_recv(&phone_mq, &recv_msg, sizeof(recv_msg), RT_WAITING_FOREVER) == RT_EOK) /* 【== RT_EOK不能丢,否则无法进入接收,原因是RT_EOK是0 】 */

 

to sum up

  • Use RT-Thread correctly to solve the problem of data and command exchange between threads, which can be used for data transmission
  • Familiar with the communication IPC between threads.

Guess you like

Origin blog.csdn.net/tcjy1000/article/details/114900996