mirror of
https://github.com/espressif/openthread.git
synced 2026-08-06 10:47:46 +00:00
[message] add TxCallback to track transmission outcome (#11614)
This commit introduces new public APIs to register a `TxCallback` on a message to be notified of its transmission outcome. The callback is invoked with an error code indicating the transmission status of the IPv6 message to an immediate neighbor (a one-hop transmission). It does not indicate that the message was received by its final, multi-hop destination. For a unicast IPv6 message, a success (`OT_ERROR_NONE`) indicates that the message, including all its corresponding fragments if applicable, was successfully delivered to the immediate neighbor and a MAC layer acknowledgment was received for all fragments. This is reported regardless of whether the message is sent using direct or indirect transmission (e.g., to a sleepy child via CSL or a data poll). For a multicast message, an `OT_ERROR_NONE` status indicates that the message and all its fragments were successfully broadcast. Note that no MAC-level acknowledgment is required for a broadcast frame transmission.
This commit is contained in:
@@ -52,7 +52,7 @@ extern "C" {
|
||||
*
|
||||
* @note This number versions both OpenThread platform and user APIs.
|
||||
*/
|
||||
#define OPENTHREAD_API_VERSION (513)
|
||||
#define OPENTHREAD_API_VERSION (514)
|
||||
|
||||
/**
|
||||
* @addtogroup api-instance
|
||||
|
||||
@@ -108,6 +108,15 @@ typedef struct otThreadLinkInfo
|
||||
uint8_t mRadioType; ///< Radio link type.
|
||||
} otThreadLinkInfo;
|
||||
|
||||
/**
|
||||
* Gets the `otInstance` associated with a given message.
|
||||
*
|
||||
* @param[in] aMessage A message.
|
||||
*
|
||||
* @returns The `otInstance` associated with @p aMessage.
|
||||
*/
|
||||
otInstance *otMessageGetInstance(const otMessage *aMessage);
|
||||
|
||||
/**
|
||||
* Free an allocated message buffer.
|
||||
*
|
||||
@@ -288,6 +297,44 @@ int8_t otMessageGetRss(const otMessage *aMessage);
|
||||
*/
|
||||
otError otMessageGetThreadLinkInfo(const otMessage *aMessage, otThreadLinkInfo *aLinkInfo);
|
||||
|
||||
/**
|
||||
* Represents the callback function pointer to notify the transmission outcome (success or failure) of a message.
|
||||
*
|
||||
* The error indicates the transmission status of the IPv6 message from this device to an immediate neighbor (one-hop
|
||||
* transmission). It doesn't indicate that the message is received by its final intended destination (multi-hop away).
|
||||
*
|
||||
* For a unicast IPv6 message, an `OT_ERROR_NONE` error indicates that the message (all its corresponding fragment
|
||||
* frames if the message is larger and requires fragmentation) was successfully delivered to the immediate neighbor,
|
||||
* and a MAC layer acknowledgment was received for all fragments. This is reported regardless of whether the message
|
||||
* is sent using direct TX or indirect TX (to a sleepy child using CSL or data poll triggered TX).
|
||||
*
|
||||
* For a multicast message, an `OT_ERROR_NONE` status indicates that the message (all its fragment frames) was
|
||||
* successfully broadcast. Note that no MAC-level acknowledgment is required for broadcast frame TX.
|
||||
*
|
||||
* The OpenThread stack may alter the content of the message as it is prepared for transmission (e.g., IPv6 headers
|
||||
* may be prepended, or additional metadata appended at the end). So, the content of @p aMessage when this callback
|
||||
* is invoked may differ from its original content (e.g., when it was given as input in `otIp6Send()` for transmission).
|
||||
*
|
||||
* @param[in] aMessage A pointer to the message.
|
||||
* @param[in] aError The TX error when sending the message.
|
||||
* @param[in] aContext A pointer to the user-provided context when the callback was registered.
|
||||
*/
|
||||
typedef void (*otMessageTxCallback)(const otMessage *aMessage, otError aError, void *aContext);
|
||||
|
||||
/**
|
||||
* Registers a callback to be notified of a message's transmission outcome.
|
||||
*
|
||||
* Calling this function again for the same message will replace any previously registered callback.
|
||||
*
|
||||
* If the message is never actually sent (e.g., it's not passed to `otIp6Send()` or other send APIs), the callback
|
||||
* will still be invoked when the message is freed. In this case, `OT_ERROR_DROP` will be passed as the error.
|
||||
*
|
||||
* @param[in] aMessage The message to register the callback with.
|
||||
* @param[in] aCallback The TX callback.
|
||||
* @param[in] aContext A pointer to a user-provided arbitrary context for the callback.
|
||||
*/
|
||||
void otMessageRegisterTxCallback(otMessage *aMessage, otMessageTxCallback aCallback, void *aContext);
|
||||
|
||||
/**
|
||||
* Append bytes to a message.
|
||||
*
|
||||
|
||||
@@ -37,6 +37,8 @@
|
||||
|
||||
using namespace ot;
|
||||
|
||||
otInstance *otMessageGetInstance(const otMessage *aMessage) { return &AsCoreType(aMessage).GetInstance(); }
|
||||
|
||||
void otMessageFree(otMessage *aMessage) { AsCoreType(aMessage).Free(); }
|
||||
|
||||
uint16_t otMessageGetLength(const otMessage *aMessage) { return AsCoreType(aMessage).GetLength(); }
|
||||
@@ -92,6 +94,11 @@ otError otMessageGetThreadLinkInfo(const otMessage *aMessage, otThreadLinkInfo *
|
||||
return AsCoreType(aMessage).GetLinkInfo(AsCoreType(aLinkInfo));
|
||||
}
|
||||
|
||||
void otMessageRegisterTxCallback(otMessage *aMessage, otMessageTxCallback aCallback, void *aContext)
|
||||
{
|
||||
AsCoreType(aMessage).RegisterTxCallback(aCallback, aContext);
|
||||
}
|
||||
|
||||
otError otMessageAppend(otMessage *aMessage, const void *aBuf, uint16_t aLength)
|
||||
{
|
||||
AssertPointerIsNotNull(aBuf);
|
||||
|
||||
@@ -250,7 +250,15 @@ exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
void Message::Free(void) { Get<MessagePool>().Free(this); }
|
||||
void Message::Free(void)
|
||||
{
|
||||
// `TxCallback` is cleared once it is invoked. If the message is
|
||||
// freed before we know the TX outcome, it's treated as a dropped
|
||||
// message, signaling `kErrorDrop`.
|
||||
|
||||
InvokeTxCallback(kErrorDrop);
|
||||
Get<MessagePool>().Free(this);
|
||||
}
|
||||
|
||||
Message *Message::GetNext(void) const
|
||||
{
|
||||
@@ -364,6 +372,23 @@ const char *Message::PriorityToString(Priority aPriority)
|
||||
return kPriorityStrings[aPriority];
|
||||
}
|
||||
|
||||
void Message::RegisterTxCallback(TxCallback aCallback, void *aContext)
|
||||
{
|
||||
GetMetadata().mTxCallback = aCallback;
|
||||
GetMetadata().mTxContext = aContext;
|
||||
}
|
||||
|
||||
void Message::InvokeTxCallback(Error aError)
|
||||
{
|
||||
TxCallback callback = GetMetadata().mTxCallback;
|
||||
|
||||
if (callback != nullptr)
|
||||
{
|
||||
GetMetadata().mTxCallback = nullptr;
|
||||
callback(this, aError, GetMetadata().mTxContext);
|
||||
}
|
||||
}
|
||||
|
||||
Error Message::AppendBytes(const void *aBuf, uint16_t aLength)
|
||||
{
|
||||
Error error = kErrorNone;
|
||||
|
||||
@@ -166,6 +166,8 @@ class Buffer : public otMessageBuffer, public LinkedListEntry<Buffer>
|
||||
friend class Message;
|
||||
|
||||
public:
|
||||
typedef otMessageTxCallback TxCallback; ///< Message TX callback.
|
||||
|
||||
/**
|
||||
* Returns a pointer to the next message buffer.
|
||||
*
|
||||
@@ -234,6 +236,8 @@ protected:
|
||||
Message *mNext; // Next message in a doubly linked list.
|
||||
Message *mPrev; // Previous message in a doubly linked list.
|
||||
void *mQueue; // The queue where message is queued (if any). Queue type from `mInPriorityQ`.
|
||||
TxCallback mTxCallback; // The callback to inform message TX success or failure.
|
||||
void *mTxContext; // The arbitrary context associated with `mTxCallback`.
|
||||
RssAverager mRssAverager; // The averager maintaining the received signal strength (RSS) average.
|
||||
LqiAverager mLqiAverager; // The averager maintaining the Link quality indicator (LQI) average.
|
||||
#if OPENTHREAD_FTD
|
||||
@@ -654,6 +658,35 @@ public:
|
||||
*/
|
||||
static const char *PriorityToString(Priority aPriority);
|
||||
|
||||
/**
|
||||
* Registers a callback to be notified of a message's transmission outcome.
|
||||
*
|
||||
* The registered `TxCallback` provides notification of the transmission status of the message from this device to
|
||||
* an immediate neighbor (one hop). It doesn't indicate delivery to the final multi-hop destination.
|
||||
*
|
||||
* For unicast messages, `kErrorNone` callback error signifies successful delivery and MAC acknowledgment for all
|
||||
* fragments of the message to an immediate neighbor, irrespective of whether direct or indirect TX is used. For
|
||||
* multicast messages, `kErrorNone` indicates successful broadcast of all fragments. Note that no MAC-level ack
|
||||
* is expected for broadcast frame transmissions.
|
||||
*
|
||||
* Only one callback can be registered per `Message`. Subsequent calls replace any existing callback. If the
|
||||
* message is never actually sent, the callback will still be invoked when the message is freed, with `kErrorDrop`
|
||||
* as the error.
|
||||
*
|
||||
* @param[in] aCallback The `TxCallback` function to register with the message.
|
||||
* @param[in] aContext An arbitrary context that will be passed when @p aCallback is invoked.
|
||||
*/
|
||||
void RegisterTxCallback(TxCallback aCallback, void *aContext);
|
||||
|
||||
/**
|
||||
* Invokes the registered `TxCallback` on the `Message` with the given error status.
|
||||
*
|
||||
* The `TxCallback` is a one-time callback, meaning it's automatically cleared once it's invoked.
|
||||
*
|
||||
* @param[in] aError The error to report.
|
||||
*/
|
||||
void InvokeTxCallback(Error aError);
|
||||
|
||||
/**
|
||||
* Prepends bytes to the front of the message.
|
||||
*
|
||||
|
||||
@@ -524,6 +524,8 @@ void IndirectSender::HandleSentFrameToChild(const Mac::TxFrame &aFrame,
|
||||
mSourceMatchController.DecrementMessageCount(aChild);
|
||||
}
|
||||
|
||||
message->InvokeTxCallback(txError);
|
||||
|
||||
Get<MeshForwarder>().RemoveMessageIfNoPendingTx(*message);
|
||||
}
|
||||
|
||||
|
||||
@@ -1288,6 +1288,8 @@ void MeshForwarder::FinalizeMessageDirectTx(Message &aMessage, Error aError)
|
||||
Get<Mle::Mle>().HandleChildIdRequestTxDone(aMessage);
|
||||
}
|
||||
|
||||
aMessage.InvokeTxCallback(aError);
|
||||
|
||||
exit:
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user