Liteos读写消息队列的时候提供了不带拷贝和拷贝两种方式。不带拷贝的方式操作的是指针,这也就要求保存原始数据地址中的内容在读出之前不能更改,否则进行读消息队列的时候就会读到错误的内容;拷贝的方式会将原始数据拷贝到创建消息队列时开辟的内存空间中,即使原始数据地址中的内容被改变也不会对消息队列中数据造成影响。函数原型如下:
不带拷贝:
LITE_OS_SEC_TEXT UINT32 LOS_QueueRead(UINT32 uwQueueID, VOID *pBufferAddr, UINT32 uwBufferSize, UINT32 uwTimeOut)
LITE_OS_SEC_TEXT UINT32 LOS_QueueWrite(UINT32 uwQueueID, VOID *pBufferAddr, UINT32 uwBufferSize, UINT32 uwTimeOut)
拷贝:
LITE_OS_SEC_TEXT UINT32 LOS_QueueReadCopy(UINT32 uwQueueID, //消息队列句柄
VOID * pBufferAddr, //读出数据缓冲区
UINT32 * puwBufferSize, //读出数据长度
UINT32 uwTimeOut) //超时时间
LITE_OS_SEC_TEXT UINT32 LOS_QueueWriteCopy( UINT32 uwQueueID, //消息队列句柄
VOID * pBufferAddr, //写入数据缓冲区
UINT32 uwBufferSize, //写入数据长度
UINT32 uwTimeOut ) //超时时间
uwQueueID为创建消息队列的时候返回的句柄,读写消息队列时都需要用到,用来查找要操作的消息队列控制块。
创建消息队列:
#define TEST_QUEUE_LEN 16
#define TEST_QUEUE_SIZE 20
UINT32 uwRet = LOS_OK;
uwRet = LOS_QueueCreate("test_queue",TEST_QUEUE_LEN,&test_queue_handle,0,TEST_QUEUE_SIZE);
if(uwRet != LOS_OK)
{
PRINT_ERR("Queue Error Code:0x%X\n",uwRet);
return uwRet;
}
创建消息队列的时候,需要用到TEST_QUEUE_LEN 和TEST_QUEUE_SIZE,其中TEST_QUEUE_LEN表示消息队列的长度,TEST_QUEUE_SIZE表示消息队列每个节点的大小(字节),创建成功后消息队列可存储16条数据,每条数据最大20字节。创建成功后通过跟踪调试获取到消息队列存储区地址,可以看到消息队列的存储区已经初始化为0x00。
向消息队列写入数据:
UINT32 uwRet = LOS_OK;
UINT8 senddata[20];
UINT32 senddatalen = 0;
UINT32 count = 1;
memset(senddata,0x00,20);
senddatalen = sprintf((char *)senddata,"hello = %d",count);
uwRet = LOS_QueueWriteCopy(test_queue_handle,&senddata,senddatalen,LOS_NO_WAIT);
if(uwRet != LOS_OK)
{
PRINT_ERR("Queue Write Error Code:0x%X\n",uwRet);
}
senddata为写入数据缓冲区,senddatalen为写入数据的实际长度,写入成功后可以在存储区看到写入的内容。创建消息队列的时候每个节点大小是20字节,实际上每写入一条数据时也会把对应的长度写入,即为9,也就是说每写入一条数据,占用的存储区大小为(节点大小+4)。
从消息队列读出数据:
UINT32 uwRet = LOS_OK;
UINT32 recvdatalen = 0;
UINT8 recvdata[20];
recvdatalen = 20;
uwRet = LOS_QueueReadCopy(test_queue_handle,recvdata,&recvdatalen,LOS_WAIT_FOREVER);
if(uwRet == LOS_OK)
{
HAL_UART_Transmit(&huart1,recvdata,recvdatalen,0xFFFF);
}
else
{
PRINT_ERR("Queue Read Error Code:0x%X\n",uwRet);
}
recvdata为读出数据缓冲区,recvdatalen为读出数据长度。要注意的是在执行LOS_QueueReadCopy函数时传入的recvdatalen必须为消息队列节点的大小,即为20,否则会导致读出失败,因为在实际操作消息队列的函数osQueueOperate中有对recvdatalen的判断,pstQueueCB->usQueueSize的值为(节点大小+4),*puwBufferSize为传入的recvdatalen。读取成功后recvdatalen为读出数据的实际长度。
if(OS_QUEUE_IS_READ(uwOperateType) && (*puwBufferSize < pstQueueCB->usQueueSize - sizeof(UINT32)))
{
uwRet = LOS_ERRNO_QUEUE_READ_SIZE_TOO_SMALL;
goto QUEUE_END;
}
在使用消息队列的时候如果队列为满,那么是不能写入数据的。对于可能有数据堆积时,如果存储空间不足需要丢弃最早数据的场景下,就需要先读出一条数据,再写入一条数据。Liteos的消息系列支持先进先出(FIFO)的模式,这样就可以满足需求。
通过LOS_QueueInfoGet函数可以获取消息队列控制块,进而判断消息队列是否为满。
QUEUE_INFO_S pstQueueInfo;
uwRet = LOS_QueueInfoGet(test_queue_handle,&pstQueueInfo);
if(uwRet == LOS_OK)
{
PRINT_INFO("Queue Read Cnt:%d\n",pstQueueInfo.usReadableCnt);
PRINT_INFO("Queue Write Cnt:%d\n",pstQueueInfo.usWritableCnt);
}
pstQueueInfo.usReadableCnt为消息队列可读消息数,如果为0表示消息队列为空;pstQueueInfo.usWritableCnt为消息队列可写消息数,如果为0表示消息队列为满。