/**
* @file CM_MQ_LIGHT.c
* @brief 实现轻型消息队列（非线程安全）的封装
* @author GT-BU
* @date 2021.02.01
* @version V1.0
* @copyright TCT
* @par 修改日志
* <table>
* <tr><th>Date        <th>Version  <th>Author     <th>Description
* <tr><td>2021.02.01  <td>V1.0     <td>GT-BU      <td>创建初始版本
* </table>
*/
#include "CM_MQ_Light.h"
#include "CM_Memory.h"

#define CM_MQ_LIGHT_MSG_NUM_MAX (60000u)   /**< 最大消息条数 */
#define CM_MQ_LIGHT_MSG_SIZE_MAX (65535u)  /**< 单条消息最大长度 */

/**
* @brief 消息队列读取
* @param pMQ 要读的消息队列
* @param pOutBuf 要输出消息的缓冲区
* @param pSize 作为输入参数时为输出的缓冲区消息大小，作为输出参数为读到的消息大小
* @return 执行结果
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
ENUM_CM_RETURN CM_MQ_Light_Read(INOUT CM_MQ_Light_Struct_T* pMQ, OUT CM_UINT8* pOutBuf, INOUT CM_UINT16* pBufSize)
{
    /*- 变量初始化 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    /*- 入口参数是否非法 */
    if ((NULL == pMQ) || (NULL == pOutBuf) || (NULL == pBufSize)
        || ((CM_UINT16)0u == pMQ->msgNum) || (CM_TRUE != pMQ->initialized))
    {
        /*- 函数执行失败 */
        rt = ENUM_CM_FALSE;
    }
    else
    {
        /*- 消息长度是否过长 */
        if (pMQ->pMQMsg[pMQ->front].msgSize > *pBufSize)
        {
            /*- 函数执行失败 */
            rt = ENUM_CM_FALSE;
        }
        else
        {
            /*- 从front位读出消息*/
            (void)CM_Memcpy((void*)pOutBuf, (CM_SIZE_T) *pBufSize, ((const void*)(pMQ->pMQMsg[pMQ->front].pMsgBuf)), ((CM_SIZE_T)(pMQ->pMQMsg[pMQ->front].msgSize)));
            *pBufSize = pMQ->pMQMsg[pMQ->front].msgSize;

            /*- 清空已读消息内容的接口*/
            rt = CM_Memset(((void*)(pMQ->pMQMsg[pMQ->front].pMsgBuf)), (CM_UINT8)0U, ((CM_SIZE_T)(pMQ->maxMsgSize)), ((CM_SIZE_T)(pMQ->maxMsgSize)));
            pMQ->pMQMsg[pMQ->front].msgSize = 0U;

            /*- 更新队列状态 */
            pMQ->front = (pMQ->front + 1) % (CM_INT32)pMQ->maxMsgNum;/*front前进一步*/
            --(pMQ->msgNum);
        }
    }

    /*- 返回函数执行结果 */
    return rt;
}

/**
* @brief 消息队列查询（仅读取而不弹出）
* @param pMQ 要读的消息队列
* @param index 要读取的消息序号
* @param pOutBuf 要输出消息的缓冲区
* @param pSize 作为输入参数时为输出的缓冲区消息大小，作为输出参数为读到的消息大小
* @return 执行结果
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
ENUM_CM_RETURN CM_MQ_Light_Get(IN const CM_MQ_Light_Struct_T* pMQ, IN CM_UINT16 index, OUT CM_UINT8* pOutBuf, INOUT CM_UINT16* pBufSize)
{
    /*- 变量初始化 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;

    /*- 入口参数是否非法 */
    if ((NULL == pMQ) || (NULL == pOutBuf) || (NULL == pBufSize)
        || (index >= pMQ->msgNum) || (CM_TRUE != pMQ->initialized))
    {
        /*- 函数执行失败 */
        rt = ENUM_CM_FALSE;
    }
    else
    {
        /*- 要读取的消息长度是否过长 */
        if (pMQ->pMQMsg[(pMQ->front + (CM_INT32)index) % (CM_INT32)pMQ->maxMsgNum].msgSize > *pBufSize)
        {
            /*- 函数执行失败 */
            rt = ENUM_CM_FALSE;
        }
        else
        {
            /*- 输出要读取的消息 */
            (void)CM_Memcpy((void*)pOutBuf, (CM_SIZE_T) *pBufSize, ((const void*)(pMQ->pMQMsg[(pMQ->front + (CM_INT32)index) % (CM_INT32)pMQ->maxMsgNum].pMsgBuf)),
                ((CM_SIZE_T)(pMQ->pMQMsg[(pMQ->front + (CM_INT32)index) % (CM_INT32)pMQ->maxMsgNum].msgSize)));
            *pBufSize = pMQ->pMQMsg[(pMQ->front + (CM_INT32)index) % (CM_INT32)pMQ->maxMsgNum].msgSize;
            /*- 函数执行成功 */
            rt = ENUM_CM_TRUE;
        }
    }
    /*- 返回函数执行结果 */
    return rt;
}

