/*
 * 程序清单：消息队列例程
 *
 * 这个程序会创建2个动态线程，一个线程会从消息队列中收取消息；一个线程会定时给消
 * 息队列发送 普通消息和紧急消息。
 */
#include <rtthread.h>

#define THREAD_PRIORITY      25
#define THREAD_TIMESLICE     5

/* 消息队列控制块 */
static struct rt_messagequeue mq;
/* 消息队列中用到的放置消息的内存池 */
static rt_uint8_t msg_pool[2048];

static char thread1_stack[1024];
static struct rt_thread thread1;

/* 线程1入口函数 */
static void thread1_entry(void *parameter)
{
    char buf = 0;  // 用于接收消息的缓冲区
    rt_uint8_t cnt = 0;  // 消息计数器

    while (1)
    {
        /* 从消息队列中接收消息 */
        if (rt_mq_recv(&mq, &buf, sizeof(buf), RT_WAITING_FOREVER) > 0)
        {
            rt_kprintf("thread1: recv msg from msg queue, the content: %c\n", buf);
            if (cnt == 19)
            {
                break;  // 接收20次消息后退出
            }
        }
        /* 延时50ms */
        cnt++;
        rt_thread_mdelay(50);
    }
    rt_kprintf("thread1: detach mq \n");
    rt_mq_detach(&mq);  // 脱离消息队列
}

static char thread2_stack[1024];
static struct rt_thread thread2;

/* 线程2入口 */
static void thread2_entry(void *parameter)
{
    int result;
    char buf = 'A';  // 要发送的消息内容
    rt_uint8_t cnt = 0;  // 消息计数器

    while (1)
    {
        if (cnt == 8)
        {
            /* 发送紧急消息到消息队列中 */
            result = rt_mq_urgent(&mq, &buf, 1);
            if (result != RT_EOK)
            {
                rt_kprintf("rt_mq_urgent ERR\n");
            }
            else
            {
                rt_kprintf("thread2: send urgent message - %c\n", buf);
            }
        }
        else if (cnt >= 20) /* 发送20次消息之后退出 */
        {
            rt_kprintf("message queue stop send, thread2 quit\n");
            break;
        }
        else
        {
            /* 发送消息到消息队列中 */
            result = rt_mq_send(&mq, &buf, 1);
            if (result != RT_EOK)
            {
                rt_kprintf("rt_mq_send ERR\n");
            }

            rt_kprintf("thread2: send message - %c\n", buf);
        }
        buf++;
        cnt++;
        /* 延时5ms */
        rt_thread_mdelay(5);
    }
}

/* 消息队列示例的初始化 */
int msgq_sample(void)
{
    rt_err_t result;

    /* 初始化消息队列 */
    result = rt_mq_init(&mq,
                        "mqt",                       /* 名称是mqt */
                        &msg_pool[0],                /* 内存池指向msg_pool */
                        1,                           /* 每个消息的大小是1字节 */
                        sizeof(msg_pool),            /* 内存池的大小是msg_pool的大小 */
                        RT_IPC_FLAG_PRIO);           /* 如果有多个线程等待，按照优先级的方式分配消息 */

    if (result != RT_EOK)
    {
        rt_kprintf("init message queue failed.\n");
        return -1;
    }

    /* 初始化线程1 */
    rt_thread_init(&thread1,
                   "thread1",                       /* 线程名称 */
                   thread1_entry,                   /* 线程入口函数 */
                   RT_NULL,                         /* 入口函数参数 */
                   &thread1_stack[0],               /* 线程栈起始地址 */
                   sizeof(thread1_stack),           /* 线程栈大小 */
                   THREAD_PRIORITY, THREAD_TIMESLICE); /* 线程优先级和时间片大小 */

    /* 启动线程1 */
    rt_thread_startup(&thread1);

    /* 初始化线程2 */
    rt_thread_init(&thread2,
                   "thread2",                       /* 线程名称 */
                   thread2_entry,                   /* 线程入口函数 */
                   RT_NULL,                         /* 入口函数参数 */
                   &thread2_stack[0],               /* 线程栈起始地址 */
                   sizeof(thread2_stack),           /* 线程栈大小 */
                   THREAD_PRIORITY-1, THREAD_TIMESLICE); /* 线程优先级和时间片大小 */

    /* 启动线程2 */
    rt_thread_startup(&thread2);

    return 0;
}

/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(msgq_sample, msgq sample);