diff --git a/examples/platforms/posix/radio.c b/examples/platforms/posix/radio.c
index c9a4becab..49f704c86 100644
--- a/examples/platforms/posix/radio.c
+++ b/examples/platforms/posix/radio.c
@@ -351,7 +351,7 @@ void platformRadioInit(void)
if (*endptr != '\0')
{
fprintf(stderr, "Invalid PORT_OFFSET: %s\n", offset);
- exit(1);
+ exit(EXIT_FAILURE);
}
sPortOffset *= WELLKNOWN_NODE_ID;
diff --git a/include/openthread/link_raw.h b/include/openthread/link_raw.h
index 8531ebfd6..89e7b8e98 100644
--- a/include/openthread/link_raw.h
+++ b/include/openthread/link_raw.h
@@ -191,7 +191,7 @@ otRadioFrame *otLinkRawGetTransmitBuffer(otInstance *aInstance);
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aFrame A pointer to the frame that was transmitted.
- * @param[in] aFramePending TRUE if an ACK frame was received and the Frame Pending bit was set.
+ * @param[in] aAckFrame A pointer to the ACK frame.
* @param[in] aError OT_ERROR_NONE when the frame was transmitted.
* OT_ERROR_NO_ACK when the frame was transmitted but no ACK was received
* OT_ERROR_CHANNEL_ACCESS_FAILURE when the transmission could not take place
@@ -199,8 +199,8 @@ otRadioFrame *otLinkRawGetTransmitBuffer(otInstance *aInstance);
* OT_ERROR_ABORT when transmission was aborted for other reasons.
*
*/
-typedef void (*otLinkRawTransmitDone)(otInstance *aInstance, otRadioFrame *aFrame, bool aFramePending,
- otError aError);
+typedef void (*otLinkRawTransmitDone)(otInstance *aInstance, otRadioFrame *aFrame,
+ otRadioFrame *aAckFrame, otError aError);
/**
* This method begins the transmit sequence on the radio.
diff --git a/include/openthread/platform/radio.h b/include/openthread/platform/radio.h
index 7032cd1d9..ce5cca252 100644
--- a/include/openthread/platform/radio.h
+++ b/include/openthread/platform/radio.h
@@ -405,8 +405,8 @@ otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame);
extern void otPlatRadioTxStarted(otInstance *aInstance, otRadioFrame *aFrame);
/**
- * The radio driver calls this method to notify OpenThread that the transmission has completed,
- * this callback pass up the ACK frame, new add platforms should use this callback function.
+ * The radio driver calls this function to notify OpenThread that the transmit operation has completed,
+ * providing both the transmitted frame and, if applicable, the received ack frame.
*
* @param[in] aInstance The OpenThread instance structure.
* @param[in] aFrame A pointer to the frame that was transmitted.
diff --git a/src/core/api/link_raw.hpp b/src/core/api/link_raw.hpp
index e39629503..239592092 100644
--- a/src/core/api/link_raw.hpp
+++ b/src/core/api/link_raw.hpp
@@ -96,7 +96,7 @@ public:
* This method invokes the mTransmitDoneCallback, if set.
*
*/
- void InvokeTransmitDone(otRadioFrame *aFrame, bool aFramePending, otError aError);
+ void InvokeTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
/**
* This method starts a (single) Enery Scan on the link-layer.
diff --git a/src/core/api/link_raw_api.cpp b/src/core/api/link_raw_api.cpp
index 7ac85dfd7..0b388ec28 100644
--- a/src/core/api/link_raw_api.cpp
+++ b/src/core/api/link_raw_api.cpp
@@ -384,7 +384,7 @@ otError LinkRaw::DoTransmit(otRadioFrame *aFrame)
return error;
}
-void LinkRaw::InvokeTransmitDone(otRadioFrame *aFrame, bool aFramePending, otError aError)
+void LinkRaw::InvokeTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
{
otLogDebgPlat(&mInstance, "LinkRaw Transmit Done (err=0x%x)", aError);
@@ -434,7 +434,7 @@ void LinkRaw::InvokeTransmitDone(otRadioFrame *aFrame, bool aFramePending, otErr
otLogWarnPlat(&mInstance, "LinkRaw Invoke Transmit Failed (err=0x%x)", aError);
}
- mTransmitDoneCallback(&mInstance, aFrame, aFramePending, aError);
+ mTransmitDoneCallback(&mInstance, aFrame, aAckFrame, aError);
mTransmitDoneCallback = NULL;
}
@@ -501,7 +501,7 @@ void LinkRaw::HandleTimer(void)
otPlatRadioReceive(&mInstance, mReceiveChannel);
// Invoke completion callback for transmit
- InvokeTransmitDone(otPlatRadioGetTransmitBuffer(&mInstance), false, OT_ERROR_NO_ACK);
+ InvokeTransmitDone(otPlatRadioGetTransmitBuffer(&mInstance), NULL, OT_ERROR_NO_ACK);
break;
}
@@ -518,7 +518,7 @@ void LinkRaw::HandleTimer(void)
if (error != OT_ERROR_NONE)
{
- InvokeTransmitDone(aFrame, false, error);
+ InvokeTransmitDone(aFrame, NULL, error);
}
break;
diff --git a/src/core/mac/mac.cpp b/src/core/mac/mac.cpp
index 125720ae5..e01e38900 100644
--- a/src/core/mac/mac.cpp
+++ b/src/core/mac/mac.cpp
@@ -971,7 +971,7 @@ extern "C" void otPlatRadioTxDone(otInstance *aInstance, otRadioFrame *aFrame, o
if (aInstance->mLinkRaw.IsEnabled())
{
- aInstance->mLinkRaw.InvokeTransmitDone(aFrame, (static_cast(aAckFrame))->GetFramePending(), aError);
+ aInstance->mLinkRaw.InvokeTransmitDone(aFrame, aAckFrame, aError);
}
else
#endif // OPENTHREAD_ENABLE_RAW_LINK_API
@@ -1060,7 +1060,17 @@ void Mac::TransmitDoneTask(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otErro
break;
default:
- assert(false);
+#if OPENTHREAD_ENABLE_RAW_LINK_API
+ if (GetInstance().mLinkRaw.IsEnabled())
+ {
+ GetInstance().mLinkRaw.InvokeTransmitDone(mTxFrame, NULL, OT_ERROR_NO_ACK);
+ }
+ else
+#endif
+ {
+ assert(false);
+ }
+
break;
}
diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp
index 03c60eefb..d97d48823 100644
--- a/src/ncp/ncp_base.cpp
+++ b/src/ncp/ncp_base.cpp
@@ -69,6 +69,7 @@
#include "openthread-instance.h"
#include "common/code_utils.hpp"
#include "common/debug.hpp"
+#include "mac/mac_frame.hpp"
#include "net/ip6.hpp"
namespace ot {
@@ -1161,27 +1162,60 @@ exit:
return;
}
-void NcpBase::LinkRawTransmitDone(otInstance *, otRadioFrame *aFrame, bool aFramePending, otError aError)
+void NcpBase::LinkRawTransmitDone(otInstance *, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
{
- sNcpInstance->LinkRawTransmitDone(aFrame, aFramePending, aError);
+ sNcpInstance->LinkRawTransmitDone(aFrame, aAckFrame, aError);
}
-void NcpBase::LinkRawTransmitDone(otRadioFrame *, bool aFramePending, otError aError)
+void NcpBase::LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError)
{
if (mCurTransmitTID)
{
- SendPropertyUpdate(
- SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0 | mCurTransmitTID,
- SPINEL_CMD_PROP_VALUE_IS,
- SPINEL_PROP_LAST_STATUS,
- SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_BOOL_S,
- ThreadErrorToSpinelStatus(aError),
- aFramePending
- );
+ uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0 | mCurTransmitTID;
+ bool framePending = (aAckFrame != NULL && static_cast(aAckFrame)->GetFramePending());
// Clear cached transmit TID
mCurTransmitTID = 0;
+
+ SuccessOrExit(OutboundFrameBegin(header));
+
+ SuccessOrExit(OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT_PACKED_S SPINEL_DATATYPE_BOOL_S,
+ header,
+ SPINEL_CMD_PROP_VALUE_IS,
+ SPINEL_PROP_LAST_STATUS,
+ ThreadErrorToSpinelStatus(aError),
+ framePending
+ ));
+
+ if (aAckFrame && aError == OT_ERROR_NONE)
+ {
+ SuccessOrExit(OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT16_S, aAckFrame->mLength));
+ SuccessOrExit(OutboundFrameFeedData(aAckFrame->mPsdu, aAckFrame->mLength));
+ SuccessOrExit(OutboundFrameFeedPacked(
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_INT8_S
+ SPINEL_DATATYPE_UINT16_S
+ SPINEL_DATATYPE_STRUCT_S( // PHY-data
+ SPINEL_DATATYPE_UINT8_S // 802.15.4 channel
+ SPINEL_DATATYPE_UINT8_S // 802.15.4 LQI
+ ),
+ aAckFrame->mPower, // RSSI
+ -128, // Noise Floor (Currently unused)
+ 0, // Flags
+ aAckFrame->mChannel, // Receive channel
+ aAckFrame->mLqi, // Link quality indicator
+ aFrame->mMsec, // The timestamp milliseconds
+ aFrame->mUsec // The timestamp microseconds, offset to mMsec
+ ));
+ }
+
+ SuccessOrExit(OutboundFrameSend());
}
+
+exit:
+ OT_UNUSED_VARIABLE(aFrame);
+ return;
}
void NcpBase::LinkRawEnergyScanDone(otInstance *, int8_t aEnergyScanMaxRssi)
diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp
index 87e32634e..738da413f 100644
--- a/src/ncp/ncp_base.hpp
+++ b/src/ncp/ncp_base.hpp
@@ -224,8 +224,8 @@ private:
static void LinkRawReceiveDone(otInstance *aInstance, otRadioFrame *aFrame, otError aError);
void LinkRawReceiveDone(otRadioFrame *aFrame, otError aError);
- static void LinkRawTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, bool aFramePending, otError aError);
- void LinkRawTransmitDone(otRadioFrame *aFrame, bool aFramePending, otError aError);
+ static void LinkRawTransmitDone(otInstance *aInstance, otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
+ void LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, otError aError);
static void LinkRawEnergyScanDone(otInstance *aInstance, int8_t aEnergyScanMaxRssi);
void LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi);