diff --git a/examples/apps/ncp/Makefile.am b/examples/apps/ncp/Makefile.am index f4bb6c8eb..ed08b7139 100644 --- a/examples/apps/ncp/Makefile.am +++ b/examples/apps/ncp/Makefile.am @@ -39,8 +39,8 @@ ot_ncp_CPPFLAGS = \ $(NULL) ot_ncp_LDADD = \ - $(top_builddir)/src/core/libopenthread-ftd.a \ $(top_builddir)/src/ncp/libopenthread-ncp.a \ + $(top_builddir)/src/core/libopenthread-ftd.a \ $(NULL) ot_ncp_LDFLAGS = \ diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 00cebef8c..b9237555c 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -230,7 +230,10 @@ const NcpBase::SetPropertyHandlerEntry NcpBase::mSetPropertyHandlerTable[] = { { SPINEL_PROP_POWER_STATE, &NcpBase::SetPropertyHandler_POWER_STATE }, +#if OPENTHREAD_ENABLE_RAW_LINK_API { SPINEL_PROP_PHY_ENABLED, &NcpBase::SetPropertyHandler_PHY_ENABLED }, + { SPINEL_PROP_STREAM_RAW, &NcpBase::SetPropertyHandler_STREAM_RAW }, +#endif // OPENTHREAD_ENABLE_RAW_LINK_API { SPINEL_PROP_PHY_TX_POWER, &NcpBase::SetPropertyHandler_PHY_TX_POWER }, { SPINEL_PROP_PHY_CHAN, &NcpBase::SetPropertyHandler_PHY_CHAN }, { SPINEL_PROP_MAC_PROMISCUOUS_MODE, &NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE }, @@ -483,6 +486,10 @@ NcpBase::NcpBase(otInstance *aInstance): mRequireJoinExistingNetwork(false), mIsRawStreamEnabled(false), mDisableStreamWrite(false), +#if OPENTHREAD_ENABLE_RAW_LINK_API + mCurTransmitTID(0), + mCurReceiveChannel(OPENTHREAD_CONFIG_DEFAULT_CHANNEL), +#endif // OPENTHREAD_ENABLE_RAW_LINK_API mFramingErrorCounter(0), mRxSpinelFrameCounter(0), @@ -750,6 +757,99 @@ void NcpBase::HandleEnergyScanResult(otEnergyScanResult *aResult) } } +// ---------------------------------------------------------------------------- +// MARK: Raw Link-Layer Datapath Glue +// ---------------------------------------------------------------------------- + +#if OPENTHREAD_ENABLE_RAW_LINK_API + +void NcpBase::LinkRawReceiveDone(otInstance *, RadioPacket *aPacket, ThreadError aError) +{ + sNcpContext->LinkRawReceiveDone(aPacket, aError); +} + +void NcpBase::LinkRawReceiveDone(RadioPacket *aPacket, ThreadError aError) +{ + ThreadError errorCode = kThreadError_None; + uint16_t flags = 0; + + SuccessOrExit(errorCode = OutboundFrameBegin()); + + if (aPacket->mDidTX) + { + flags |= SPINEL_MD_FLAG_TX; + } + + // Append frame header and frame length + SuccessOrExit( + errorCode = OutboundFrameFeedPacked( + "CiiS", + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_STREAM_RAW, + (aError == kThreadError_None) ? aPacket->mLength : 0 + ) + ); + + if (aError == kThreadError_None) + { + // Append the frame contents + SuccessOrExit( + errorCode = OutboundFrameFeedData( + aPacket->mPsdu, + aPacket->mLength + ) + ); + } + + // Append metadata (rssi, etc) + SuccessOrExit( + errorCode = OutboundFrameFeedPacked( + "ccSiCC", + aPacket->mPower, // TX Power + -128, // Noise Floor (Currently unused) + flags, // Flags + aError, // Receive error + aPacket->mChannel, // Receive channel + aPacket->mLqi // Link quality indicator + ) + ); + + SuccessOrExit(errorCode = OutboundFrameSend()); + +exit: + return; +} + +void NcpBase::LinkRawTransmitDone(otInstance *, RadioPacket *aPacket, bool aFramePending, ThreadError aError) +{ + sNcpContext->LinkRawTransmitDone(aPacket, aFramePending, aError); +} + +void NcpBase::LinkRawTransmitDone(RadioPacket *, bool aFramePending, ThreadError aError) +{ + if (mCurTransmitTID) + { + SendPropertyUpdate( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0 | mCurTransmitTID, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_LAST_STATUS, + "ib", + aError, + aFramePending + ); + + // Clear cached transmit TID + mCurTransmitTID = 0; + } + + // Make sure we are back listening on the original receive channel, + // since the transmit could have been on a different channel. + otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone); +} + +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + // ---------------------------------------------------------------------------- // MARK: Address Table Changed Glue // ---------------------------------------------------------------------------- @@ -1529,6 +1629,10 @@ ThreadError NcpBase::GetPropertyHandler_CAPS(uint8_t header, spinel_prop_key_t k SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_COUNTERS)); SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_MAC_WHITELIST)); +#if OPENTHREAD_ENABLE_RAW_LINK_API + SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_MAC_RAW)); +#endif + #if OPENTHREAD_ENABLE_JAM_DETECTION SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_JAM_DETECT)); #endif @@ -1611,10 +1715,17 @@ ThreadError NcpBase::GetPropertyHandler_LOCK(uint8_t header, spinel_prop_key_t k ThreadError NcpBase::GetPropertyHandler_PHY_ENABLED(uint8_t header, spinel_prop_key_t key) { - // TODO: Implement PHY_ENBLED (Needs API!) - (void)key; - - return SendLastStatus(header, SPINEL_STATUS_UNIMPLEMENTED); + return SendPropertyUpdate( + header, + SPINEL_CMD_PROP_VALUE_IS, + key, + SPINEL_DATATYPE_BOOL_S, +#if OPENTHREAD_ENABLE_RAW_LINK_API + otLinkRawIsEnabled(mInstance) +#else + false +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + ); } ThreadError NcpBase::GetPropertyHandler_PHY_FREQ(uint8_t header, spinel_prop_key_t key) @@ -3073,6 +3184,8 @@ ThreadError NcpBase::SetPropertyHandler_POWER_STATE(uint8_t header, spinel_prop_ return SendLastStatus(header, SPINEL_STATUS_UNIMPLEMENTED); } +#if OPENTHREAD_ENABLE_RAW_LINK_API + ThreadError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) { @@ -3091,11 +3204,23 @@ ThreadError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t header, spinel_prop_ { if (value == false) { - errorCode = otPlatRadioDisable(mInstance); + // If we have raw stream enabled stop receiving + if (mIsRawStreamEnabled) + { + otLinkRawSleep(mInstance); + } + + errorCode = otLinkRawSetEnable(mInstance, false); } else { - errorCode = otPlatRadioEnable(mInstance); + errorCode = otLinkRawSetEnable(mInstance, true); + + // If we have raw stream enabled already, start receiving + if (errorCode == kThreadError_None && mIsRawStreamEnabled) + { + errorCode = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone); + } } } else @@ -3115,6 +3240,8 @@ ThreadError NcpBase::SetPropertyHandler_PHY_ENABLED(uint8_t header, spinel_prop_ return errorCode; } +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + ThreadError NcpBase::SetPropertyHandler_PHY_TX_POWER(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) { @@ -3144,6 +3271,25 @@ ThreadError NcpBase::SetPropertyHandler_PHY_CHAN(uint8_t header, spinel_prop_key { errorCode = otSetChannel(mInstance, static_cast(i)); +#if OPENTHREAD_ENABLE_RAW_LINK_API + + if (errorCode == kThreadError_None) + { + // Cache the channel. If the raw link layer isn't enabled yet, the otSetChannel call + // doesn't call into the radio layer to set the channel. We will have to do it + // manually whenever the radios are enabled and/or raw stream is enabled. + mCurReceiveChannel = static_cast(i); + + // Make sure we are update the receiving channel if raw link is enabled and we have raw + // stream enabled already + if (otLinkRawIsEnabled(mInstance) && mIsRawStreamEnabled) + { + errorCode = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone); + } + } + +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + if (errorCode == kThreadError_None) { errorCode = HandleCommandPropertyGet(header, key); @@ -3424,7 +3570,19 @@ ThreadError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t header, s if (parsedLength > 0) { - mIsRawStreamEnabled = value; +#if OPENTHREAD_ENABLE_RAW_LINK_API + if (otLinkRawIsEnabled(mInstance)) + { + if (value) + { + errorCode = otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone); + } + else + { + errorCode = otLinkRawSleep(mInstance); + } + } +#endif // OPENTHREAD_ENABLE_RAW_LINK_API } else { @@ -3433,6 +3591,7 @@ ThreadError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t header, s if (errorCode == kThreadError_None) { + mIsRawStreamEnabled = value; errorCode = HandleCommandPropertyGet(header, key); } else @@ -3443,6 +3602,70 @@ ThreadError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t header, s return errorCode; } +#if OPENTHREAD_ENABLE_RAW_LINK_API + +ThreadError NcpBase::SetPropertyHandler_STREAM_RAW(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, + uint16_t value_len) +{ + ThreadError errorCode = kThreadError_None; + + if (otLinkRawIsEnabled(mInstance)) + { + spinel_ssize_t parsedLength(0); + uint8_t *frame_buffer(NULL); + unsigned int frame_len(0); + + RadioPacket *packet = otLinkRawGetTransmitBuffer(mInstance); + + parsedLength = spinel_datatype_unpack( + value_ptr, + value_len, + "DCc", + &frame_buffer, + &frame_len, + &packet->mChannel, + &packet->mPower + ); + + if (parsedLength > 0 && frame_len <= kMaxPHYPacketSize) + { + // Cache the transaction ID for async response + mCurTransmitTID = SPINEL_HEADER_GET_TID(header); + + // Update packet buffer and length + packet->mLength = static_cast(frame_len); + memcpy(packet->mPsdu, frame_buffer, packet->mLength); + + // Pass packet to the radio layer. Note, this fails if we + // haven't enabled raw stream or are already transmitting. + errorCode = otLinkRawTransmit(mInstance, packet, &NcpBase::LinkRawTransmitDone); + } + else + { + errorCode = kThreadError_Parse; + } + } + else + { + errorCode = kThreadError_InvalidState; + } + + if (errorCode == kThreadError_None) + { + // Don't do anything here yet. We will complete the transaction when we get a transmit done callback + } + else + { + errorCode = SendLastStatus(header, ThreadErrorToSpinelStatus(errorCode)); + } + + (void)key; + + return errorCode; +} + +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + ThreadError NcpBase::SetPropertyHandler_NET_IF_UP(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len) { diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index d0079aadc..a353e7504 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -188,6 +188,25 @@ private: void SendDoneTask(void); +#if OPENTHREAD_ENABLE_RAW_LINK_API + + /** + * Trampoline for LinkRawReceiveDone(). + */ + static void LinkRawReceiveDone(otInstance *aInstance, RadioPacket *aPacket, ThreadError aError); + + void LinkRawReceiveDone(RadioPacket *aPacket, ThreadError aError); + + /** + * Trampoline for LinkRawTransmitDone(). + */ + static void LinkRawTransmitDone(otInstance *aInstance, RadioPacket *aPacket, bool aFramePending, + ThreadError aError); + + void LinkRawTransmitDone(RadioPacket *aPacket, bool aFramePending, ThreadError aError); + +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + static void HandleNetifStateChanged(uint32_t flags, void *context); private: @@ -387,6 +406,10 @@ private: uint16_t value_len); ThreadError SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); +#if OPENTHREAD_ENABLE_RAW_LINK_API + ThreadError SetPropertyHandler_STREAM_RAW(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, + uint16_t value_len); +#endif // OPENTHREAD_ENABLE_RAW_LINK_API ThreadError SetPropertyHandler_NET_IF_UP(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError SetPropertyHandler_NET_STACK_UP(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, @@ -413,8 +436,10 @@ private: uint16_t value_len); ThreadError SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); +#if OPENTHREAD_ENABLE_RAW_LINK_API ThreadError SetPropertyHandler_PHY_ENABLED(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); +#endif // OPENTHREAD_ENABLE_RAW_LINK_API ThreadError SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, uint16_t value_len); ThreadError SetPropertyHandler_MAC_SCAN_PERIOD(uint8_t header, spinel_prop_key_t key, const uint8_t *value_ptr, @@ -526,6 +551,11 @@ private: bool mIsRawStreamEnabled; bool mDisableStreamWrite; +#if OPENTHREAD_ENABLE_RAW_LINK_API + uint8_t mCurTransmitTID; + uint8_t mCurReceiveChannel; +#endif // OPENTHREAD_ENABLE_RAW_LINK_API + uint32_t mFramingErrorCounter; // Number of improperly formed received spinel frames. uint32_t mRxSpinelFrameCounter; // Number of received (inbound) spinel frames. uint32_t mRxSpinelOutOfOrderTidCounter; // Number of out of order received spinel frames (tid increase > 1). diff --git a/src/ncp/spinel.h b/src/ncp/spinel.h index faabbb898..7f40179e8 100644 --- a/src/ncp/spinel.h +++ b/src/ncp/spinel.h @@ -337,6 +337,7 @@ enum SPINEL_CAP_OPENTHREAD__BEGIN = 512, SPINEL_CAP_MAC_WHITELIST = (SPINEL_CAP_OPENTHREAD__BEGIN + 0), + SPINEL_CAP_MAC_RAW = (SPINEL_CAP_OPENTHREAD__BEGIN + 1), SPINEL_CAP_OPENTHREAD__END = 640, SPINEL_CAP_NEST__BEGIN = 15296,