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);