/**
* @brief 写消息队列
* @param pMQ 要写的消息队列
* @param pMsgBuf 要写的消息
* @param BufSize 要写的消息大小
* @return 执行结果
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
ENUM_CM_RETURN CM_MQ_Light_Write(INOUT CM_MQ_Light_Struct_T* pMQ, IN const CM_UINT8* pMsgBuf, IN CM_UINT16 BufSize)
{
    /*- 变量初始化 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    CM_UINT16 temp = 0U;

    /*- 入口参数是否非法 */
    if ((NULL == pMQ) || (NULL == pMsgBuf) || (BufSize > pMQ->maxMsgSize) || (BufSize == 0U)
        || (CM_TRUE != pMQ->initialized))
    {
        /*- 函数执行失败 */
        rt = ENUM_CM_FALSE;
    }
    else
    {
        /*- 找到待写入位置 */
        temp = pMQ->maxMsgNum - (CM_UINT16)1u;/*计算temp*/
        /*- 消息队列是否已满*/
        if (temp == pMQ->msgNum)/*如果当前消息数=max-1 表示满了*/
        {
            /*- 函数执行失败 */
            rt = ENUM_CM_FALSE;
        }
        else
        {
            /*- 在队尾写入消息 */
            (void)CM_Memcpy(((void*)(pMQ->pMQMsg[pMQ->rear].pMsgBuf)), (CM_SIZE_T)(pMQ->maxMsgSize), (const void*)pMsgBuf, (size_t)BufSize);/*复制消息进入rear位*/
            pMQ->pMQMsg[pMQ->rear].msgSize = BufSize;

            /*- 更新队尾指针和消息总数 */
            pMQ->rear = (pMQ->rear + 1) % (CM_INT32)pMQ->maxMsgNum;/*rear前进一步*/
            ++(pMQ->msgNum);/*当前消息数++*/

            /*- 函数执行成功 */
            rt = ENUM_CM_TRUE;
        }
    }
    /*- 返回函数执行结果 */
    return rt;
}

/**
* @brief 消息队列初始化
* @param pMQ 要初始化的消息队列
* @param maxMsgNum 消息队列大小
* @param maxMsgSize 每条消息的大小
* @return 执行结果
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
ENUM_CM_RETURN CM_MQ_Light_Init(INOUT CM_MQ_Light_Struct_T* pMQ, IN CM_UINT16 maxMsgNum, IN CM_UINT16 maxMsgSize)
{
    /*- 变量初始化 */
    CM_UINT16 i = 0U;
    CM_INT16 j = 0;
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    ENUM_CM_RETURN errorFlag = ENUM_CM_TRUE;
    /*- 入口参数是否非法 */
    if ((NULL == pMQ) || (0U == maxMsgNum) || (0U == maxMsgSize)
        || ((CM_UINT16)CM_MQ_LIGHT_MSG_NUM_MAX < maxMsgNum) || ((CM_UINT16)CM_MQ_LIGHT_MSG_SIZE_MAX < maxMsgSize))
    {
        /*- 函数执行失败 */
        rt = ENUM_CM_FALSE;
    }
    /*- 消息队列是否已经初始化过 */
    else if (CM_TRUE == pMQ->initialized)
    {
        /*- 函数执行成功 */
        rt = ENUM_CM_TRUE;
    }
    else
    {
        /*- 初始化消息队列为空 */
        pMQ->pMQMsg = NULL;

        pMQ->msgNum = (CM_UINT16)0u;
        pMQ->front = 0;
        pMQ->rear = 0;
        pMQ->maxMsgNum = maxMsgNum + 1U;/*改为maxMsgNum+1，使用户可以初始最大数与可放最大数相等*/
        pMQ->maxMsgSize = maxMsgSize;
        /*- 为消息队列分配内存 */
        pMQ->pMQMsg = (CM_MQ_Light_Msg_Struct_T*)CM_Malloc(sizeof(CM_MQ_Light_Msg_Struct_T) * pMQ->maxMsgNum);

        /*- 内存分配是否失败 */
        if (NULL == pMQ->pMQMsg)
        {
            /*- 函数执行失败 */
            rt = ENUM_CM_FALSE;
        }
        else
        {
            /*- 函数执行成功 */
            rt = ENUM_CM_TRUE;
            /*- @alias 逐条消息划分内存 */
            for (i = (CM_UINT16)0u; i < pMQ->maxMsgNum; ++i)
            {
                pMQ->pMQMsg[i].pMsgBuf = (CM_UINT8*)CM_Malloc((CM_SIZE_T)(pMQ->maxMsgSize));

                /** @brief 如果初始化失败,则释放之前分配的资源 */

                if (NULL == pMQ->pMQMsg[i].pMsgBuf)
                {
                    for (j = (CM_INT16)i - (CM_INT16)1; j >= (CM_INT16)0; --j)
                    {
                        CM_Free(((void*)(pMQ->pMQMsg[j].pMsgBuf)));
                        pMQ->pMQMsg[j].pMsgBuf = NULL;
                    }

                    CM_Free((void*)(pMQ->pMQMsg));

                    pMQ->pMQMsg = NULL;  /* parasoft-suppress BD-RES-LEAKS "误报" */
                    rt = ENUM_CM_FALSE;
                    /*- 跳出 */
                    break;
                }
                else
                {
                    pMQ->pMQMsg[i].msgSize = (CM_UINT16)0u;
                    rt = CM_Memset(((void*)(pMQ->pMQMsg[i].pMsgBuf)), (CM_UINT8)0U, ((size_t)(pMQ->maxMsgSize)), ((size_t)(pMQ->maxMsgSize)));
                    if(ENUM_CM_FALSE == rt)
                    {
                    	errorFlag = ENUM_CM_FALSE;
                    }
                }
            }
            /*- 消息队列初始化成功 */
            pMQ->initialized = CM_TRUE;
            if(ENUM_CM_FALSE == errorFlag)
            {
            	rt = ENUM_CM_FALSE;
            }
            else
            {
            	/*- 无处理 */
            }
        }
    }
    /*- 返回执行结果 */
    return rt;
}

