mirror of
https://github.com/espressif/openthread.git
synced 2026-08-26 20:19:53 +00:00
Adding otMessageQueue OpenThread C APIs and their unit test (#1115)
This commit is contained in:
committed by
Jonathan Hui
parent
23396a30f8
commit
3fbba0eced
@@ -29,7 +29,7 @@
|
||||
/**
|
||||
* @file
|
||||
* @brief
|
||||
* This file defines the top-level ip6 functions for the OpenThread library.
|
||||
* This file defines the top-level OpenThread APIs related to message buffer and queues.
|
||||
*/
|
||||
|
||||
#ifndef OPENTHREAD_MESSAGE_H_
|
||||
@@ -229,6 +229,65 @@ int otReadMessage(otMessage aMessage, uint16_t aOffset, void *aBuf, uint16_t aLe
|
||||
*/
|
||||
int otWriteMessage(otMessage aMessage, uint16_t aOffset, const void *aBuf, uint16_t aLength);
|
||||
|
||||
/**
|
||||
*
|
||||
* Initialize the message queue.
|
||||
*
|
||||
* This function MUST be called once and only once for a `otMessageQueue` instance before any other `otMessageQueue`
|
||||
* functions. The behavior is undefined if other queue APIs are used with an `otMessageQueue` before it being
|
||||
* initialized or if it is initialized more than once.
|
||||
*
|
||||
* @param[in] aQueue A pointer to a message queue.
|
||||
*
|
||||
*/
|
||||
void otMessageQueueInit(otMessageQueue *aQueue);
|
||||
|
||||
/**
|
||||
* This function adds a message to the end of the given message queue.
|
||||
*
|
||||
* @param[in] aQueue A pointer to the message queue.
|
||||
* @param[in] aMessage The message to add.
|
||||
*
|
||||
* @retval kThreadError_None Successfully added the message to the queue.
|
||||
* @retval kThreadError_Already The message is already enqueued in a queue.
|
||||
*
|
||||
*/
|
||||
ThreadError otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage aMessage);
|
||||
|
||||
/**
|
||||
* This function removes a message from the given message queue.
|
||||
*
|
||||
* @param[in] aQueue A pointer to the message queue.
|
||||
* @param[in] aMessage The message to remove.
|
||||
*
|
||||
* @retval kThreadError_None Successfully removed the message from the queue.
|
||||
* @retval kThreadError_NotFound The message is not enqueued in this queue.
|
||||
*
|
||||
*/
|
||||
ThreadError otMessageQueueDequeue(otMessageQueue *aQueue, otMessage aMessage);
|
||||
|
||||
/**
|
||||
* This function returns a pointer to the message at the head of the queue.
|
||||
*
|
||||
* @param[in] aQueue A pointer to a message queue.
|
||||
*
|
||||
* @returns A pointer to the message at the head of queue or NULL if queue is empty.
|
||||
*
|
||||
*/
|
||||
otMessage otMessageQueueGetHead(otMessageQueue *aQueue);
|
||||
|
||||
/**
|
||||
* This function returns a pointer to the next message in the queue by iterating forward (from head to tail).
|
||||
*
|
||||
* @param[in] aQueue A pointer to a message queue.
|
||||
* @param[in] aMessage A pointer to current message buffer.
|
||||
*
|
||||
* @returns A pointer to the next message in the queue after `aMessage` or NULL if `aMessage is the tail of queue.
|
||||
* NULL is returned if `aMessage` is not in the queue `aQueue`.
|
||||
*
|
||||
*/
|
||||
otMessage otMessageQueueGetNext(otMessageQueue *aQueue, const otMessage aMessage);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -959,6 +959,14 @@ typedef struct
|
||||
*/
|
||||
typedef void *otMessage;
|
||||
|
||||
/**
|
||||
* This structure represents an OpenThread message queue.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
void *mData; ///< Opaque data used by the implementation.
|
||||
} otMessageQueue;
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
+12
-12
@@ -874,9 +874,9 @@ void Message::SetPriorityQueue(PriorityQueue *aPriorityQueue)
|
||||
mInfo.mInPriorityQ = true;
|
||||
}
|
||||
|
||||
MessageQueue::MessageQueue(void) :
|
||||
mTail(NULL)
|
||||
MessageQueue::MessageQueue(void)
|
||||
{
|
||||
SetTail(NULL);
|
||||
}
|
||||
|
||||
void MessageQueue::AddToList(uint8_t aList, Message &aMessage)
|
||||
@@ -885,36 +885,36 @@ void MessageQueue::AddToList(uint8_t aList, Message &aMessage)
|
||||
|
||||
assert((aMessage.Next(aList) == NULL) && (aMessage.Prev(aList) == NULL));
|
||||
|
||||
if (mTail == NULL)
|
||||
if (GetTail() == NULL)
|
||||
{
|
||||
aMessage.Next(aList) = &aMessage;
|
||||
aMessage.Prev(aList) = &aMessage;
|
||||
}
|
||||
else
|
||||
{
|
||||
head = mTail->Next(aList);
|
||||
head = GetTail()->Next(aList);
|
||||
|
||||
aMessage.Next(aList) = head;
|
||||
aMessage.Prev(aList) = mTail;
|
||||
aMessage.Prev(aList) = GetTail();
|
||||
|
||||
head->Prev(aList) = &aMessage;
|
||||
mTail->Next(aList) = &aMessage;
|
||||
GetTail()->Next(aList) = &aMessage;
|
||||
}
|
||||
|
||||
mTail = &aMessage;
|
||||
SetTail(&aMessage);
|
||||
}
|
||||
|
||||
void MessageQueue::RemoveFromList(uint8_t aList, Message &aMessage)
|
||||
{
|
||||
assert((aMessage.Next(aList) != NULL) && (aMessage.Prev(aList) != NULL));
|
||||
|
||||
if (&aMessage == mTail)
|
||||
if (&aMessage == GetTail())
|
||||
{
|
||||
mTail = mTail->Prev(aList);
|
||||
SetTail(GetTail()->Prev(aList));
|
||||
|
||||
if (&aMessage == mTail)
|
||||
if (&aMessage == GetTail())
|
||||
{
|
||||
mTail = NULL;
|
||||
SetTail(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -927,7 +927,7 @@ void MessageQueue::RemoveFromList(uint8_t aList, Message &aMessage)
|
||||
|
||||
Message *MessageQueue::GetHead(void) const
|
||||
{
|
||||
return (mTail == NULL) ? NULL : mTail->Next(MessageInfo::kListInterface);
|
||||
return (GetTail() == NULL) ? NULL : GetTail()->Next(MessageInfo::kListInterface);
|
||||
}
|
||||
|
||||
ThreadError MessageQueue::Enqueue(Message &aMessage)
|
||||
|
||||
+18
-12
@@ -610,6 +610,14 @@ public:
|
||||
*/
|
||||
uint16_t UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const;
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the message queue (if any) where this message is queued.
|
||||
*
|
||||
* @returns A pointer to the message queue or NULL if not in any message queue.
|
||||
*
|
||||
*/
|
||||
MessageQueue *GetMessageQueue(void) const { return (!mInfo.mInPriorityQ) ? mInfo.mMessageQueue : NULL; }
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
@@ -636,14 +644,6 @@ private:
|
||||
*/
|
||||
bool IsInAQueue(void) const { return (mInfo.mMessageQueue != NULL); }
|
||||
|
||||
/**
|
||||
* This method returns a pointer to the message queue (if any) where this message is queued.
|
||||
*
|
||||
* @returns A pointer to the message queue or NULL if not in any message queue.
|
||||
*
|
||||
*/
|
||||
MessageQueue *GetMessageQueue(void) const { return (!mInfo.mInPriorityQ) ? mInfo.mMessageQueue : NULL; }
|
||||
|
||||
/**
|
||||
* This method sets the message queue information for the message.
|
||||
*
|
||||
@@ -738,7 +738,7 @@ private:
|
||||
* This class implements a message queue.
|
||||
*
|
||||
*/
|
||||
class MessageQueue
|
||||
class MessageQueue : public otMessageQueue
|
||||
{
|
||||
friend class Message;
|
||||
friend class PriorityQueue;
|
||||
@@ -797,7 +797,15 @@ private:
|
||||
* @returns A pointer to the tail of the list.
|
||||
*
|
||||
*/
|
||||
Message *GetTail(void) const { return mTail; }
|
||||
Message *GetTail(void) const { return static_cast<Message *>(mData); }
|
||||
|
||||
/**
|
||||
* This method set the tail of the list.
|
||||
*
|
||||
* @param[in] aMessage A pointer to the message to set as new tail.
|
||||
*
|
||||
*/
|
||||
void SetTail(Message *aMessage) { mData = aMessage; }
|
||||
|
||||
/**
|
||||
* This method adds a message to a list.
|
||||
@@ -816,8 +824,6 @@ private:
|
||||
*
|
||||
*/
|
||||
void RemoveFromList(uint8_t aListId, Message &aMessage);
|
||||
|
||||
Message *mTail; ///< A pointer to the last Message in the list.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -1489,6 +1489,45 @@ int otWriteMessage(otMessage aMessage, uint16_t aOffset, const void *aBuf, uint1
|
||||
return message->Write(aOffset, aLength, aBuf);
|
||||
}
|
||||
|
||||
void otMessageQueueInit(otMessageQueue *aQueue)
|
||||
{
|
||||
aQueue->mData = NULL;
|
||||
}
|
||||
|
||||
ThreadError otMessageQueueEnqueue(otMessageQueue *aQueue, otMessage aMessage)
|
||||
{
|
||||
Message *message = static_cast<Message *>(aMessage);
|
||||
MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
|
||||
return queue->Enqueue(*message);
|
||||
}
|
||||
|
||||
ThreadError otMessageQueueDequeue(otMessageQueue *aQueue, otMessage aMessage)
|
||||
{
|
||||
Message *message = static_cast<Message *>(aMessage);
|
||||
MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
|
||||
return queue->Dequeue(*message);
|
||||
}
|
||||
|
||||
otMessage otMessageQueueGetHead(otMessageQueue *aQueue)
|
||||
{
|
||||
MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
|
||||
return queue->GetHead();
|
||||
}
|
||||
|
||||
otMessage otMessageQueueGetNext(otMessageQueue *aQueue, otMessage aMessage)
|
||||
{
|
||||
Message *next;
|
||||
Message *message = static_cast<Message *>(aMessage);
|
||||
MessageQueue *queue = static_cast<MessageQueue *>(aQueue);
|
||||
|
||||
VerifyOrExit(message != NULL, next = NULL);
|
||||
VerifyOrExit(message->GetMessageQueue() == queue, next = NULL);
|
||||
next = message->GetNext();
|
||||
|
||||
exit:
|
||||
return next;
|
||||
}
|
||||
|
||||
ThreadError otOpenUdpSocket(otInstance *aInstance, otUdpSocket *aSocket, otUdpReceive aCallback, void *aCallbackContext)
|
||||
{
|
||||
ThreadError error = kThreadError_InvalidArgs;
|
||||
|
||||
@@ -27,9 +27,14 @@
|
||||
*/
|
||||
|
||||
#include "test_util.h"
|
||||
|
||||
#include <openthread.h>
|
||||
#include <openthread-message.h>
|
||||
#include <openthread-ip6.h>
|
||||
|
||||
#include <common/debug.hpp>
|
||||
#include <common/message.hpp>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
@@ -72,6 +77,7 @@ void TestMessageQueue(void)
|
||||
Thread::MessagePool messagePool;
|
||||
Thread::MessageQueue messageQueue;
|
||||
Thread::Message *msg[kNumTestMessages];
|
||||
ThreadError error;
|
||||
uint16_t msgCount, bufferCount;
|
||||
|
||||
for (int i = 0; i < kNumTestMessages; i++)
|
||||
@@ -131,12 +137,127 @@ void TestMessageQueue(void)
|
||||
VerifyMessageQueueContent(messageQueue, 1, msg[0]);
|
||||
SuccessOrQuit(messageQueue.Dequeue(*msg[0]), "MessageQueue::Dequeue() failed.\n");
|
||||
VerifyMessageQueueContent(messageQueue, 0);
|
||||
|
||||
// Check the failure cases: Enqueue an already queued message or dequeue a message not in the queue.
|
||||
SuccessOrQuit(messageQueue.Enqueue(*msg[0]), "MessageQueue::Enqueue() failed.\n");
|
||||
VerifyMessageQueueContent(messageQueue, 1, msg[0]);
|
||||
error = messageQueue.Enqueue(*msg[0]);
|
||||
VerifyOrQuit(error == kThreadError_Already, "Enqueuing an already queued message did not fail as expected.\n");
|
||||
error = messageQueue.Dequeue(*msg[1]);
|
||||
VerifyOrQuit(error == kThreadError_NotFound, "Dequeuing a message not in the queue did not fail as expected.\n");
|
||||
}
|
||||
|
||||
// This function verifies the content of the message queue to match the passed in messages
|
||||
void VerifyMessageQueueContentUsingOtApi(otMessageQueue *aQueue, int aExpectedLength, ...)
|
||||
{
|
||||
va_list args;
|
||||
otMessage message;
|
||||
otMessage msgArg;
|
||||
|
||||
va_start(args, aExpectedLength);
|
||||
|
||||
if (aExpectedLength == 0)
|
||||
{
|
||||
message = otMessageQueueGetHead(aQueue);
|
||||
VerifyOrQuit(message == NULL, "MessageQueue is not empty when expected len is zero.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
for (message = otMessageQueueGetHead(aQueue);
|
||||
message != NULL;
|
||||
message = otMessageQueueGetNext(aQueue, message)
|
||||
)
|
||||
{
|
||||
VerifyOrQuit(aExpectedLength != 0, "MessageQueue contains more entries than expected\n");
|
||||
|
||||
msgArg = va_arg(args, otMessage);
|
||||
VerifyOrQuit(msgArg == message, "MessageQueue content does not match what is expected.\n");
|
||||
|
||||
aExpectedLength--;
|
||||
}
|
||||
|
||||
VerifyOrQuit(aExpectedLength == 0, "MessageQueue contains less entries than expected\n");
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
// This test checks all the OpenThread C APIs for `otMessageQueue`
|
||||
void TestMessageQueueOtApis(void)
|
||||
{
|
||||
otInstance *instance;
|
||||
otMessageQueue queue, queue2;
|
||||
|
||||
otMessage msg[kNumTestMessages];
|
||||
ThreadError error;
|
||||
otMessage message;
|
||||
|
||||
instance = otInstanceInit();
|
||||
VerifyOrQuit(instance != NULL, "Failed to get and init an otInstance.\n");
|
||||
|
||||
for (int i = 0; i < kNumTestMessages; i++)
|
||||
{
|
||||
msg[i] = otNewIp6Message(instance, true);
|
||||
VerifyOrQuit(msg[i] != NULL, "otNewIp6Message() failed.\n");
|
||||
}
|
||||
|
||||
otMessageQueueInit(&queue);
|
||||
otMessageQueueInit(&queue2);
|
||||
|
||||
// Check an empty queue.
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 0);
|
||||
|
||||
// Add message to the queue and check the content
|
||||
SuccessOrQuit(otMessageQueueEnqueue(&queue, msg[0]), "Failed to enqueue a message to otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 1, msg[0]);
|
||||
SuccessOrQuit(otMessageQueueEnqueue(&queue, msg[1]), "Failed to enqueue a message to otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 2, msg[0], msg[1]);
|
||||
SuccessOrQuit(otMessageQueueEnqueue(&queue, msg[2]), "Failed to enqueue a message to otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 3, msg[0], msg[1], msg[2]);
|
||||
SuccessOrQuit(otMessageQueueEnqueue(&queue, msg[3]), "Failed to enqueue a message to otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 4, msg[0], msg[1], msg[2], msg[3]);
|
||||
|
||||
// Remove elements and check the content
|
||||
SuccessOrQuit(otMessageQueueDequeue(&queue, msg[1]), "Failed to dequeue a message from otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 3, msg[0], msg[2], msg[3]);
|
||||
SuccessOrQuit(otMessageQueueDequeue(&queue, msg[0]), "Failed to dequeue a message from otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 2, msg[2], msg[3]);
|
||||
SuccessOrQuit(otMessageQueueDequeue(&queue, msg[3]), "Failed to dequeue a message from otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 1, msg[2]);
|
||||
|
||||
// Check the expected failure cases for the enqueue and dequeue:
|
||||
error = otMessageQueueEnqueue(&queue, msg[2]);
|
||||
VerifyOrQuit(error == kThreadError_Already, "Enqueuing an already queued message did not fail as expected.\n");
|
||||
error = otMessageQueueDequeue(&queue, msg[0]);
|
||||
VerifyOrQuit(error == kThreadError_NotFound, "Dequeuing a message not in the queue did not fail as expected.\n");
|
||||
|
||||
// Check the failure cases for otMessageQueueGetNext()
|
||||
message = otMessageQueueGetNext(&queue, NULL);
|
||||
VerifyOrQuit(message == NULL, "otMessageQueueGetNext(queue, NULL) did not return NULL.\n");
|
||||
message = otMessageQueueGetNext(&queue, msg[1]);
|
||||
VerifyOrQuit(message == NULL, "otMessageQueueGetNext() did not return NULL for a message not in the queue.\n");
|
||||
|
||||
// Check the failure case when attempting to do otMessageQueueGetNext() but passing in a wrong queue pointer.
|
||||
SuccessOrQuit(otMessageQueueEnqueue(&queue2, msg[0]), "Failed to enqueue a message to otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue2, 1, msg[0]);
|
||||
SuccessOrQuit(otMessageQueueEnqueue(&queue2, msg[1]), "Failed to enqueue a message to otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue2, 2, msg[0], msg[1]);
|
||||
|
||||
message = otMessageQueueGetNext(&queue2, msg[0]);
|
||||
VerifyOrQuit(message == msg[1], "otMessageQueueGetNext() failed\n");
|
||||
message = otMessageQueueGetNext(&queue, msg[0]);
|
||||
VerifyOrQuit(message == NULL, "otMessageQueueGetNext() did not return NULL for message not in the queue.\n");
|
||||
|
||||
// Remove all element and make sure queue is empty
|
||||
SuccessOrQuit(otMessageQueueDequeue(&queue, msg[2]), "Failed to dequeue a message from otMessageQueue.\n");
|
||||
VerifyMessageQueueContentUsingOtApi(&queue, 0);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_TEST_MAIN
|
||||
int main(void)
|
||||
{
|
||||
TestMessageQueue();
|
||||
TestMessageQueueOtApis();
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user