/**
* @file CM_MQ.h
* @brief 实现消息队列的封装（线程安全）
* @author GT-BU
* @date 2021.05.01
* @version V1.0
* @copyright TCT
* @par 修改日志
* <table>
* <tr><th>Date        <th>Version  <th>Author     <th>Description
* <tr><td>2021.05.01  <td>V1.0     <td>GT-BU      <td>创建初始版本
* </table>
*/
#ifndef CM_MQ_H
#define CM_MQ_H

#include "CM_Mutex.h"

#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */

    /** 消息 */
    typedef struct
    {
        CM_UINT16 msgSize;     /**< 消息长度 */
        CM_UINT16 again_msgSize;     /**< 二次读取的消息长度 */
        CM_UINT8* pMsgBuf;     /**< 消息数组 */
    }CM_MQ_Msg_Struct_T;

    /** 消息队列 */
    typedef struct
    {
        CM_BOOL initialized;   /**< 是否初始化了         */
        CM_UINT16 maxMsgNum;   /**< MQ中最大消息个数     */
        CM_UINT16 maxMsgSize;  /**< 每条消息的最大字节数 */
        CM_INT32 front;        /**< 头指针               */
        CM_INT32 rear;         /**< 尾指针               */
        CM_UINT16 msgNum;      /**< 消息队列中消息个数   */
        CM_MUTEX_T mutex;        /**< 互斥信号量 */
        CM_MQ_Msg_Struct_T* pMQMsg; /**< 指向第一条消息    */
    }CM_MQ_Struct_T;

    /**
    * @brief 消息队列初始化
    * @param[inout] pMQ 要初始化的消息队列
    * @param[in] maxMsgNum 消息队列大小
    * @param[in] maxMsgSize 每条消息的大小
    * @return 执行结果
    * - ENUM_CM_TRUE 成功
    * - ENUM_CM_FALSE 失败
    */
    ENUM_CM_RETURN CM_MQ_Init(INOUT CM_MQ_Struct_T* pMQ, IN CM_UINT16 maxMsgNum, IN CM_UINT16 maxMsgSize);

    /**
    * @brief 查看队列中消息总数
    * @param[in] pMQ 要获得消息个数的消息队列
    * @return CM_INT32 若失败则返回-1,否则返回消息个数
    */
    CM_INT32 CM_MQ_Get_Msg_Num(IN const CM_MQ_Struct_T* pMQ);

    /**
    * @brief 写消息队列
    * @param[in] pMQ 要写的消息队列
    * @param[in] pMsgBuf 要写的消息
    * @param[in] size 要写的消息大小
    * @return 执行结果
    * - ENUM_CM_TRUE 成功
    * - ENUM_CM_FALSE 失败
    */
    ENUM_CM_RETURN CM_MQ_Write(INOUT CM_MQ_Struct_T* pMQ, IN const CM_UINT8* pMsgBuf, IN CM_UINT16 BufSize);

    /**
    * @brief 读消息队列
    * @param[in] pMQ 要读的消息队列
    * @param[out] pOutBuf 要输出消息的缓冲区
    * @param[inout] pSize 作为输入参数时为输出的缓冲区消息大小，作为输出参数为读到的消息大小
    * @return 执行结果
    * - ENUM_CM_TRUE 成功
    * - ENUM_CM_FALSE 失败
    */
    ENUM_CM_RETURN CM_MQ_Read(INOUT CM_MQ_Struct_T* pMQ, OUT CM_UINT8* pOutBuf, INOUT CM_UINT16* pBufSize);
    /**
    * @brief 消息队列读取
    * @param pMQ 要读的消息队列
    * @param pOutBuf 要输出消息的缓冲区
    * @param pSize 作为输入参数时为输出的缓冲区消息大小，作为输出参数为读到的消息大小
    * @return 执行结果
    * - ENUM_CM_TRUE 执行成功
    * - ENUM_CM_FALSE 执行失败
    */
    ENUM_CM_RETURN CM_MQ_Again_Read(INOUT CM_MQ_Struct_T* pMQ, IN CM_UINT16 index, OUT CM_UINT8* pOutBuf, INOUT CM_UINT16* pBufSize);
    /**
    * @brief 消息队列清空（一条消息）
    * @param pMQ 要清空的消息队列
    * @return 执行结果
    * - ENUM_CM_TRUE 执行成功
    * - ENUM_CM_FALSE 执行失败
    */
    ENUM_CM_RETURN CM_MQ_Read_Clear(INOUT CM_MQ_Struct_T* pMQ);
    /**
    * @brief 从指定位置读取消息队列(一条消息分别读到两个缓冲区)
    * @param pMQ 要读的消息队列
    * @param pOutBuf 要输出消息的缓冲区
    * @param pSize 作为输入参数时为输出的缓冲区消息大小，作为输出参数为读到的消息大小
    * @return 执行结果
    * - ENUM_CM_TRUE 执行成功
    * - ENUM_CM_FALSE 执行失败
    */
    CM_UINT8* CM_MQ_Read_Addr(INOUT CM_MQ_Struct_T* pMQ,INOUT CM_UINT16* pBufSize);
    /**
    * @brief 查看消息队列
    *
    * 仅读取数据，而不弹出.
    * @param[in] pMQ 要查看的消息队列
    * @param[in] index 要查看的消息索引（从0开始）
    * @param[out] pOutBuf 要输出的消息缓冲区
    * @param[inout] pSize 作为输入参数时为输出的缓冲区消息大小，作为输出参数为读到的消息大小
    * @return 执行结果
    * - ENUM_CM_TRUE 成功
    * - ENUM_CM_FALSE 失败
    */
    ENUM_CM_RETURN CM_MQ_Get(IN const CM_MQ_Struct_T* pMQ, IN CM_UINT16 index, OUT CM_UINT8* pOutBuf, INOUT CM_UINT16* pBufSize);

    /**
    * @brief 清空消息队列
    * @param[inout] pMQ 要清空的消息队列
    * @return 执行结果
    * - ENUM_CM_TRUE 成功
    * - ENUM_CM_FALSE 失败
    * @note 清空队列，但消息数据缓冲区不清零，执行速度较快
    */
    ENUM_CM_RETURN CM_MQ_Clear(INOUT CM_MQ_Struct_T* pMQ);

    /**
    * @brief 清零消息队列
    * @param[inout] pMQ 要清零的消息队列
    * @return 执行结果
    * - ENUM_CM_TRUE 成功
    * - ENUM_CM_FALSE 失败
    * @note 清空队列，消息数据缓冲区也置零，执行速度较慢
    */
    ENUM_CM_RETURN CM_MQ_Flush(INOUT CM_MQ_Struct_T* pMQ);
    CM_UINT8* CM_MQ_Get_BufAddr(INOUT CM_MQ_Struct_T* pMQ);
    ENUM_CM_RETURN CM_MQ_UpData(INOUT CM_MQ_Struct_T* pMQ,IN CM_UINT16 BufSize);
    ENUM_CM_RETURN CM_MQ_Read_UpData(INOUT CM_MQ_Struct_T* pMQ);
    /*消息队列回滚*/
    ENUM_CM_RETURN CM_MQ_RollbackData(INOUT CM_MQ_Struct_T* pMQ);
#ifdef __cplusplus
}

#endif /* __cplusplus */

#endif /* _CM_MQ_LIGHT_H */