/**
* @brief 清空消息队列
* @param pMQ 要清空的消息队列
* @return 执行结果
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
ENUM_CM_RETURN CM_MQ_Light_Clear(INOUT CM_MQ_Light_Struct_T* pMQ)
{
    /*- 变量初始化 */
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    /*- 入口参数是否非法 */
    if ((NULL == pMQ) || (CM_TRUE != pMQ->initialized))
    {
        /*- 函数执行失败 */
        rt = ENUM_CM_FALSE;
    }
    else
    {
        /*- 消息队列置为空 */
        pMQ->msgNum = (CM_UINT16)0u;
        pMQ->front = 0;
        pMQ->rear = 0;
        /*- 函数执行成功 */
        rt = ENUM_CM_TRUE;
    }
    /*- 返回函数执行结果 */
    return rt;
}

/**
* @brief 获取消息队列中的消息条数
* @param pMQ 要获得消息个数的消息队列
* @return CM_INT32 若失败则返回-1,否则返回消息个数
*/
CM_INT32 CM_MQ_Light_Get_Msg_Num(IN const CM_MQ_Light_Struct_T* pMQ)
{
    /*- 变量初始化 */
    CM_INT32 rt = -1;
    /*- 入口参数是否非法 */
    if ((NULL == pMQ) || (CM_TRUE != pMQ->initialized))
    {
        /*- 返回-1 */
        rt = -1;
    }
    else
    {
        /*- 返回消息条数 */
        rt = (CM_INT32)(pMQ->msgNum);
    }
    /*- 返回 */
    return rt;
}

/**
* @brief 清零消息队列
* @param pMQ 要清零的消息队列
* @return 执行结果
* - ENUM_CM_TRUE 执行成功
* - ENUM_CM_FALSE 执行失败
*/
ENUM_CM_RETURN CM_MQ_Light_Flush(INOUT CM_MQ_Light_Struct_T* pMQ)
{
    /*- 变量初始化 */
    CM_UINT16 msgIndex = 0U;
    ENUM_CM_RETURN rt = ENUM_CM_FALSE;
    ENUM_CM_RETURN errorFlag = ENUM_CM_TRUE;
    /*- 入口参数是否非法 */
    if ((NULL == pMQ) || (CM_TRUE != pMQ->initialized))
    {
        /*- 函数执行失败 */
        rt = ENUM_CM_FALSE;
    }
    else
    {
        /*- @alias 将所有消息的消息内容清零 */
        for (msgIndex = 0u; msgIndex < (pMQ->maxMsgNum); ++msgIndex)
        {
            pMQ->pMQMsg[msgIndex].msgSize = 0u;
            rt = CM_Memset(((void*)(pMQ->pMQMsg[msgIndex].pMsgBuf)), (CM_UINT8)0u, (size_t)(pMQ->maxMsgSize), (size_t)(pMQ->maxMsgSize));
            if(ENUM_CM_FALSE == rt)
			{
				errorFlag = ENUM_CM_FALSE;
			}
        }

        /*- 消息队列置为空 */
        pMQ->front = 0;
        pMQ->rear = 0;
        pMQ->msgNum = (CM_UINT16)0u;
        /*- 函数执行成功 */
        if(ENUM_CM_FALSE == errorFlag)
		{
			rt = ENUM_CM_FALSE;
		}
		else
		{
			rt = ENUM_CM_TRUE;
		}
    }
    /*- 返回执行结果 */
    return rt;
}
