From 192df6cf006ec5e67e2a17181cd21f8408f75037 Mon Sep 17 00:00:00 2001 From: Abtin Keshavarzian Date: Wed, 27 Sep 2017 23:04:53 -0700 Subject: [PATCH] [ncp] adding SpinelEncoder class and updating NCP implementation (#2221) This commit adds a new class `SpinelEncoder` which provides a set of methods/APIs to help in encoding/writing content using Spinel formating (it is practically a C++ wrapper over Spinel C APIs). A unit test `test_spinel_encoder` is also added in this commit. This commit also updates the `NcpBase` implementation to adopt the new `SpinelEncoder` class mainly in implementation of get, insert, and remove handlers for different Spinel properties. The new class provides the following advantages: (a) it simplifies the implementation of handers, particularly get-handlers for properties with a single type output; (b) it adds type-checking and type-safety when frames are being created, e.g., if the Spinel format expects a `SPINEL_DATATYPE_UINT8` but a `uint16_t` value is provided, the new model will cause a compile-time error (few instances in code where the types did not match are fixed in this commit). --- .../libopenthread-ncp-spi.vcxproj | 2 + .../libopenthread-ncp-spi.vcxproj.filters | 6 + .../libopenthread-ncp-uart.vcxproj | 2 + .../libopenthread-ncp-uart.vcxproj.filters | 6 + src/ncp/Makefile.am | 2 + src/ncp/ncp_base.cpp | 711 ++---- src/ncp/ncp_base.hpp | 138 +- src/ncp/ncp_base_ftd.cpp | 353 +-- src/ncp/ncp_base_mtd.cpp | 2204 +++++------------ src/ncp/ncp_base_radio.cpp | 248 +- src/ncp/ncp_buffer.cpp | 28 +- src/ncp/ncp_buffer.hpp | 32 +- src/ncp/spinel_encoder.cpp | 277 +++ src/ncp/spinel_encoder.hpp | 652 +++++ tests/unit/Makefile.am | 4 + tests/unit/test_spinel_encoder.cpp | 515 ++++ 16 files changed, 2576 insertions(+), 2604 deletions(-) create mode 100644 src/ncp/spinel_encoder.cpp create mode 100644 src/ncp/spinel_encoder.hpp create mode 100644 tests/unit/test_spinel_encoder.cpp diff --git a/etc/visual-studio/libopenthread-ncp-spi.vcxproj b/etc/visual-studio/libopenthread-ncp-spi.vcxproj index 9fd14d36d..d7adc3a5e 100644 --- a/etc/visual-studio/libopenthread-ncp-spi.vcxproj +++ b/etc/visual-studio/libopenthread-ncp-spi.vcxproj @@ -66,6 +66,7 @@ + @@ -73,6 +74,7 @@ + diff --git a/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters b/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters index c58c45d1c..ad6f0f90b 100644 --- a/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters +++ b/etc/visual-studio/libopenthread-ncp-spi.vcxproj.filters @@ -36,6 +36,9 @@ Source Files + + Source Files + Source Files @@ -56,5 +59,8 @@ Header Files + + Header Files + diff --git a/etc/visual-studio/libopenthread-ncp-uart.vcxproj b/etc/visual-studio/libopenthread-ncp-uart.vcxproj index 3ce3ab613..3e996c4cb 100644 --- a/etc/visual-studio/libopenthread-ncp-uart.vcxproj +++ b/etc/visual-studio/libopenthread-ncp-uart.vcxproj @@ -67,6 +67,7 @@ + @@ -75,6 +76,7 @@ + diff --git a/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters b/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters index 7f5765def..16df2e80e 100644 --- a/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters +++ b/etc/visual-studio/libopenthread-ncp-uart.vcxproj.filters @@ -42,6 +42,9 @@ Source Files + + Source Files + @@ -62,5 +65,8 @@ Header Files + + Header Files + diff --git a/src/ncp/Makefile.am b/src/ncp/Makefile.am index c31ff4eb7..c9e2e6c78 100644 --- a/src/ncp/Makefile.am +++ b/src/ncp/Makefile.am @@ -71,6 +71,8 @@ COMMON_SOURCES = \ ncp_buffer.hpp \ spinel.c \ spinel.h \ + spinel_encoder.hpp \ + spinel_encoder.cpp \ spinel_platform.h \ ncp_spi.cpp \ ncp_spi.hpp \ diff --git a/src/ncp/ncp_base.cpp b/src/ncp/ncp_base.cpp index 3be20af31..531e29340 100644 --- a/src/ncp/ncp_base.cpp +++ b/src/ncp/ncp_base.cpp @@ -182,52 +182,52 @@ const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] = #endif NCP_GET_PROP_HANDLER_ENTRY(STREAM_NET), // MAC counters - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_TOTAL, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_ACK_REQ, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_ACKED, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_NO_ACK_REQ, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_DATA, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_DATA_POLL, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_BEACON, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_BEACON_REQ, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_OTHER, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_RETRY, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_UNICAST, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_PKT_BROADCAST, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_ERR_CCA, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_ERR_ABORT, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_TOTAL, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_DATA, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_DATA_POLL, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_BEACON, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_BEACON_REQ, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_OTHER, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_FILT_WL, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_FILT_DA, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_UNICAST, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_BROADCAST, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_ERR_EMPTY, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_ERR_UKWN_NBR, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_ERR_NVLD_SADDR, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_ERR_SECURITY, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_ERR_BAD_FCS, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_ERR_OTHER, MAC_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_PKT_DUP, MAC_CNTR), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_TOTAL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_ACK_REQ), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_ACKED), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_NO_ACK_REQ), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_DATA), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_DATA_POLL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_BEACON), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_BEACON_REQ), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_OTHER), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_RETRY), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_UNICAST), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_PKT_BROADCAST), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_ERR_CCA), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_ERR_ABORT), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_TOTAL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_DATA), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_DATA_POLL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_BEACON), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_BEACON_REQ), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_OTHER), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_FILT_WL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_FILT_DA), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_UNICAST), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_BROADCAST), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_ERR_EMPTY), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_ERR_UKWN_NBR), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_ERR_NVLD_SADDR), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_ERR_SECURITY), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_ERR_BAD_FCS), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_ERR_OTHER), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_PKT_DUP), // NCP counters - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_IP_SEC_TOTAL, NCP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_IP_INSEC_TOTAL, NCP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_IP_DROPPED, NCP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_IP_SEC_TOTAL, NCP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_IP_INSEC_TOTAL, NCP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_IP_DROPPED, NCP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_TX_SPINEL_TOTAL, NCP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_SPINEL_TOTAL, NCP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_RX_SPINEL_ERR, NCP_CNTR), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_IP_SEC_TOTAL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_IP_INSEC_TOTAL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_IP_DROPPED), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_IP_SEC_TOTAL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_IP_INSEC_TOTAL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_IP_DROPPED), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_TX_SPINEL_TOTAL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_SPINEL_TOTAL), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_RX_SPINEL_ERR), // IP counters - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_IP_TX_SUCCESS, IP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_IP_RX_SUCCESS, IP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_IP_TX_FAILURE, IP_CNTR), - NCP_GET_PROP_HANDLER_ENTRY_METHOD(CNTR_IP_RX_FAILURE, IP_CNTR), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_TX_SUCCESS), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_RX_SUCCESS), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_TX_FAILURE), + NCP_GET_PROP_HANDLER_ENTRY(CNTR_IP_RX_FAILURE), #endif // OPENTHREAD_MTD || OPENTHREAD_FTD #if OPENTHREAD_FTD @@ -534,6 +534,7 @@ NcpBase *NcpBase::sNcpInstance = NULL; NcpBase::NcpBase(otInstance *aInstance): mInstance(aInstance), mTxFrameBuffer(mTxBuffer, sizeof(mTxBuffer)), + mEncoder(mTxFrameBuffer), mHostPowerStateInProgress(false), mLastStatus(SPINEL_STATUS_OK), mSupportedChannelMask(OT_RADIO_SUPPORTED_CHANNELS), @@ -606,62 +607,14 @@ NcpBase *NcpBase::GetNcpInstance(void) } // ---------------------------------------------------------------------------- -// MARK: Outbound Frame methods +// MARK: Serial Traffic Glue // ---------------------------------------------------------------------------- -otError NcpBase::OutboundFrameBegin(uint8_t aHeader) -{ - NcpFrameBuffer::Priority priority; - - // Non-zero tid indicates this is a response to a spinel command. - if (SPINEL_HEADER_GET_TID(aHeader) != 0) - { - priority = NcpFrameBuffer::kPriorityHigh; - } - else - { - priority = NcpFrameBuffer::kPriorityLow; - } - - return mTxFrameBuffer.InFrameBegin(priority); -} - -otError NcpBase::OutboundFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength) -{ - return mTxFrameBuffer.InFrameFeedData(aDataBuffer, aDataBufferLength); -} - -otError NcpBase::OutboundFrameFeedMessage(otMessage *aMessage) -{ - return mTxFrameBuffer.InFrameFeedMessage(aMessage); -} - -otError NcpBase::OutboundFrameEnd(void) -{ - return mTxFrameBuffer.InFrameEnd(); -} - NcpFrameBuffer::FrameTag NcpBase::GetLastOutboundFrameTag(void) { return mTxFrameBuffer.InFrameGetLastTag(); } -// ---------------------------------------------------------------------------- -// MARK: Serial Traffic Glue -// ---------------------------------------------------------------------------- - -otError NcpBase::OutboundFrameSend(void) -{ - otError error; - - SuccessOrExit(error = OutboundFrameEnd()); - - mTxSpinelFrameCounter++; - -exit: - return error; -} - void NcpBase::HandleReceive(const uint8_t *aBuf, uint16_t aBufLength) { uint8_t header = 0; @@ -781,7 +734,7 @@ void NcpBase::HandleFrameRemovedFromNcpBuffer(NcpFrameBuffer::FrameTag aFrameTag if (mHostPowerStateHeader) { SuccessOrExit( - GetPropertyHandler_HOST_POWER_STATE( + HandleCommandPropertyGet( mHostPowerStateHeader, SPINEL_PROP_HOST_POWER_STATE )); @@ -819,6 +772,7 @@ void NcpBase::IncrementFrameErrorCounter(void) otError NcpBase::StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen) { otError error = OT_ERROR_NONE; + uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0; spinel_prop_key_t streamPropKey; if (aStreamId == 0) @@ -833,21 +787,18 @@ otError NcpBase::StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLe VerifyOrExit(!mDisableStreamWrite, error = OT_ERROR_INVALID_STATE); VerifyOrExit(!mChangedPropsSet.IsPropertyFiltered(streamPropKey), error = OT_ERROR_INVALID_STATE); - error = SendPropertyUpdate( - SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, - SPINEL_CMD_PROP_VALUE_IS, - streamPropKey, - aDataPtr, - static_cast(aDataLen) - ); + SuccessOrExit(error = mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, streamPropKey)); + SuccessOrExit(error = mEncoder.WriteData(aDataPtr, static_cast(aDataLen))); + SuccessOrExit(error = mEncoder.EndFrame()); - if (error != OT_ERROR_NONE) +exit: + + if (error == OT_ERROR_NO_BUFS) { mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM); mUpdateChangedPropsTask.Post(); } -exit: return error; } @@ -881,46 +832,32 @@ void NcpBase::HandleRawFrame(const otRadioFrame *aFrame) goto exit; } - SuccessOrExit(OutboundFrameBegin(header)); - if (aFrame->mDidTX) { flags |= SPINEL_MD_FLAG_TX; } // Append frame header and frame length - SuccessOrExit( - OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S, - header, - SPINEL_CMD_PROP_VALUE_IS, - SPINEL_PROP_STREAM_RAW, - aFrame->mLength - )); + SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_STREAM_RAW)); + SuccessOrExit(mEncoder.WriteUint16(aFrame->mLength)); // Append the frame contents - SuccessOrExit(OutboundFrameFeedData(aFrame->mPsdu, aFrame->mLength)); + SuccessOrExit(mEncoder.WriteData(aFrame->mPsdu, aFrame->mLength)); // Append metadata (rssi, etc) - SuccessOrExit( - OutboundFrameFeedPacked( - SPINEL_DATATYPE_INT8_S - SPINEL_DATATYPE_INT8_S - SPINEL_DATATYPE_UINT16_S - SPINEL_DATATYPE_STRUCT_S( // PHY-data - SPINEL_DATATYPE_NULL_S // Empty for now - ) - SPINEL_DATATYPE_STRUCT_S( // Vendor-data - SPINEL_DATATYPE_NULL_S // Empty for now - ), - aFrame->mPower, // TX Power - -128, // Noise Floor (Currently unused) - flags // Flags + SuccessOrExit(mEncoder.WriteInt8(aFrame->mPower)); // TX Power + SuccessOrExit(mEncoder.WriteInt8(-128)); // Noise floor (Currently unused) + SuccessOrExit(mEncoder.WriteUint16(flags)); // Flags - // Skip PHY and Vendor data for now - )); + SuccessOrExit(mEncoder.OpenStruct()); // PHY-data + // Empty for now + SuccessOrExit(mEncoder.CloseStruct()); - SuccessOrExit(OutboundFrameSend()); + SuccessOrExit(mEncoder.OpenStruct()); // Vendor-data + // Empty for now + SuccessOrExit(mEncoder.CloseStruct()); + + SuccessOrExit(mEncoder.EndFrame()); exit: return; @@ -1033,25 +970,34 @@ exit: otError NcpBase::HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey) { unsigned i; + bool found = false; otError error = OT_ERROR_NONE; for (i = 0; i < sizeof(mGetPropertyHandlerTable) / sizeof(mGetPropertyHandlerTable[0]); i++) { if (mGetPropertyHandlerTable[i].mPropKey == aKey) { + found = true; break; } } - if (i < sizeof(mGetPropertyHandlerTable) / sizeof(mGetPropertyHandlerTable[0])) + mDisableStreamWrite = true; + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + + if (found) { - error = (this->*mGetPropertyHandlerTable[i].mHandler)(aHeader, aKey); + SuccessOrExit(error = (this->*mGetPropertyHandlerTable[i].mHandler)()); } else { - error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND); + SuccessOrExit(error = mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_PROP_NOT_FOUND)); } + SuccessOrExit(error = mEncoder.EndFrame()); + +exit: + mDisableStreamWrite = false; return error; } @@ -1086,6 +1032,7 @@ otError NcpBase::HandleCommandPropertyInsert(uint8_t aHeader, spinel_prop_key_t { unsigned i; otError error = OT_ERROR_NONE; + spinel_status_t spinelError = SPINEL_STATUS_PROP_NOT_FOUND; for (i = 0; i < sizeof(mInsertPropertyHandlerTable) / sizeof(mInsertPropertyHandlerTable[0]); i++) { @@ -1097,13 +1044,22 @@ otError NcpBase::HandleCommandPropertyInsert(uint8_t aHeader, spinel_prop_key_t if (i < sizeof(mInsertPropertyHandlerTable) / sizeof(mInsertPropertyHandlerTable[0])) { - error = (this->*mInsertPropertyHandlerTable[i].mHandler)(aHeader, aKey, aValuePtr, aValueLen); + spinelError = ThreadErrorToSpinelStatus( + (this->*mInsertPropertyHandlerTable[i].mHandler)(aValuePtr, aValueLen)); + } + + if (spinelError == SPINEL_STATUS_OK) + { + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_INSERTED, aKey)); + SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen)); + SuccessOrExit(error = mEncoder.EndFrame()); } else { - error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND); + SuccessOrExit(error = SendLastStatus(aHeader, spinelError)); } +exit: return error; } @@ -1112,6 +1068,7 @@ otError NcpBase::HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t { unsigned i; otError error = OT_ERROR_NONE; + spinel_status_t spinelError = SPINEL_STATUS_PROP_NOT_FOUND; for (i = 0; i < sizeof(mRemovePropertyHandlerTable) / sizeof(mRemovePropertyHandlerTable[0]); i++) { @@ -1123,92 +1080,43 @@ otError NcpBase::HandleCommandPropertyRemove(uint8_t aHeader, spinel_prop_key_t if (i < sizeof(mRemovePropertyHandlerTable) / sizeof(mRemovePropertyHandlerTable[0])) { - error = (this->*mRemovePropertyHandlerTable[i].mHandler)(aHeader, aKey, aValuePtr, aValueLen); + spinelError = ThreadErrorToSpinelStatus( + (this->*mRemovePropertyHandlerTable[i].mHandler)(aValuePtr, aValueLen)); + } + + if (spinelError == SPINEL_STATUS_OK) + { + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_REMOVED, aKey)); + SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen)); + SuccessOrExit(error = mEncoder.EndFrame()); } else { - error = SendLastStatus(aHeader, SPINEL_STATUS_PROP_NOT_FOUND); + SuccessOrExit(error = SendLastStatus(aHeader, spinelError)); } +exit: return error; } - // ---------------------------------------------------------------------------- -// MARK: Outbound Command Handlers +// MARK: Outbound Frame Methods // ---------------------------------------------------------------------------- otError NcpBase::SendLastStatus(uint8_t aHeader, spinel_status_t aLastStatus) { + otError error = OT_ERROR_NONE; + if (SPINEL_HEADER_GET_IID(aHeader) == 0) { mLastStatus = aLastStatus; } - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - SPINEL_PROP_LAST_STATUS, - SPINEL_DATATYPE_UINT_PACKED_S, - aLastStatus - ); -} - -otError NcpBase::SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, - const char *aPackFormat, ...) -{ - otError error = OT_ERROR_NONE; - va_list args; - - va_start(args, aPackFormat); - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_COMMAND_PROP_S, aHeader, aCommand, aKey)); - SuccessOrExit(error = OutboundFrameFeedVPacked(aPackFormat, args)); - SuccessOrExit(error = OutboundFrameSend()); + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_LAST_STATUS)); + SuccessOrExit(error = mEncoder.WriteUintPacked(aLastStatus)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: - va_end(args); - return error; -} - -otError NcpBase::SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) -{ - otError error = OT_ERROR_NONE; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_COMMAND_PROP_S, aHeader, aCommand, aKey)); - SuccessOrExit(error = OutboundFrameFeedData(aValuePtr, aValueLen)); - SuccessOrExit(error = OutboundFrameSend()); - -exit: - return error; -} - -otError NcpBase::SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, otMessage *aMessage) -{ - otError error = OT_ERROR_NONE; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_COMMAND_PROP_S, aHeader, aCommand, aKey)); - SuccessOrExit(error = OutboundFrameFeedMessage(aMessage)); - - // Set the `aMessage` pointer to NULL to indicate that it does - // not need to be freed at the exit. The `aMessage` is now owned - // by the OutboundFrame and will be freed when the frame is either - // successfully sent and then removed, or if the frame gets - // discarded. - aMessage = NULL; - - SuccessOrExit(error = OutboundFrameSend()); - -exit: - - if (aMessage != NULL) - { - otMessageFree(aMessage); - } - return error; } @@ -1226,34 +1134,6 @@ otError NcpBase::SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey return aError; } -otError NcpBase::OutboundFrameFeedVPacked(const char *aPackFormat, va_list aArgs) -{ - uint8_t buf[96]; - otError error = OT_ERROR_NO_BUFS; - spinel_ssize_t packedLen; - - packedLen = spinel_datatype_vpack(buf, sizeof(buf), aPackFormat, aArgs); - - if ((packedLen > 0) && (packedLen <= static_cast(sizeof(buf)))) - { - error = OutboundFrameFeedData(buf, static_cast(packedLen)); - } - - return error; -} - -otError NcpBase::OutboundFrameFeedPacked(const char *aPackFormat, ...) -{ - otError error; - va_list args; - - va_start(args, aPackFormat); - error = OutboundFrameFeedVPacked(aPackFormat, args); - va_end(args); - - return error; -} - // ---------------------------------------------------------------------------- // MARK: Individual Command Handlers // ---------------------------------------------------------------------------- @@ -1466,21 +1346,11 @@ otError NcpBase::CommandHandler_PEEK(uint8_t aHeader, unsigned int aCommand, con VerifyOrExit(mAllowPeekDelegate(address, count), spinelError = SPINEL_STATUS_INVALID_ARGUMENT); } - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - ( - SPINEL_DATATYPE_COMMAND_S // Header and Command - SPINEL_DATATYPE_UINT32_S // Address - SPINEL_DATATYPE_UINT16_S // Count - ), - aHeader, - SPINEL_CMD_PEEK_RET, - address, - count - )); - SuccessOrExit(error = OutboundFrameFeedData(reinterpret_cast(address), count)); - SuccessOrExit(error = OutboundFrameSend()); + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PEEK_RET)); + SuccessOrExit(error = mEncoder.WriteUint32(address)); + SuccessOrExit(error = mEncoder.WriteUint16(count)); + SuccessOrExit(error = mEncoder.WriteData(reinterpret_cast(address), count)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: if (spinelError != SPINEL_STATUS_OK) @@ -1544,30 +1414,18 @@ exit: // MARK: Individual Property Getters and Setters // ---------------------------------------------------------------------------- -otError NcpBase::GetPropertyHandler_PHY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_PHY_ENABLED(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, #if OPENTHREAD_ENABLE_RAW_LINK_API - otLinkRawIsEnabled(mInstance) + return mEncoder.WriteBool(otLinkRawIsEnabled(mInstance)); #else - false -#endif // OPENTHREAD_ENABLE_RAW_LINK_API - ); + return mEncoder.WriteBool(false); +#endif } -otError NcpBase::GetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_PHY_CHAN(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otLinkGetChannel(mInstance) - ); + return mEncoder.WriteUint8(otLinkGetChannel(mInstance)); } otError NcpBase::SetPropertyHandler_PHY_CHAN(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -1612,17 +1470,12 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_PROMISCUOUS_MODE(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_INT8_S, - otPlatRadioGetPromiscuous(mInstance) - ? SPINEL_MAC_PROMISCUOUS_MODE_FULL - : SPINEL_MAC_PROMISCUOUS_MODE_OFF - ); + return mEncoder.WriteUint8(otPlatRadioGetPromiscuous(mInstance) + ? SPINEL_MAC_PROMISCUOUS_MODE_FULL + : SPINEL_MAC_PROMISCUOUS_MODE_OFF + ); } otError NcpBase::SetPropertyHandler_MAC_PROMISCUOUS_MODE(uint8_t aHeader, spinel_prop_key_t aKey, @@ -1661,15 +1514,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_MAC_15_4_PANID(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_15_4_PANID(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT16_S, - otLinkGetPanId(mInstance) - ); + return mEncoder.WriteUint16(otLinkGetPanId(mInstance)); } otError NcpBase::SetPropertyHandler_MAC_15_4_PANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -1694,15 +1541,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_MAC_15_4_LADDR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_15_4_LADDR(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_EUI64_S, - otLinkGetExtendedAddress(mInstance) - ); + return mEncoder.WriteEui64(*otLinkGetExtendedAddress(mInstance)); } otError NcpBase::SetPropertyHandler_MAC_15_4_LADDR(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -1727,26 +1568,14 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_MAC_15_4_SADDR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_15_4_SADDR(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT16_S, - otLinkGetShortAddress(mInstance) - ); + return mEncoder.WriteUint16(otLinkGetShortAddress(mInstance)); } -otError NcpBase::GetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_RAW_STREAM_ENABLED(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - mIsRawStreamEnabled - ); + return mEncoder.WriteBool(mIsRawStreamEnabled); } otError NcpBase::SetPropertyHandler_MAC_RAW_STREAM_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, @@ -1787,33 +1616,22 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_FILTER(void) { otError error = OT_ERROR_NONE; uint8_t numEntries; const ChangedPropsSet::Entry *entry; - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - entry = mChangedPropsSet.GetSupportedEntries(numEntries); for (uint8_t index = 0; index < numEntries; index++, entry++) { if (mChangedPropsSet.IsEntryFiltered(index)) { - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, entry->mPropKey)); + SuccessOrExit(error = mEncoder.WriteUintPacked(entry->mPropKey)); } } - SuccessOrExit(error = OutboundFrameSend()); - exit: return error; } @@ -1863,12 +1681,10 @@ exit: return error; } -otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; unsigned int propKey; parsedLength = spinel_datatype_unpack( @@ -1878,35 +1694,18 @@ otError NcpBase::InsertPropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spin &propKey ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), true); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; unsigned int propKey; parsedLength = spinel_datatype_unpack( @@ -1916,169 +1715,106 @@ otError NcpBase::RemovePropertyHandler_UNSOL_UPDATE_FILTER(uint8_t aHeader, spin &propKey ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = mChangedPropsSet.EnablePropertyFilter(static_cast(propKey), false); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::GetPropertyHandler_LAST_STATUS(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_LAST_STATUS(void) { - return SendPropertyUpdate(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey, SPINEL_DATATYPE_UINT_PACKED_S, mLastStatus); + return mEncoder.WriteUintPacked(mLastStatus); } -otError NcpBase::GetPropertyHandler_PROTOCOL_VERSION(uint8_t aHeader, spinel_prop_key_t aKey) -{ - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - ( - SPINEL_DATATYPE_UINT_PACKED_S // Major - SPINEL_DATATYPE_UINT_PACKED_S // Minor - ), - SPINEL_PROTOCOL_VERSION_THREAD_MAJOR, - SPINEL_PROTOCOL_VERSION_THREAD_MINOR - ); -} - -otError NcpBase::GetPropertyHandler_INTERFACE_TYPE(uint8_t aHeader, spinel_prop_key_t aKey) -{ - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT_PACKED_S, - SPINEL_PROTOCOL_TYPE_THREAD - ); -} - -otError NcpBase::GetPropertyHandler_VENDOR_ID(uint8_t aHeader, spinel_prop_key_t aKey) -{ - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT_PACKED_S, - 0 // Vendor ID. Zero for unknown. - ); -} - -otError NcpBase::GetPropertyHandler_CAPS(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_PROTOCOL_VERSION(void) { otError error = OT_ERROR_NONE; - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROTOCOL_VERSION_THREAD_MAJOR)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROTOCOL_VERSION_THREAD_MINOR)); - // Begin adding capabilities ////////////////////////////////////////////// +exit: + return error; +} - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_COUNTERS)); - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_UNSOL_UPDATE_FILTER)); +otError NcpBase::GetPropertyHandler_INTERFACE_TYPE(void) +{ + return mEncoder.WriteUintPacked(SPINEL_PROTOCOL_TYPE_THREAD); +} + +otError NcpBase::GetPropertyHandler_VENDOR_ID(void) +{ + return mEncoder.WriteUintPacked(0); // Vendor ID. Zero for unknown. +} + +otError NcpBase::GetPropertyHandler_CAPS(void) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_COUNTERS)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_UNSOL_UPDATE_FILTER)); #if OPENTHREAD_ENABLE_RAW_LINK_API - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_MAC_RAW)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_MAC_RAW)); #endif #if OPENTHREAD_MTD || OPENTHREAD_FTD - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_NET_THREAD_1_0)); + + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_NET_THREAD_1_0)); #if OPENTHREAD_ENABLE_MAC_FILTER - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_MAC_WHITELIST)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_MAC_WHITELIST)); #endif #if OPENTHREAD_ENABLE_JAM_DETECTION - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_JAM_DETECT)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_JAM_DETECT)); #endif #if OPENTHREAD_CONFIG_ENABLE_STEERING_DATA_SET_OOB - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_OOB_STEERING_DATA)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_OOB_STEERING_DATA)); #endif #if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_PEEK_POKE)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_PEEK_POKE)); #endif // TODO: Somehow get the following capability from the radio. - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_802_15_4_2450MHZ_OQPSK)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_802_15_4_2450MHZ_OQPSK)); #if OPENTHREAD_CONFIG_MAX_CHILDREN > 0 - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_ROLE_ROUTER)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_ROLE_ROUTER)); #endif - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_ROLE_SLEEPY)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_ROLE_SLEEPY)); #if OPENTHREAD_ENABLE_LEGACY - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_NEST_LEGACY_INTERFACE)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_NEST_LEGACY_INTERFACE)); #endif #if OPENTHREAD_ENABLE_TMF_PROXY - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_THREAD_TMF_PROXY)); + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_CAP_THREAD_TMF_PROXY)); #endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD - // End adding capabilities ///////////////////////////////////////////////// - - SuccessOrExit(error = OutboundFrameSend()); exit: return error; } -otError NcpBase::GetPropertyHandler_NCP_VERSION(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NCP_VERSION(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UTF8_S, - otGetVersionString() - ); + return mEncoder.WriteUtf8(otGetVersionString()); } -otError NcpBase::GetPropertyHandler_INTERFACE_COUNT(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_INTERFACE_COUNT(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - 1 // Only one interface for now - ); + return mEncoder.WriteUint8(1); // Only one interface for now } -otError NcpBase::GetPropertyHandler_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_POWER_STATE(void) { - // Always online at the moment - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - SPINEL_POWER_STATE_ONLINE - ); + return mEncoder.WriteUint8(SPINEL_POWER_STATE_ONLINE); // Always online at the moment } otError NcpBase::SetPropertyHandler_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -2092,37 +1828,23 @@ otError NcpBase::SetPropertyHandler_POWER_STATE(uint8_t aHeader, spinel_prop_key return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED); } -otError NcpBase::GetPropertyHandler_HWADDR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_HWADDR(void) { otExtAddress hwAddr; - otPlatRadioGetIeeeEui64(mInstance, hwAddr.m8); + otLinkGetFactoryAssignedIeeeEui64(mInstance, &hwAddr); - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_EUI64_S, - hwAddr.m8 - ); + return mEncoder.WriteEui64(hwAddr); } -otError NcpBase::GetPropertyHandler_LOCK(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_LOCK(void) { // TODO: Implement property lock (Needs API!) - OT_UNUSED_VARIABLE(aKey); - - return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED); + return mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_UNIMPLEMENTED); } -otError NcpBase::GetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_HOST_POWER_STATE(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - mHostPowerState - ); + return mEncoder.WriteUint8(mHostPowerState); } otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -2206,57 +1928,34 @@ otError NcpBase::SetPropertyHandler_HOST_POWER_STATE(uint8_t aHeader, spinel_pro return error; } -otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_LIST(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_UNSOL_UPDATE_LIST(void) { otError error = OT_ERROR_NONE; uint8_t numEntries; const ChangedPropsSet::Entry *entry; - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - entry = mChangedPropsSet.GetSupportedEntries(numEntries); for (uint8_t index = 0; index < numEntries; index++, entry++) { if (entry->mFilterable) { - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, entry->mPropKey)); + SuccessOrExit(error = mEncoder.WriteUintPacked(entry->mPropKey)); } } - SuccessOrExit(error = OutboundFrameSend()); - exit: return error; } -otError NcpBase::GetPropertyHandler_PHY_RX_SENSITIVITY(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_PHY_RX_SENSITIVITY(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_INT8_S, - otPlatRadioGetReceiveSensitivity(mInstance) - ); + return mEncoder.WriteInt8(otPlatRadioGetReceiveSensitivity(mInstance)); } -otError NcpBase::GetPropertyHandler_PHY_TX_POWER(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_PHY_TX_POWER(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_INT8_S, - otLinkGetMaxTransmitPower(mInstance) - ); + return mEncoder.WriteInt8(otLinkGetMaxTransmitPower(mInstance)); } otError NcpBase::SetPropertyHandler_PHY_TX_POWER(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -2281,7 +1980,7 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_DEBUG_TEST_ASSERT(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_DEBUG_TEST_ASSERT(void) { assert(false); @@ -2291,17 +1990,11 @@ otError NcpBase::GetPropertyHandler_DEBUG_TEST_ASSERT(uint8_t aHeader, spinel_pr // property value to indicate this. OT_UNREACHABLE_CODE( - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - false - ); + return mEncoder.WriteBool(false); ) } -otError NcpBase::GetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_DEBUG_NCP_LOG_LEVEL(void) { uint8_t logLevel = 0; @@ -2328,13 +2021,7 @@ otError NcpBase::GetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_ break; } - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - logLevel - ); + return mEncoder.WriteUint8(logLevel); } otError NcpBase::SetPropertyHandler_DEBUG_NCP_LOG_LEVEL(uint8_t aHeader, spinel_prop_key_t aKey, diff --git a/src/ncp/ncp_base.hpp b/src/ncp/ncp_base.hpp index ea9342101..6a641d096 100644 --- a/src/ncp/ncp_base.hpp +++ b/src/ncp/ncp_base.hpp @@ -47,6 +47,7 @@ #include "changed_props_set.hpp" #include "common/tasklet.hpp" #include "ncp/ncp_buffer.hpp" +#include "ncp/spinel_encoder.hpp" #include "spinel.h" @@ -63,10 +64,7 @@ namespace Ncp { #define NCP_GET_PROP_HANDLER(name) \ - otError GetPropertyHandler_##name( \ - uint8_t aHeader, \ - spinel_prop_key_t aKey \ - ) + otError GetPropertyHandler_##name(void) #define NCP_SET_PROP_HANDLER(name) \ otError SetPropertyHandler_##name( \ @@ -78,16 +76,12 @@ namespace Ncp { #define NCP_INSERT_PROP_HANDLER(name) \ otError InsertPropertyHandler_##name( \ - uint8_t aHeader, \ - spinel_prop_key_t aKey, \ const uint8_t *aValuePtr, \ uint16_t aValueLen \ ) #define NCP_REMOVE_PROP_HANDLER(name) \ otError RemovePropertyHandler_##name( \ - uint8_t aHeader, \ - spinel_prop_key_t aKey, \ const uint8_t *aValuePtr, \ uint16_t aValueLen \ ) @@ -175,59 +169,6 @@ public: #endif #endif // OPENTHREAD_MTD || OPENTHREAD_FTD -protected: - /** - * This method is called to start a new outbound frame. - * - * param[in] aHeader The spinel header byte - * - * @retval OT_ERROR_NONE Successfully started a new frame. - * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. - * - */ - otError OutboundFrameBegin(uint8_t aHeader); - - /** - * This method adds data to the current outbound frame being written. - * - * If no buffer space is available, this method should discard and clear the frame before returning an error status. - * - * @param[in] aDataBuffer A pointer to data buffer. - * @param[in] aDataBufferLength The length of the data buffer. - * - * @retval OT_ERROR_NONE Successfully added new data to the frame. - * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add data. - * - */ - otError OutboundFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength); - - /** - * This method adds a message to the current outbound frame being written. - * - * If no buffer space is available, this method should discard and clear the frame before returning an error status. - * In case of success, the passed-in message @aMessage should be owned by outbound buffer and should be freed - * when either the frame is successfully sent and removed or if the frame is discarded. - * - * @param[in] aMessage A reference to the message to be added to current frame. - * - * @retval OT_ERROR_NONE Successfully added the message to the frame. - * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message. - * - */ - otError OutboundFrameFeedMessage(otMessage *aMessage); - - /** - * This method finalizes and sends the current outbound frame - * - * If no buffer space is available, this method should discard and clear the frame - * before returning an error status. - * - * @retval OT_ERROR_NONE Successfully added the message to the frame. - * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message. - * - */ - otError OutboundFrameEnd(void); - /** * This method is called by the framer whenever a framing error is detected. */ @@ -252,7 +193,9 @@ private: typedef otError(NcpBase::*CommandHandlerType)(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen); - typedef otError(NcpBase::*GetPropertyHandlerType)(uint8_t aHeader, spinel_prop_key_t aKey); + typedef otError(NcpBase::*GetPropertyHandlerType)(void); + + typedef otError(NcpBase::*InsertRemovePropertyHandlerType)(const uint8_t *aValuePtr, uint16_t aValueLen); typedef otError(NcpBase::*SetPropertyHandlerType)(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, uint16_t aValueLen); @@ -278,24 +221,17 @@ private: struct InsertPropertyHandlerEntry { spinel_prop_key_t mPropKey; - SetPropertyHandlerType mHandler; + InsertRemovePropertyHandlerType mHandler; }; struct RemovePropertyHandlerEntry { spinel_prop_key_t mPropKey; - SetPropertyHandlerType mHandler; + InsertRemovePropertyHandlerType mHandler; }; - otError OutboundFrameSend(void); - NcpFrameBuffer::FrameTag GetLastOutboundFrameTag(void); - otError OutboundFrameFeedPacked(const char *aPackFormat, ...); - - otError OutboundFrameFeedVPacked(const char *aPackFormat, va_list aArgs); - - otError HandleCommand(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, uint16_t aArgLen); otError HandleCommandPropertyGet(uint8_t aHeader, spinel_prop_key_t aKey); @@ -311,14 +247,6 @@ private: otError SendLastStatus(uint8_t aHeader, spinel_status_t aLastStatus); - - otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, const uint8_t *aValuePtr, - uint16_t aValueLen); - - otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, otMessage *message); - - otError SendPropertyUpdate(uint8_t aHeader, uint8_t aCommand, spinel_prop_key_t aKey, const char *format, ...); - otError SendSetPropertyResponse(uint8_t aHeader, spinel_prop_key_t aKey, otError aError); static void UpdateChangedProps(Tasklet &aTasklet); @@ -363,7 +291,7 @@ private: static void SendDoneTask(void *aContext); void SendDoneTask(void); - otError GetPropertyHandler_ChannelMaskHelper(uint8_t aHeader, spinel_prop_key_t aKey, uint32_t channel_mask); + otError GetPropertyHandler_ChannelMaskHelper(uint32_t channel_mask); #endif // OPENTHREAD_MTD || OPENTHREAD_FTD #if OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY @@ -536,9 +464,52 @@ private: #endif NCP_GET_PROP_HANDLER(STREAM_NET); NCP_SET_PROP_HANDLER(STREAM_NET); - NCP_GET_PROP_HANDLER(MAC_CNTR); - NCP_GET_PROP_HANDLER(NCP_CNTR); - NCP_GET_PROP_HANDLER(IP_CNTR); + + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_TOTAL); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_ACK_REQ); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_ACKED); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_NO_ACK_REQ); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_DATA); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_DATA_POLL); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_BEACON); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_BEACON_REQ); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_OTHER); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_RETRY); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_UNICAST); + NCP_GET_PROP_HANDLER(CNTR_TX_PKT_BROADCAST); + NCP_GET_PROP_HANDLER(CNTR_TX_ERR_CCA); + NCP_GET_PROP_HANDLER(CNTR_TX_ERR_ABORT); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_TOTAL); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_DATA); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_DATA_POLL); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_BEACON); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_BEACON_REQ); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_OTHER); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_FILT_WL); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_FILT_DA); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_UNICAST); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_BROADCAST); + NCP_GET_PROP_HANDLER(CNTR_RX_ERR_EMPTY); + NCP_GET_PROP_HANDLER(CNTR_RX_ERR_UKWN_NBR); + NCP_GET_PROP_HANDLER(CNTR_RX_ERR_NVLD_SADDR); + NCP_GET_PROP_HANDLER(CNTR_RX_ERR_SECURITY); + NCP_GET_PROP_HANDLER(CNTR_RX_ERR_BAD_FCS); + NCP_GET_PROP_HANDLER(CNTR_RX_ERR_OTHER); + NCP_GET_PROP_HANDLER(CNTR_RX_PKT_DUP); + NCP_GET_PROP_HANDLER(CNTR_TX_IP_SEC_TOTAL); + NCP_GET_PROP_HANDLER(CNTR_TX_IP_INSEC_TOTAL); + NCP_GET_PROP_HANDLER(CNTR_TX_IP_DROPPED); + NCP_GET_PROP_HANDLER(CNTR_RX_IP_SEC_TOTAL); + NCP_GET_PROP_HANDLER(CNTR_RX_IP_INSEC_TOTAL); + NCP_GET_PROP_HANDLER(CNTR_RX_IP_DROPPED); + NCP_GET_PROP_HANDLER(CNTR_TX_SPINEL_TOTAL); + NCP_GET_PROP_HANDLER(CNTR_RX_SPINEL_TOTAL); + NCP_GET_PROP_HANDLER(CNTR_RX_SPINEL_OUT_OF_ORDER_TID); + NCP_GET_PROP_HANDLER(CNTR_RX_SPINEL_ERR); + NCP_GET_PROP_HANDLER(CNTR_IP_TX_SUCCESS); + NCP_GET_PROP_HANDLER(CNTR_IP_RX_SUCCESS); + NCP_GET_PROP_HANDLER(CNTR_IP_TX_FAILURE); + NCP_GET_PROP_HANDLER(CNTR_IP_RX_FAILURE); NCP_GET_PROP_HANDLER(MSG_BUFFER_COUNTERS); #if OPENTHREAD_ENABLE_MAC_FILTER NCP_GET_PROP_HANDLER(MAC_WHITELIST_ENABLED); @@ -639,6 +610,7 @@ protected: static uint8_t LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aSecureDataRequests, bool aDeviceType, bool aNetworkData); otInstance *mInstance; NcpFrameBuffer mTxFrameBuffer; + SpinelEncoder mEncoder; bool mHostPowerStateInProgress; private: diff --git a/src/ncp/ncp_base_ftd.cpp b/src/ncp/ncp_base_ftd.cpp index 50835955b..193a6f0e5 100644 --- a/src/ncp/ncp_base_ftd.cpp +++ b/src/ncp/ncp_base_ftd.cpp @@ -56,53 +56,28 @@ namespace ot { namespace Ncp { -otError NcpBase::GetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_LOCAL_LEADER_WEIGHT(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otThreadGetLocalLeaderWeight(mInstance) - ); + return mEncoder.WriteUint8(otThreadGetLocalLeaderWeight(mInstance)); } -otError NcpBase::GetPropertyHandler_THREAD_LEADER_WEIGHT(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_LEADER_WEIGHT(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otThreadGetLeaderWeight(mInstance) - ); + return mEncoder.WriteUint8(otThreadGetLeaderWeight(mInstance)); } -otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(void) { otError error = OT_ERROR_NONE; otChildInfo childInfo; uint8_t maxChildren; uint8_t modeFlags; - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - maxChildren = otThreadGetMaxAllowedChildren(mInstance); for (uint8_t index = 0; index < maxChildren; index++) { - error = otThreadGetChildInfoByIndex(mInstance, index, &childInfo); - - if (error != OT_ERROR_NONE) + if (otThreadGetChildInfoByIndex(mInstance, index, &childInfo) != OT_ERROR_NONE) { continue; } @@ -114,47 +89,28 @@ otError NcpBase::GetPropertyHandler_THREAD_CHILD_TABLE(uint8_t aHeader, spinel_p childInfo.mFullNetworkData ); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S // EUI64 Address - SPINEL_DATATYPE_UINT16_S // Rloc16 - SPINEL_DATATYPE_UINT32_S // Timeout - SPINEL_DATATYPE_UINT32_S // Age - SPINEL_DATATYPE_UINT8_S // Network Data Version - SPINEL_DATATYPE_UINT8_S // Link Quality In - SPINEL_DATATYPE_INT8_S // Average RSS - SPINEL_DATATYPE_UINT8_S // Mode (flags) - SPINEL_DATATYPE_INT8_S // Most recent RSS - ), - childInfo.mExtAddress.m8, - childInfo.mRloc16, - childInfo.mTimeout, - childInfo.mAge, - childInfo.mNetworkDataVersion, - childInfo.mLinkQualityIn, - childInfo.mAverageRssi, - modeFlags, - childInfo.mLastRssi - )); + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteEui64(childInfo.mExtAddress)); + SuccessOrExit(error = mEncoder.WriteUint16(childInfo.mRloc16)); + SuccessOrExit(error = mEncoder.WriteUint32(childInfo.mTimeout)); + SuccessOrExit(error = mEncoder.WriteUint32(childInfo.mAge)); + SuccessOrExit(error = mEncoder.WriteUint8(childInfo.mNetworkDataVersion)); + SuccessOrExit(error = mEncoder.WriteUint8(childInfo.mLinkQualityIn)); + SuccessOrExit(error = mEncoder.WriteInt8(childInfo.mAverageRssi)); + SuccessOrExit(error = mEncoder.WriteUint8(modeFlags)); + SuccessOrExit(error = mEncoder.WriteInt8(childInfo.mLastRssi)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } -otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - otThreadIsRouterRoleEnabled(mInstance) - ); + return mEncoder.WriteBool(otThreadIsRouterRoleEnabled(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_ROUTER_ROLE_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, @@ -179,16 +135,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_PSKC(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_DATA_S, - otThreadGetPSKc(mInstance), - sizeof(spinel_net_pskc_t) - ); + return mEncoder.WriteData(otThreadGetPSKc(mInstance), sizeof(spinel_net_pskc_t)); } otError NcpBase::SetPropertyHandler_NET_PSKC(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -215,15 +164,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_CHILD_COUNT_MAX(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otThreadGetMaxAllowedChildren(mInstance) - ); + return mEncoder.WriteUint8(otThreadGetMaxAllowedChildren(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_CHILD_COUNT_MAX(uint8_t aHeader, spinel_prop_key_t aKey, @@ -248,15 +191,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otThreadGetRouterUpgradeThreshold(mInstance) - ); + return mEncoder.WriteUint8(otThreadGetRouterUpgradeThreshold(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_ROUTER_UPGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey, @@ -281,15 +218,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otThreadGetRouterDowngradeThreshold(mInstance) - ); + return mEncoder.WriteUint8(otThreadGetRouterDowngradeThreshold(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_ROUTER_DOWNGRADE_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey, @@ -314,15 +245,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otThreadGetRouterSelectionJitter(mInstance) - ); + return mEncoder.WriteUint8(otThreadGetRouterSelectionJitter(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_ROUTER_SELECTION_JITTER(uint8_t aHeader, spinel_prop_key_t aKey, @@ -347,15 +272,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - otThreadGetContextIdReuseDelay(mInstance) - ); + return mEncoder.WriteUint32(otThreadGetContextIdReuseDelay(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, spinel_prop_key_t aKey, @@ -380,15 +299,9 @@ otError NcpBase::SetPropertyHandler_THREAD_CONTEXT_REUSE_DELAY(uint8_t aHeader, return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otThreadGetNetworkIdTimeout(mInstance) - ); + return mEncoder.WriteUint8(otThreadGetNetworkIdTimeout(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey, @@ -414,22 +327,9 @@ otError NcpBase::SetPropertyHandler_THREAD_NETWORK_ID_TIMEOUT(uint8_t aHeader, s } #if OPENTHREAD_ENABLE_COMMISSIONER -otError NcpBase::GetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_COMMISSIONER_ENABLED(void) { - bool enabled = false; - - if (otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE) - { - enabled = true; - } - - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - enabled - ); + return mEncoder.WriteBool(otCommissionerGetState(mInstance) == OT_COMMISSIONER_STATE_ACTIVE); } otError NcpBase::SetPropertyHandler_THREAD_COMMISSIONER_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, @@ -464,17 +364,15 @@ exit: return SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); } -otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress = NULL; const char *aPSKd = NULL; uint32_t joinerTimeout = 0; - VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE); + VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); parsedLength = spinel_datatype_unpack( aValuePtr, @@ -504,26 +402,11 @@ otError NcpBase::InsertPropertyHandler_THREAD_JOINERS(uint8_t aHeader, spinel_pr extAddress = NULL; } - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otCommissionerAddJoiner(mInstance, extAddress, aPSKd, joinerTimeout); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } @@ -558,6 +441,7 @@ otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(uint8_t aHeader, spinel otExtAddress *extAddress; spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; + spinel_status_t spinelError = SPINEL_STATUS_OK; parsedLength = spinel_datatype_unpack( aValuePtr, @@ -566,26 +450,21 @@ otError NcpBase::SetPropertyHandler_THREAD_STEERING_DATA(uint8_t aHeader, spinel &extAddress ); - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); error = otThreadSetSteeringData(mInstance, extAddress); + VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); + + // Note that there is no get handler for this property + + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + SuccessOrExit(error = mEncoder.WriteEui64(*extAddress)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: - - if (error == OT_ERROR_NONE) + if (spinelError != SPINEL_STATUS_OK) { - // Note that there is no get handler for this property. - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_EUI64_S, - extAddress->m8 - ); - } - else - { - error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); + error = SendLastStatus(aHeader, spinelError); } return error; @@ -620,44 +499,7 @@ otError NcpBase::SetPropertyHandler_THREAD_PREFERRED_ROUTER_ID(uint8_t aHeader, uint8_t routerId = 0; spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT8_S, - &routerId - ); - - VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); - - error = otThreadSetPreferredRouterId(mInstance, routerId); - -exit: - if (error == OT_ERROR_NONE) - { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - routerId - ); - } - else - { - error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); - } - - return error; -} - -otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) -{ - spinel_ssize_t parsedLength; - otError error = OT_ERROR_NONE; spinel_status_t spinelError = SPINEL_STATUS_OK; - uint8_t routerId; parsedLength = spinel_datatype_unpack( aValuePtr, @@ -668,24 +510,16 @@ otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(uint8_t aHeader, VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); - error = otThreadReleaseRouterId(mInstance, routerId); - - // `INVALID_STATE` is returned when router ID was not allocated (i.e. not in the list) - // in such a case, the "remove" operation can be considered successful. - VerifyOrExit(error != OT_ERROR_INVALID_STATE, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - + error = otThreadSetPreferredRouterId(mInstance, routerId); VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); + // Note that there is no get handler for this property. + + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + SuccessOrExit(error = mEncoder.WriteUint8(routerId)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: - if (spinelError != SPINEL_STATUS_OK) { error = SendLastStatus(aHeader, spinelError); @@ -694,16 +528,39 @@ exit: return error; } -#if OPENTHREAD_ENABLE_TMF_PROXY -otError NcpBase::GetPropertyHandler_THREAD_TMF_PROXY_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::RemovePropertyHandler_THREAD_ACTIVE_ROUTER_IDS(const uint8_t *aValuePtr, uint16_t aValueLen) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - otTmfProxyIsEnabled(mInstance) - ); + spinel_ssize_t parsedLength; + otError error = OT_ERROR_NONE; + uint8_t routerId; + + parsedLength = spinel_datatype_unpack( + aValuePtr, + aValueLen, + SPINEL_DATATYPE_UINT8_S, + &routerId + ); + + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + + error = otThreadReleaseRouterId(mInstance, routerId); + + // `INVALID_STATE` is returned when router ID was not allocated (i.e. not in the list) + // in such a case, the "remove" operation can be considered successful. + + if (error == OT_ERROR_INVALID_STATE) + { + error = OT_ERROR_NONE; + } + +exit: + return error; +} + +#if OPENTHREAD_ENABLE_TMF_PROXY +otError NcpBase::GetPropertyHandler_THREAD_TMF_PROXY_ENABLED(void) +{ + return mEncoder.WriteBool(otTmfProxyIsEnabled(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_TMF_PROXY_STREAM(uint8_t aHeader, spinel_prop_key_t aKey, @@ -812,34 +669,24 @@ void NcpBase::HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint1 uint16_t length = otMessageGetLength(aMessage); uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0; - SuccessOrExit(error = OutboundFrameBegin(header)); - - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S, - header, - SPINEL_CMD_PROP_VALUE_IS, - SPINEL_PROP_THREAD_TMF_PROXY_STREAM, - length - )); - - SuccessOrExit(error = OutboundFrameFeedMessage(aMessage)); - - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_UINT16_S SPINEL_DATATYPE_UINT16_S, - aLocator, - aPort - )); + SuccessOrExit(error = mEncoder.BeginFrame( + header, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_THREAD_TMF_PROXY_STREAM + )); + SuccessOrExit(error = mEncoder.WriteUint16(length)); + SuccessOrExit(error = mEncoder.WriteMessage(aMessage)); // Set the `aMessage` pointer to NULL to indicate that it does // not need to be freed at the exit. The `aMessage` is now owned - // by the OutboundFrame and will be freed when the frame is either + // by the outbound frame and will be freed when the frame is either // successfully sent and then removed, or if the frame gets // discarded. aMessage = NULL; - SuccessOrExit(error = OutboundFrameSend()); + SuccessOrExit(error = mEncoder.WriteUint16(aLocator)); + SuccessOrExit(error = mEncoder.WriteUint16(aPort)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: diff --git a/src/ncp/ncp_base_mtd.cpp b/src/ncp/ncp_base_mtd.cpp index ffe98dac5..c240a27df 100644 --- a/src/ncp/ncp_base_mtd.cpp +++ b/src/ncp/ncp_base_mtd.cpp @@ -172,15 +172,9 @@ uint8_t NcpBase::LinkFlagsToFlagByte(bool aRxOnWhenIdle, bool aSecureDataRequest return flags; } -otError NcpBase::GetPropertyHandler_MAC_DATA_POLL_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_DATA_POLL_PERIOD(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - otLinkGetPollPeriod(mInstance) - ); + return mEncoder.WriteUint32(otLinkGetPollPeriod(mInstance)); } otError NcpBase::SetPropertyHandler_MAC_DATA_POLL_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey, @@ -205,19 +199,12 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } - -otError NcpBase::GetPropertyHandler_MAC_EXTENDED_ADDR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_EXTENDED_ADDR(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_EUI64_S, - otLinkGetExtendedAddress(mInstance) - ); + return mEncoder.WriteEui64(*otLinkGetExtendedAddress(mInstance)); } -otError NcpBase::GetPropertyHandler_PHY_FREQ(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_PHY_FREQ(void) { uint32_t freq_khz(0); const uint8_t chan(otLinkGetChannel(mInstance)); @@ -235,29 +222,17 @@ otError NcpBase::GetPropertyHandler_PHY_FREQ(uint8_t aHeader, spinel_prop_key_t freq_khz = 2405000 - (5000 * 11) + 5000 * (chan); } - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - freq_khz - ); + return mEncoder.WriteUint32(freq_khz); } -otError NcpBase::GetPropertyHandler_PHY_CHAN_SUPPORTED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_PHY_CHAN_SUPPORTED(void) { - return GetPropertyHandler_ChannelMaskHelper(aHeader, aKey, mSupportedChannelMask); + return GetPropertyHandler_ChannelMaskHelper(mSupportedChannelMask); } -otError NcpBase::GetPropertyHandler_PHY_RSSI(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_PHY_RSSI(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_INT8_S, - otPlatRadioGetRssi(mInstance) - ); + return mEncoder.WriteInt8(otPlatRadioGetRssi(mInstance)); } otError NcpBase::CommandHandler_NET_SAVE(uint8_t aHeader, unsigned int aCommand, const uint8_t *aArgPtr, @@ -290,26 +265,14 @@ otError NcpBase::CommandHandler_NET_RECALL(uint8_t aHeader, unsigned int aComman return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED); } -otError NcpBase::GetPropertyHandler_NET_SAVED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_SAVED(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - otDatasetIsCommissioned(mInstance) - ); + return mEncoder.WriteBool(otDatasetIsCommissioned(mInstance)); } -otError NcpBase::GetPropertyHandler_NET_IF_UP(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_IF_UP(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - otIp6IsEnabled(mInstance) - ); + return mEncoder.WriteBool(otIp6IsEnabled(mInstance)); } otError NcpBase::SetPropertyHandler_NET_IF_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -334,15 +297,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_STACK_UP(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED - ); + return mEncoder.WriteBool(otThreadGetDeviceRole(mInstance) != OT_DEVICE_ROLE_DISABLED); } otError NcpBase::SetPropertyHandler_NET_STACK_UP(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -396,7 +353,7 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_ROLE(void) { spinel_net_role_t role(SPINEL_NET_ROLE_DETACHED); @@ -420,13 +377,7 @@ otError NcpBase::GetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t break; } - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - role - ); + return mEncoder.WriteUint8(role); } otError NcpBase::SetPropertyHandler_NET_ROLE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -471,15 +422,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NET_NETWORK_NAME(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_NETWORK_NAME(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UTF8_S, - otThreadGetNetworkName(mInstance) - ); + return mEncoder.WriteUtf8(otThreadGetNetworkName(mInstance)); } otError NcpBase::SetPropertyHandler_NET_NETWORK_NAME(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -504,16 +449,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NET_XPANID(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_XPANID(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_DATA_S, - otThreadGetExtendedPanId(mInstance), - sizeof(spinel_net_xpanid_t) - ); + return mEncoder.WriteData(otThreadGetExtendedPanId(mInstance), sizeof(spinel_net_xpanid_t)); } otError NcpBase::SetPropertyHandler_NET_XPANID(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -540,16 +478,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NET_MASTER_KEY(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_MASTER_KEY(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_DATA_S, - otThreadGetMasterKey(mInstance)->m8, - OT_MASTER_KEY_SIZE - ); + return mEncoder.WriteData(otThreadGetMasterKey(mInstance)->m8, OT_MASTER_KEY_SIZE); } otError NcpBase::SetPropertyHandler_NET_MASTER_KEY(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -576,15 +507,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - otThreadGetKeySequenceCounter(mInstance) - ); + return mEncoder.WriteUint32(otThreadGetKeySequenceCounter(mInstance)); } otError NcpBase::SetPropertyHandler_NET_KEY_SEQUENCE_COUNTER(uint8_t aHeader, spinel_prop_key_t aKey, @@ -609,26 +534,14 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NET_PARTITION_ID(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_PARTITION_ID(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - otThreadGetPartitionId(mInstance) - ); + return mEncoder.WriteUint32(otThreadGetPartitionId(mInstance)); } -otError NcpBase::GetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - otThreadGetKeySwitchGuardTime(mInstance) - ); + return mEncoder.WriteUint32(otThreadGetKeySwitchGuardTime(mInstance)); } otError NcpBase::SetPropertyHandler_NET_KEY_SWITCH_GUARDTIME(uint8_t aHeader, spinel_prop_key_t aKey, @@ -653,32 +566,19 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA_VERSION(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA_VERSION(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otNetDataGetVersion(mInstance) - ); + return mEncoder.WriteUint8(otNetDataGetVersion(mInstance)); } -otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA_VERSION(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA_VERSION(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otNetDataGetStableVersion(mInstance) - ); + return mEncoder.WriteUint8(otNetDataGetStableVersion(mInstance)); } #if OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA(void) { - otError error = OT_ERROR_NONE; uint8_t networkData[255]; uint8_t networkDataLen = 255; @@ -689,24 +589,11 @@ otError NcpBase::GetPropertyHandler_THREAD_NETWORK_DATA(uint8_t aHeader, spinel_ &networkDataLen ); - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen)); - SuccessOrExit(error = OutboundFrameSend()); - -exit: - return error; + return mEncoder.WriteData(networkData, networkDataLen); } -otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA(void) { - otError error = OT_ERROR_NONE; uint8_t networkData[255]; uint8_t networkDataLen = 255; @@ -717,25 +604,12 @@ otError NcpBase::GetPropertyHandler_THREAD_STABLE_NETWORK_DATA(uint8_t aHeader, &networkDataLen ); - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen)); - SuccessOrExit(error = OutboundFrameSend()); - -exit: - return error; + return mEncoder.WriteData(networkData, networkDataLen); } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::GetPropertyHandler_THREAD_LEADER_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_LEADER_NETWORK_DATA(void) { - otError error = OT_ERROR_NONE; uint8_t networkData[255]; uint8_t networkDataLen = 255; @@ -746,24 +620,11 @@ otError NcpBase::GetPropertyHandler_THREAD_LEADER_NETWORK_DATA(uint8_t aHeader, &networkDataLen ); - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen)); - SuccessOrExit(error = OutboundFrameSend()); - -exit: - return error; + return mEncoder.WriteData(networkData, networkDataLen); } -otError NcpBase::GetPropertyHandler_THREAD_STABLE_LEADER_NETWORK_DATA(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_STABLE_LEADER_NETWORK_DATA(void) { - otError error = OT_ERROR_NONE; uint8_t networkData[255]; uint8_t networkDataLen = 255; @@ -774,35 +635,15 @@ otError NcpBase::GetPropertyHandler_THREAD_STABLE_LEADER_NETWORK_DATA(uint8_t aH &networkDataLen ); - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - SuccessOrExit(error = OutboundFrameFeedData(networkData, networkDataLen)); - SuccessOrExit(error = OutboundFrameSend()); - -exit: - return error; + return mEncoder.WriteData(networkData, networkDataLen); } -otError NcpBase::GetPropertyHandler_THREAD_LEADER_RID(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_LEADER_RID(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otThreadGetLeaderRouterId(mInstance) - ); + return mEncoder.WriteUint8(otThreadGetLeaderRouterId(mInstance)); } - - -otError NcpBase::GetPropertyHandler_THREAD_LEADER_ADDR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_LEADER_ADDR(void) { otError error = OT_ERROR_NONE; otIp6Address address; @@ -811,69 +652,45 @@ otError NcpBase::GetPropertyHandler_THREAD_LEADER_ADDR(uint8_t aHeader, spinel_p if (error == OT_ERROR_NONE) { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_IPv6ADDR_S, - &address - ); + error = mEncoder.WriteIp6Address(address); } else { - error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); + error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error)); } return error; } -otError NcpBase::GetPropertyHandler_THREAD_PARENT(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_PARENT(void) { otError error = OT_ERROR_NONE; + otRouterInfo parentInfo; error = otThreadGetParentInfo(mInstance, &parentInfo); if (error == OT_ERROR_NONE) { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - ( - SPINEL_DATATYPE_EUI64_S // Parent's extended address - SPINEL_DATATYPE_UINT16_S // Parent's rloc16 - ), - parentInfo.mExtAddress.m8, - parentInfo.mRloc16 - ); + SuccessOrExit(error = mEncoder.WriteEui64(parentInfo.mExtAddress)); // Parent's extended address + SuccessOrExit(error = mEncoder.WriteUint16(parentInfo.mRloc16)); } else { - error = SendLastStatus(aHeader, ThreadErrorToSpinelStatus(error)); + error = mEncoder.OverwriteWithLastStatusError(ThreadErrorToSpinelStatus(error)); } +exit: return error; } -otError NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE(void) { otError error = OT_ERROR_NONE; otNeighborInfoIterator iter = OT_NEIGHBOR_INFO_ITERATOR_INIT; otNeighborInfo neighInfo; uint8_t modeFlags; - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - while (otThreadGetNextNeighborInfo(mInstance, &iter, &neighInfo) == OT_ERROR_NONE) { modeFlags = LinkFlagsToFlagByte( @@ -883,62 +700,37 @@ otError NcpBase::GetPropertyHandler_THREAD_NEIGHBOR_TABLE(uint8_t aHeader, spine neighInfo.mFullNetworkData ); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S // EUI64 Address - SPINEL_DATATYPE_UINT16_S // Rloc16 - SPINEL_DATATYPE_UINT32_S // Age - SPINEL_DATATYPE_UINT8_S // Link Quality In - SPINEL_DATATYPE_INT8_S // Average RSS - SPINEL_DATATYPE_UINT8_S // Mode (flags) - SPINEL_DATATYPE_BOOL_S // Is Child - SPINEL_DATATYPE_UINT32_S // Link Frame Counter - SPINEL_DATATYPE_UINT32_S // MLE Frame Counter - SPINEL_DATATYPE_INT8_S // Most recent RSS - ), - neighInfo.mExtAddress.m8, - neighInfo.mRloc16, - neighInfo.mAge, - neighInfo.mLinkQualityIn, - neighInfo.mAverageRssi, - modeFlags, - neighInfo.mIsChild, - neighInfo.mLinkFrameCounter, - neighInfo.mMleFrameCounter, - neighInfo.mLastRssi - )); + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteEui64(neighInfo.mExtAddress)); + SuccessOrExit(error = mEncoder.WriteUint16(neighInfo.mRloc16)); + SuccessOrExit(error = mEncoder.WriteUint32(neighInfo.mAge)); + SuccessOrExit(error = mEncoder.WriteUint8(neighInfo.mLinkQualityIn)); + SuccessOrExit(error = mEncoder.WriteInt8(neighInfo.mAverageRssi)); + SuccessOrExit(error = mEncoder.WriteUint8(modeFlags)); + SuccessOrExit(error = mEncoder.WriteBool(neighInfo.mIsChild)); + SuccessOrExit(error = mEncoder.WriteUint32(neighInfo.mLinkFrameCounter)); + SuccessOrExit(error = mEncoder.WriteUint32(neighInfo.mMleFrameCounter)); + SuccessOrExit(error = mEncoder.WriteInt8(neighInfo.mLastRssi)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } -otError NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_ASSISTING_PORTS(void) { otError error = OT_ERROR_NONE; uint8_t numEntries = 0; const uint16_t *ports = otIp6GetUnsecurePorts(mInstance, &numEntries); - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - for (; numEntries != 0; ports++, numEntries--) { - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT16_S, *ports)); + SuccessOrExit(error = mEncoder.WriteUint16(*ports)); } - SuccessOrExit(error = OutboundFrameSend()); - exit: return error; } @@ -999,15 +791,9 @@ exit: return error; } -otError NcpBase::GetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_ALLOW_LOCAL_NET_DATA_CHANGE(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - mAllowLocalNetworkDataChange - ); + return mEncoder.WriteBool(mAllowLocalNetworkDataChange); } #if OPENTHREAD_ENABLE_BORDER_ROUTER @@ -1045,46 +831,25 @@ exit: } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS(void) { otError error = OT_ERROR_NONE; otBorderRouterConfig borderRouterConfig; otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; - uint8_t flags; - - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); // Fill from non-local network data first while (otNetDataGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig) == OT_ERROR_NONE) { - flags = BorderRouterConfigToFlagByte(borderRouterConfig); + SuccessOrExit(error = mEncoder.OpenStruct()); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix - SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits) - SPINEL_DATATYPE_BOOL_S // isStable - SPINEL_DATATYPE_UINT8_S // Flags - SPINEL_DATATYPE_BOOL_S // isLocal - SPINEL_DATATYPE_UINT16_S // RLOC16 - ), - &borderRouterConfig.mPrefix, - 64, - borderRouterConfig.mStable, - flags, - false, - borderRouterConfig.mRloc16 - )); + SuccessOrExit(error = mEncoder.WriteIp6Address(borderRouterConfig.mPrefix.mPrefix)); + SuccessOrExit(error = mEncoder.WriteUint8(borderRouterConfig.mPrefix.mLength)); + SuccessOrExit(error = mEncoder.WriteBool(borderRouterConfig.mStable)); + SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByte(borderRouterConfig))); + SuccessOrExit(error = mEncoder.WriteBool(false)); // isLocal + SuccessOrExit(error = mEncoder.WriteUint16(borderRouterConfig.mRloc16)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } #if OPENTHREAD_ENABLE_BORDER_ROUTER @@ -1094,42 +859,28 @@ otError NcpBase::GetPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_ // Fill from local network data last while (otBorderRouterGetNextOnMeshPrefix(mInstance, &iter, &borderRouterConfig) == OT_ERROR_NONE) { - flags = BorderRouterConfigToFlagByte(borderRouterConfig); + SuccessOrExit(error = mEncoder.OpenStruct()); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix - SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits) - SPINEL_DATATYPE_BOOL_S // isStable - SPINEL_DATATYPE_UINT8_S // Flags - SPINEL_DATATYPE_BOOL_S // isLocal - SPINEL_DATATYPE_UINT16_S // RLOC16 - ), - &borderRouterConfig.mPrefix, - 64, - borderRouterConfig.mStable, - flags, - true, - borderRouterConfig.mRloc16 - )); + SuccessOrExit(error = mEncoder.WriteIp6Address(borderRouterConfig.mPrefix.mPrefix)); + SuccessOrExit(error = mEncoder.WriteUint8(borderRouterConfig.mPrefix.mLength)); + SuccessOrExit(error = mEncoder.WriteBool(borderRouterConfig.mStable)); + SuccessOrExit(error = mEncoder.WriteUint8(BorderRouterConfigToFlagByte(borderRouterConfig))); + SuccessOrExit(error = mEncoder.WriteBool(true)); // isLocal + SuccessOrExit(error = mEncoder.WriteUint16(borderRouterConfig.mRloc16)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } #if OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otBorderRouterConfig borderRouterConfig; otIp6Address *addrPtr; bool stable = false; @@ -1137,7 +888,7 @@ otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spin memset(&borderRouterConfig, 0, sizeof(otBorderRouterConfig)); - VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE); + VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); parsedLength = spinel_datatype_unpack( aValuePtr, @@ -1154,7 +905,7 @@ otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spin &flags ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); borderRouterConfig.mPrefix.mPrefix = *addrPtr; borderRouterConfig.mStable = stable; @@ -1168,38 +919,21 @@ otError NcpBase::InsertPropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spin borderRouterConfig.mOnMesh = ((flags & SPINEL_NET_FLAG_ON_MESH) != 0); error = otBorderRouterAddOnMeshPrefix(mInstance, &borderRouterConfig); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otIp6Prefix ip6Prefix; otIp6Address *addrPtr; memset(&ip6Prefix, 0, sizeof(otIp6Prefix)); - VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE); + VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); parsedLength = spinel_datatype_unpack( aValuePtr, @@ -1212,46 +946,28 @@ otError NcpBase::RemovePropertyHandler_THREAD_ON_MESH_NETS(uint8_t aHeader, spin &ip6Prefix.mLength ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); ip6Prefix.mPrefix = *addrPtr; error = otBorderRouterRemoveOnMeshPrefix(mInstance, &ip6Prefix); - // If prefix was not on the list, "remove" command is successful, - // and we respond with a `SPINEL_STATUS_OK` status. - VerifyOrExit(error != OT_ERROR_NOT_FOUND, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); + // If prefix was not on the list, "remove" command can be considred + // successful. - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + if (error == OT_ERROR_NOT_FOUND) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - mDiscoveryScanJoinerFlag - ); + return mEncoder.WriteBool(mDiscoveryScanJoinerFlag); } otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_JOINER_FLAG(uint8_t aHeader, spinel_prop_key_t aKey, @@ -1276,15 +992,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - mDiscoveryScanEnableFiltering - ); + return mEncoder.WriteBool(mDiscoveryScanEnableFiltering); } otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_ENABLE_FILTERING(uint8_t aHeader, spinel_prop_key_t aKey, @@ -1310,15 +1020,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT16_S, - mDiscoveryScanPanId - ); + return mEncoder.WriteUint16(mDiscoveryScanPanId); } otError NcpBase::SetPropertyHandler_THREAD_DISCOVERY_SCAN_PANID(uint8_t aHeader, spinel_prop_key_t aKey, @@ -1343,42 +1047,23 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_IPV6_ML_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_IPV6_ML_PREFIX(void) { otError error = OT_ERROR_NONE; const uint8_t *mlPrefix = otThreadGetMeshLocalPrefix(mInstance); + otIp6Address addr; - if (mlPrefix) - { - otIp6Address addr; + VerifyOrExit(mlPrefix != NULL); // If `mlPrefix` is NULL send empty response. - memcpy(addr.mFields.m8, mlPrefix, 8); + memcpy(addr.mFields.m8, mlPrefix, 8); - // Zero out the last 8 bytes. - memset(addr.mFields.m8 + 8, 0, 8); + // Zero out the last 8 bytes. + memset(addr.mFields.m8 + 8, 0, 8); - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - ( - SPINEL_DATATYPE_IPv6ADDR_S // Mesh-local IPv6 address - SPINEL_DATATYPE_UINT8_S // Prefix length (in bits) - ), - &addr, - 64 - ); - } - else - { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_VOID_S - ); - } + SuccessOrExit(error = mEncoder.WriteIp6Address(addr)); // Mesh local prefix + SuccessOrExit(error = mEncoder.WriteUint8(64)); // Prefix length (in bits) +exit: return error; } @@ -1395,108 +1080,54 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_IPV6_ML_ADDR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_IPV6_ML_ADDR(void) { otError error = OT_ERROR_NONE; const otIp6Address *ml64 = otThreadGetMeshLocalEid(mInstance); - if (ml64) - { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_IPv6ADDR_S, - ml64 - ); - } - else - { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_VOID_S - ); - } + VerifyOrExit(ml64 != NULL); + SuccessOrExit(error = mEncoder.WriteIp6Address(*ml64)); +exit: return error; } -otError NcpBase::GetPropertyHandler_IPV6_LL_ADDR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_IPV6_LL_ADDR(void) { otError error = OT_ERROR_NONE; const otIp6Address *address = otThreadGetLinkLocalIp6Address(mInstance); - if (address) - { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_IPv6ADDR_S, - address - ); - } - else - { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_VOID_S - ); - } + VerifyOrExit(address != NULL); + SuccessOrExit(error = mEncoder.WriteIp6Address(*address)); +exit: return error; } -otError NcpBase::GetPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_IPV6_ADDRESS_TABLE(void) { otError error = OT_ERROR_NONE; - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - for (const otNetifAddress *address = otIp6GetUnicastAddresses(mInstance); address; address = address->mNext) { + SuccessOrExit(error = mEncoder.OpenStruct()); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address - SPINEL_DATATYPE_UINT8_S // Prefix length (in bits) - SPINEL_DATATYPE_UINT32_S // Preferred lifetime - SPINEL_DATATYPE_UINT32_S // Valid lifetime - ), - &address->mAddress, - address->mPrefixLength, - address->mPreferred ? 0xffffffff : 0, - address->mValid ? 0xffffffff : 0 - )); + SuccessOrExit(error = mEncoder.WriteIp6Address(address->mAddress)); + SuccessOrExit(error = mEncoder.WriteUint8(address->mPrefixLength)); + SuccessOrExit(error = mEncoder.WriteUint32(address->mPreferred ? 0xffffffff : 0)); + SuccessOrExit(error = mEncoder.WriteUint32(address->mValid ? 0xffffffff : 0)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } -otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otNetifAddress netifAddr; otIp6Address *addrPtr; uint32_t preferredLifetime; @@ -1518,7 +1149,7 @@ otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spine &validLifetime ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); netifAddr.mAddress = *addrPtr; netifAddr.mPrefixLength = prefixLen; @@ -1527,34 +1158,14 @@ otError NcpBase::InsertPropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spine error = otIp6AddUnicastAddress(mInstance, &netifAddr); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); - - spinelError = SPINEL_STATUS_OK; - exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otIp6Address *addrPtr; parsedLength = spinel_datatype_unpack( @@ -1564,51 +1175,29 @@ otError NcpBase::RemovePropertyHandler_IPV6_ADDRESS_TABLE(uint8_t aHeader, spine &addrPtr ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otIp6RemoveUnicastAddress(mInstance, addrPtr); - // If address was not on the list, "remove" command is successful, - // and we respond with a `SPINEL_STATUS_OK` status. - VerifyOrExit(error != OT_ERROR_NOT_FOUND, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + // If address was not on the list, "remove" command is successful. + if (error == OT_ERROR_NOT_FOUND) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } -otError NcpBase::GetPropertyHandler_IPV6_ROUTE_TABLE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_IPV6_ROUTE_TABLE(void) { // TODO: Implement get route table - OT_UNUSED_VARIABLE(aKey); - - return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED); + return mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_UNIMPLEMENTED); } -otError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - otIcmp6IsEchoEnabled(mInstance) - ); + return mEncoder.WriteBool(otIcmp6IsEchoEnabled(mInstance)); } otError NcpBase::SetPropertyHandler_IPV6_ICMP_PING_OFFLOAD(uint8_t aHeader, spinel_prop_key_t aKey, @@ -1633,46 +1222,26 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(void) { otError error = OT_ERROR_NONE; const otNetifMulticastAddress *address; - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - for (address = otIp6GetMulticastAddresses(mInstance); address; address = address->mNext) { - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_IPv6ADDR_S // IPv6 address - ), - &address->mAddress - )); + SuccessOrExit(error = mEncoder.OpenStruct()); + SuccessOrExit(error = mEncoder.WriteIp6Address(address->mAddress)); + SuccessOrExit(error = mEncoder.CloseStruct()); } - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } -otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otIp6Address *addrPtr; parsedLength = spinel_datatype_unpack( @@ -1682,40 +1251,23 @@ otError NcpBase::InsertPropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHea &addrPtr ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otIp6SubscribeMulticastAddress(mInstance, addrPtr); - VerifyOrExit(error != OT_ERROR_ALREADY, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); - - spinelError = SPINEL_STATUS_OK; - -exit: - - if (spinelError != SPINEL_STATUS_OK) + if (error == OT_ERROR_ALREADY) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } -otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otIp6Address *addrPtr; parsedLength = spinel_datatype_unpack( @@ -1725,44 +1277,25 @@ otError NcpBase::RemovePropertyHandler_IPV6_MULTICAST_ADDRESS_TABLE(uint8_t aHea &addrPtr ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otIp6UnsubscribeMulticastAddress(mInstance, addrPtr); // If the address was not on the list, "remove" command is successful, // and we respond with a `SPINEL_STATUS_OK` status. - VerifyOrExit(error != OT_ERROR_NOT_FOUND, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + if (error == OT_ERROR_NOT_FOUND) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } -otError NcpBase::GetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(void) { // Note reverse logic: passthru enabled = filter disabled - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - !otIp6IsReceiveFilterEnabled(mInstance) - ); + return mEncoder.WriteBool(!otIp6IsReceiveFilterEnabled(mInstance)); } otError NcpBase::SetPropertyHandler_THREAD_RLOC16_DEBUG_PASSTHRU(uint8_t aHeader, spinel_prop_key_t aKey, @@ -1788,78 +1321,48 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_OFF_MESH_ROUTES(void) { otError error = OT_ERROR_NONE; - otExternalRouteConfig external_route_config; + otExternalRouteConfig routeConfig; otNetworkDataIterator iter = OT_NETWORK_DATA_ITERATOR_INIT; - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - - while (otNetDataGetNextRoute(mInstance, &iter, &external_route_config) == OT_ERROR_NONE) + while (otNetDataGetNextRoute(mInstance, &iter, &routeConfig) == OT_ERROR_NONE) { - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix - SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits) - SPINEL_DATATYPE_BOOL_S // IsStable - SPINEL_DATATYPE_UINT8_S // Route Preference Flags - SPINEL_DATATYPE_BOOL_S // IsLocal - SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice - SPINEL_DATATYPE_UINT16_S // RLOC16 - ), - &external_route_config.mPrefix.mPrefix, - external_route_config.mPrefix.mLength, - external_route_config.mStable, - ExternalRoutePreferenceToFlagByte(external_route_config.mPreference), - false, - external_route_config.mNextHopIsThisDevice, - external_route_config.mRloc16 - )); + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteIp6Address(routeConfig.mPrefix.mPrefix)); + SuccessOrExit(error = mEncoder.WriteUint8(routeConfig.mPrefix.mLength)); + SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mStable)); + SuccessOrExit(error = mEncoder.WriteUint8(ExternalRoutePreferenceToFlagByte(routeConfig.mPreference))); + SuccessOrExit(error = mEncoder.WriteBool(false)); // IsLocal + SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mNextHopIsThisDevice)); + SuccessOrExit(error = mEncoder.WriteUint16(routeConfig.mRloc16)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } #if OPENTHREAD_ENABLE_BORDER_ROUTER iter = OT_NETWORK_DATA_ITERATOR_INIT; - while (otBorderRouterGetNextRoute(mInstance, &iter, &external_route_config) == OT_ERROR_NONE) + while (otBorderRouterGetNextRoute(mInstance, &iter, &routeConfig) == OT_ERROR_NONE) { - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_IPv6ADDR_S // IPv6 Prefix - SPINEL_DATATYPE_UINT8_S // Prefix Length (in bits) - SPINEL_DATATYPE_BOOL_S // IsStable - SPINEL_DATATYPE_UINT8_S // Route Preference Flags - SPINEL_DATATYPE_BOOL_S // IsLocal - SPINEL_DATATYPE_BOOL_S // NextHopIsThisDevice - SPINEL_DATATYPE_UINT16_S // RLOC16 - ), - &external_route_config.mPrefix.mPrefix, - external_route_config.mPrefix.mLength, - external_route_config.mStable, - ExternalRoutePreferenceToFlagByte(external_route_config.mPreference), - true, - external_route_config.mNextHopIsThisDevice, - external_route_config.mRloc16 - )); + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteIp6Address(routeConfig.mPrefix.mPrefix)); + SuccessOrExit(error = mEncoder.WriteUint8(routeConfig.mPrefix.mLength)); + SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mStable)); + SuccessOrExit(error = mEncoder.WriteUint8(ExternalRoutePreferenceToFlagByte(routeConfig.mPreference))); + SuccessOrExit(error = mEncoder.WriteBool(true)); // IsLocal + SuccessOrExit(error = mEncoder.WriteBool(routeConfig.mNextHopIsThisDevice)); + SuccessOrExit(error = mEncoder.WriteUint16(routeConfig.mRloc16)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } @@ -1886,12 +1389,10 @@ static int FlagByteToExternalRoutePreference(uint8_t aFlags) return route_preference; } -otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExternalRouteConfig routeConfig; otIp6Address *addrPtr; bool stable = false; @@ -1899,7 +1400,7 @@ otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, s memset(&routeConfig, 0, sizeof(otExternalRouteConfig)); - VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE); + VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); parsedLength = spinel_datatype_unpack( aValuePtr, @@ -1916,45 +1417,28 @@ otError NcpBase::InsertPropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, s &flags ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); routeConfig.mPrefix.mPrefix = *addrPtr; routeConfig.mStable = stable; routeConfig.mPreference = FlagByteToExternalRoutePreference(flags); error = otBorderRouterAddRoute(mInstance, &routeConfig); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otIp6Prefix ip6Prefix; otIp6Address *addrPtr; memset(&ip6Prefix, 0, sizeof(otIp6Prefix)); - VerifyOrExit(mAllowLocalNetworkDataChange == true, spinelError = SPINEL_STATUS_INVALID_STATE); + VerifyOrExit(mAllowLocalNetworkDataChange == true, error = OT_ERROR_INVALID_STATE); parsedLength = spinel_datatype_unpack( aValuePtr, @@ -1967,43 +1451,27 @@ otError NcpBase::RemovePropertyHandler_THREAD_OFF_MESH_ROUTES(uint8_t aHeader, s &ip6Prefix.mLength ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); ip6Prefix.mPrefix = *addrPtr; error = otBorderRouterRemoveRoute(mInstance, &ip6Prefix); - // If the route prefix was not on the list, "remove" command is successful, - // and we respond with a `SPINEL_STATUS_OK` status. - VerifyOrExit(error != OT_ERROR_NOT_FOUND, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + // If the route prefix was not on the list, "remove" command is successful. + if (error == OT_ERROR_NOT_FOUND) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } #endif // OPENTHREAD_ENABLE_BORDER_ROUTER -otError NcpBase::GetPropertyHandler_STREAM_NET(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_STREAM_NET(void) { // TODO: Implement explicit data poll. - OT_UNUSED_VARIABLE(aKey); - - return SendLastStatus(aHeader, SPINEL_STATUS_UNIMPLEMENTED); + return mEncoder.OverwriteWithLastStatusError(SPINEL_STATUS_UNIMPLEMENTED); } otError NcpBase::SetPropertyHandler_STREAM_NET(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -2081,76 +1549,44 @@ exit: #if OPENTHREAD_ENABLE_JAM_DETECTION -otError NcpBase::GetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_JAM_DETECT_ENABLE(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - otJamDetectionIsEnabled(mInstance) - ); + return mEncoder.WriteBool(otJamDetectionIsEnabled(mInstance)); } -otError NcpBase::GetPropertyHandler_JAM_DETECTED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_JAM_DETECTED(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - otJamDetectionGetState(mInstance) - ); + return mEncoder.WriteBool(otJamDetectionGetState(mInstance)); } -otError NcpBase::GetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_JAM_DETECT_RSSI_THRESHOLD(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_INT8_S, - otJamDetectionGetRssiThreshold(mInstance) - ); + return mEncoder.WriteInt8(otJamDetectionGetRssiThreshold(mInstance)); } -otError NcpBase::GetPropertyHandler_JAM_DETECT_WINDOW(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_JAM_DETECT_WINDOW(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otJamDetectionGetWindow(mInstance) - ); + return mEncoder.WriteUint8(otJamDetectionGetWindow(mInstance)); } -otError NcpBase::GetPropertyHandler_JAM_DETECT_BUSY(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_JAM_DETECT_BUSY(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - otJamDetectionGetBusyPeriod(mInstance) - ); + return mEncoder.WriteUint8(otJamDetectionGetBusyPeriod(mInstance)); } -otError NcpBase::GetPropertyHandler_JAM_DETECT_HISTORY_BITMAP(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_JAM_DETECT_HISTORY_BITMAP(void) { + otError error = OT_ERROR_NONE; uint64_t historyBitmap = otJamDetectionGetHistoryBitmap(mInstance); - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - ( - SPINEL_DATATYPE_UINT32_S // History bitmap - bits 0-31 - SPINEL_DATATYPE_UINT32_S // History bitmap - bits 32-63 - ), - static_cast(historyBitmap & 0xffffffff), - static_cast(historyBitmap >> 32) - ); + // History bitmap - bits 0-31 + SuccessOrExit(error = mEncoder.WriteUint32(static_cast(historyBitmap & 0xffffffff))); + + // // History bitmap - bits 32-63 + SuccessOrExit(error = mEncoder.WriteUint32(static_cast(historyBitmap >> 32))); + +exit: + return error; } otError NcpBase::SetPropertyHandler_JAM_DETECT_ENABLE(uint8_t aHeader, spinel_prop_key_t aKey, @@ -2263,321 +1699,254 @@ void NcpBase::HandleJamStateChange(bool aJamState) #endif // OPENTHREAD_ENABLE_JAM_DETECTION -otError NcpBase::GetPropertyHandler_MAC_CNTR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_TOTAL(void) { - uint32_t value; - const otMacCounters *macCounters; - otError error = OT_ERROR_NONE; - - macCounters = otLinkGetCounters(mInstance); - - assert(macCounters != NULL); - - switch (aKey) - { - case SPINEL_PROP_CNTR_TX_PKT_TOTAL: - value = macCounters->mTxTotal; - break; - - case SPINEL_PROP_CNTR_TX_PKT_ACK_REQ: - value = macCounters->mTxAckRequested; - break; - - case SPINEL_PROP_CNTR_TX_PKT_ACKED: - value = macCounters->mTxAcked; - break; - - case SPINEL_PROP_CNTR_TX_PKT_NO_ACK_REQ: - value = macCounters->mTxNoAckRequested; - break; - - case SPINEL_PROP_CNTR_TX_PKT_DATA: - value = macCounters->mTxData; - break; - - case SPINEL_PROP_CNTR_TX_PKT_DATA_POLL: - value = macCounters->mTxDataPoll; - break; - - case SPINEL_PROP_CNTR_TX_PKT_BEACON: - value = macCounters->mTxBeacon; - break; - - case SPINEL_PROP_CNTR_TX_PKT_BEACON_REQ: - value = macCounters->mTxBeaconRequest; - break; - - case SPINEL_PROP_CNTR_TX_PKT_OTHER: - value = macCounters->mTxOther; - break; - - case SPINEL_PROP_CNTR_TX_PKT_RETRY: - value = macCounters->mTxRetry; - break; - - case SPINEL_PROP_CNTR_TX_ERR_CCA: - value = macCounters->mTxErrCca; - break; - - case SPINEL_PROP_CNTR_TX_PKT_UNICAST: - value = macCounters->mTxUnicast; - break; - - case SPINEL_PROP_CNTR_TX_PKT_BROADCAST: - value = macCounters->mTxBroadcast; - break; - - case SPINEL_PROP_CNTR_TX_ERR_ABORT: - value = macCounters->mTxErrAbort; - break; - - case SPINEL_PROP_CNTR_RX_PKT_TOTAL: - value = macCounters->mRxTotal; - break; - - case SPINEL_PROP_CNTR_RX_PKT_DATA: - value = macCounters->mRxData; - break; - - case SPINEL_PROP_CNTR_RX_PKT_DATA_POLL: - value = macCounters->mRxDataPoll; - break; - - case SPINEL_PROP_CNTR_RX_PKT_BEACON: - value = macCounters->mRxBeacon; - break; - - case SPINEL_PROP_CNTR_RX_PKT_BEACON_REQ: - value = macCounters->mRxBeaconRequest; - break; - - case SPINEL_PROP_CNTR_RX_PKT_OTHER: - value = macCounters->mRxOther; - break; - - case SPINEL_PROP_CNTR_RX_PKT_FILT_WL: - value = macCounters->mRxWhitelistFiltered; - break; - - case SPINEL_PROP_CNTR_RX_PKT_FILT_DA: - value = macCounters->mRxDestAddrFiltered; - break; - - case SPINEL_PROP_CNTR_RX_PKT_DUP: - value = macCounters->mRxDuplicated; - break; - - case SPINEL_PROP_CNTR_RX_PKT_UNICAST: - value = macCounters->mRxUnicast; - break; - - case SPINEL_PROP_CNTR_RX_PKT_BROADCAST: - value = macCounters->mRxBroadcast; - break; - - case SPINEL_PROP_CNTR_RX_ERR_EMPTY: - value = macCounters->mRxErrNoFrame; - break; - - case SPINEL_PROP_CNTR_RX_ERR_UKWN_NBR: - value = macCounters->mRxErrUnknownNeighbor; - break; - - case SPINEL_PROP_CNTR_RX_ERR_NVLD_SADDR: - value = macCounters->mRxErrInvalidSrcAddr; - break; - - case SPINEL_PROP_CNTR_RX_ERR_SECURITY: - value = macCounters->mRxErrSec; - break; - - case SPINEL_PROP_CNTR_RX_ERR_BAD_FCS: - value = macCounters->mRxErrFcs; - break; - - case SPINEL_PROP_CNTR_RX_ERR_OTHER: - value = macCounters->mRxErrOther; - break; - - default: - error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR); - ExitNow(); - } - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - value - ); - -exit: - return error; + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxTotal); } -otError NcpBase::GetPropertyHandler_NCP_CNTR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_ACK_REQ(void) { - uint32_t value; - otError error = OT_ERROR_NONE; - - switch (aKey) - { - case SPINEL_PROP_CNTR_TX_IP_SEC_TOTAL: - value = mInboundSecureIpFrameCounter; - break; - - case SPINEL_PROP_CNTR_TX_IP_INSEC_TOTAL: - value = mInboundInsecureIpFrameCounter; - break; - - case SPINEL_PROP_CNTR_TX_IP_DROPPED: - value = mDroppedInboundIpFrameCounter; - break; - - case SPINEL_PROP_CNTR_RX_IP_SEC_TOTAL: - value = mOutboundSecureIpFrameCounter; - break; - - case SPINEL_PROP_CNTR_RX_IP_INSEC_TOTAL: - value = mOutboundInsecureIpFrameCounter; - break; - - case SPINEL_PROP_CNTR_RX_IP_DROPPED: - value = mDroppedOutboundIpFrameCounter; - break; - - case SPINEL_PROP_CNTR_TX_SPINEL_TOTAL: - value = mTxSpinelFrameCounter; - break; - - case SPINEL_PROP_CNTR_RX_SPINEL_TOTAL: - value = mRxSpinelFrameCounter; - break; - - case SPINEL_PROP_CNTR_RX_SPINEL_OUT_OF_ORDER_TID: - value = mRxSpinelOutOfOrderTidCounter; - break; - - case SPINEL_PROP_CNTR_RX_SPINEL_ERR: - value = mFramingErrorCounter; - break; - - default: - error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR); - ExitNow(); - } - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - value - ); - -exit: - return error; + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxAckRequested); } -otError NcpBase::GetPropertyHandler_IP_CNTR(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_ACKED(void) { - uint32_t value; - otError error = OT_ERROR_NONE; - - const otIpCounters *counters = otThreadGetIp6Counters(mInstance); - - switch (aKey) - { - case SPINEL_PROP_CNTR_IP_TX_SUCCESS: - value = counters->mTxSuccess; - break; - - case SPINEL_PROP_CNTR_IP_RX_SUCCESS: - value = counters->mRxSuccess; - break; - - case SPINEL_PROP_CNTR_IP_TX_FAILURE: - value = counters->mTxFailure; - break; - - case SPINEL_PROP_CNTR_IP_RX_FAILURE: - value = counters->mRxFailure; - break; - - default: - error = SendLastStatus(aHeader, SPINEL_STATUS_INTERNAL_ERROR); - ExitNow(); - break; - } - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - value - ); - -exit: - return error; + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxAcked); } -otError NcpBase::GetPropertyHandler_MSG_BUFFER_COUNTERS(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_NO_ACK_REQ(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxNoAckRequested); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_DATA(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxData); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_DATA_POLL(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxDataPoll); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_BEACON(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBeacon); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_BEACON_REQ(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBeaconRequest); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_OTHER(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxOther); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_RETRY(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxRetry); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_ERR_CCA(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxErrCca); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_UNICAST(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxUnicast); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_PKT_BROADCAST(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxBroadcast); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_ERR_ABORT(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mTxErrAbort); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_TOTAL(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxTotal); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_DATA(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxData); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_DATA_POLL(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDataPoll); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_BEACON(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBeacon); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_BEACON_REQ(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBeaconRequest); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_OTHER(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxOther); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_FILT_WL(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxWhitelistFiltered); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_FILT_DA(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDestAddrFiltered); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_DUP(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxDuplicated); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_UNICAST(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxUnicast); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_PKT_BROADCAST(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxBroadcast); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_ERR_EMPTY(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrNoFrame); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_ERR_UKWN_NBR(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrUnknownNeighbor); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_ERR_NVLD_SADDR(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrInvalidSrcAddr); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_ERR_SECURITY(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrSec); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_ERR_BAD_FCS(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrFcs); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_ERR_OTHER(void) +{ + return mEncoder.WriteUint32(otLinkGetCounters(mInstance)->mRxErrOther); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_IP_SEC_TOTAL(void) +{ + return mEncoder.WriteUint32(mInboundSecureIpFrameCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_IP_INSEC_TOTAL(void) +{ + return mEncoder.WriteUint32(mInboundInsecureIpFrameCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_IP_DROPPED(void) +{ + return mEncoder.WriteUint32(mDroppedInboundIpFrameCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_IP_SEC_TOTAL(void) +{ + return mEncoder.WriteUint32(mOutboundSecureIpFrameCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_IP_INSEC_TOTAL(void) +{ + return mEncoder.WriteUint32(mOutboundInsecureIpFrameCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_IP_DROPPED(void) +{ + return mEncoder.WriteUint32(mDroppedOutboundIpFrameCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_TX_SPINEL_TOTAL(void) +{ + return mEncoder.WriteUint32(mTxSpinelFrameCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_SPINEL_TOTAL(void) +{ + return mEncoder.WriteUint32(mRxSpinelFrameCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_SPINEL_OUT_OF_ORDER_TID(void) +{ + return mEncoder.WriteUint32(mRxSpinelOutOfOrderTidCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_RX_SPINEL_ERR(void) +{ + return mEncoder.WriteUint32(mFramingErrorCounter); +} + +otError NcpBase::GetPropertyHandler_CNTR_IP_TX_SUCCESS(void) +{ + return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mTxSuccess); +} + +otError NcpBase::GetPropertyHandler_CNTR_IP_RX_SUCCESS(void) +{ + return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mRxSuccess); +} + +otError NcpBase::GetPropertyHandler_CNTR_IP_TX_FAILURE(void) +{ + return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mTxFailure); +} + +otError NcpBase::GetPropertyHandler_CNTR_IP_RX_FAILURE(void) +{ + return mEncoder.WriteUint32(otThreadGetIp6Counters(mInstance)->mRxFailure); +} + +otError NcpBase::GetPropertyHandler_MSG_BUFFER_COUNTERS(void) { otError error = OT_ERROR_NONE; otBufferInfo bufferInfo; otMessageGetBufferInfo(mInstance, &bufferInfo); - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - - SuccessOrExit( - error = OutboundFrameFeedPacked( - ( - SPINEL_DATATYPE_UINT16_S // Total buffers - SPINEL_DATATYPE_UINT16_S // Free buffers - SPINEL_DATATYPE_UINT16_S // Lowpan send messages - SPINEL_DATATYPE_UINT16_S // Lowpan send buffers - SPINEL_DATATYPE_UINT16_S // Lowpan reassembly messages - SPINEL_DATATYPE_UINT16_S // Lowpan reassembly buffers - SPINEL_DATATYPE_UINT16_S // Ip6 messages - SPINEL_DATATYPE_UINT16_S // Ip6 buffers - SPINEL_DATATYPE_UINT16_S // Mpl messages - SPINEL_DATATYPE_UINT16_S // Mpl buffers - SPINEL_DATATYPE_UINT16_S // Mle messages - SPINEL_DATATYPE_UINT16_S // Mle buffers - SPINEL_DATATYPE_UINT16_S // Arp messages - SPINEL_DATATYPE_UINT16_S // Arp buffers - SPINEL_DATATYPE_UINT16_S // Coap messages - SPINEL_DATATYPE_UINT16_S // Coap buffers - ), - bufferInfo.mTotalBuffers, - bufferInfo.mFreeBuffers, - bufferInfo.m6loSendMessages, - bufferInfo.m6loSendBuffers, - bufferInfo.m6loReassemblyMessages, - bufferInfo.m6loReassemblyBuffers, - bufferInfo.mIp6Messages, - bufferInfo.mIp6Buffers, - bufferInfo.mMplMessages, - bufferInfo.mMplBuffers, - bufferInfo.mMleMessages, - bufferInfo.mMleBuffers, - bufferInfo.mArpMessages, - bufferInfo.mArpBuffers, - bufferInfo.mCoapMessages, - bufferInfo.mCoapBuffers - )); - - SuccessOrExit(error = OutboundFrameSend()); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mTotalBuffers)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mFreeBuffers)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.m6loSendMessages)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.m6loSendBuffers)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.m6loReassemblyMessages)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.m6loReassemblyBuffers)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mIp6Messages)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mIp6Buffers)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mMplMessages)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mMplBuffers)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mMleMessages)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mMleBuffers)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mArpMessages)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mArpBuffers)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mCoapMessages)); + SuccessOrExit(mEncoder.WriteUint16(bufferInfo.mCoapBuffers)); exit: return error; @@ -2585,140 +1954,70 @@ exit: #if OPENTHREAD_ENABLE_MAC_FILTER -otError NcpBase::GetPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_WHITELIST(void) { otMacFilterEntry entry; otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT; otError error = OT_ERROR_NONE; - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE) { - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S // Extended address - SPINEL_DATATYPE_INT8_S // Rss - ), - entry.mExtAddress.m8, - entry.mRssIn - )); + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress)); + SuccessOrExit(error = mEncoder.WriteInt8(entry.mRssIn)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } -otError NcpBase::GetPropertyHandler_MAC_WHITELIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_WHITELIST_ENABLED(void) { - otMacFilterAddressMode mode = otLinkFilterGetAddressMode(mInstance); - bool isEnabled = (mode == OT_MAC_FILTER_ADDRESS_MODE_WHITELIST) ? true : false; - - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - isEnabled - ); + return mEncoder.WriteBool(otLinkFilterGetAddressMode(mInstance) == OT_MAC_FILTER_ADDRESS_MODE_WHITELIST); } -otError NcpBase::GetPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_BLACKLIST(void) { otMacFilterEntry entry; otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT; otError error = OT_ERROR_NONE; - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - while (otLinkFilterGetNextAddress(mInstance, &iterator, &entry) == OT_ERROR_NONE) { - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S // Extended address - ), - entry.mExtAddress.m8 - )); + SuccessOrExit(error = mEncoder.OpenStruct()); + SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress)); + SuccessOrExit(error = mEncoder.CloseStruct()); } - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } -otError NcpBase::GetPropertyHandler_MAC_BLACKLIST_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_BLACKLIST_ENABLED(void) { - otMacFilterAddressMode mode = otLinkFilterGetAddressMode(mInstance); - bool isEnabled = (mode == OT_MAC_FILTER_ADDRESS_MODE_BLACKLIST) ? true : false; - - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - isEnabled - ); + return mEncoder.WriteBool(otLinkFilterGetAddressMode(mInstance) == OT_MAC_FILTER_ADDRESS_MODE_BLACKLIST); } -otError NcpBase::GetPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_FIXED_RSS(void) { otMacFilterEntry entry; otMacFilterIterator iterator = OT_MAC_FILTER_ITERATOR_INIT; otError error = OT_ERROR_NONE; - mDisableStreamWrite = true; - - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - while (otLinkFilterGetNextRssIn(mInstance, &iterator, &entry) == OT_ERROR_NONE) { - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_STRUCT_S( - SPINEL_DATATYPE_EUI64_S // Extended address - SPINEL_DATATYPE_INT8_S // Rss - ), - entry.mExtAddress.m8, - entry.mRssIn - )); + SuccessOrExit(error = mEncoder.OpenStruct()); + + SuccessOrExit(error = mEncoder.WriteEui64(entry.mExtAddress)); + SuccessOrExit(error = mEncoder.WriteInt8(entry.mRssIn)); + + SuccessOrExit(error = mEncoder.CloseStruct()); } - SuccessOrExit(error = OutboundFrameSend()); - exit: - mDisableStreamWrite = false; return error; } @@ -2964,7 +2263,7 @@ exit: } #endif // OPENTHREAD_ENABLE_MAC_FILTER -otError NcpBase::GetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_MODE(void) { uint8_t numericMode; otLinkModeConfig modeConfig = otThreadGetLinkMode(mInstance); @@ -2976,13 +2275,7 @@ otError NcpBase::GetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key modeConfig.mNetworkData ); - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - numericMode - ); + return mEncoder.WriteUint8(numericMode); } otError NcpBase::SetPropertyHandler_THREAD_MODE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -3014,38 +2307,19 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } - -otError NcpBase::GetPropertyHandler_THREAD_CHILD_TIMEOUT(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_CHILD_TIMEOUT(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT32_S, - otThreadGetChildTimeout(mInstance) - ); + return mEncoder.WriteUint32(otThreadGetChildTimeout(mInstance)); } -otError NcpBase::GetPropertyHandler_THREAD_RLOC16(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_THREAD_RLOC16(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT16_S, - otThreadGetRloc16(mInstance) - ); + return mEncoder.WriteUint16(otThreadGetRloc16(mInstance)); } -otError NcpBase::GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_BOOL_S, - mRequireJoinExistingNetwork - ); + return mEncoder.WriteBool(mRequireJoinExistingNetwork); } otError NcpBase::SetPropertyHandler_NET_REQUIRE_JOIN_EXISTING(uint8_t aHeader, spinel_prop_key_t aKey, @@ -3186,6 +2460,7 @@ otError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader, spinel_prop char *output = NULL; spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; + spinel_status_t spinelError = SPINEL_STATUS_OK; parsedLength = spinel_datatype_unpack( aValuePtr, @@ -3194,56 +2469,16 @@ otError NcpBase::SetPropertyHandler_NEST_STREAM_MFG(uint8_t aHeader, spinel_prop &string ); - if ((parsedLength > 0) && (string != NULL)) - { - // all diagnostics related features are processed within diagnostics module - output = otDiagProcessCmdLine(string); - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - reinterpret_cast(output), - static_cast(strlen(output) + 1) - ); - } - else - { - error = SendLastStatus(aHeader, SPINEL_STATUS_PARSE_ERROR); - } - return error; -} + VerifyOrExit((parsedLength > 0) && (string != NULL), spinelError = SPINEL_STATUS_PARSE_ERROR); -#endif // OPENTHREAD_ENABLE_DIAG + // All diagnostics related features are processed within diagnostics module + output = otDiagProcessCmdLine(string); -otError NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) -{ - spinel_ssize_t parsedLength; - otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; - uint16_t port; - - parsedLength = spinel_datatype_unpack( - aValuePtr, - aValueLen, - SPINEL_DATATYPE_UINT16_S, - &port - ); - - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); - - error = otIp6AddUnsecurePort(mInstance, port); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + SuccessOrExit(error = mEncoder.WriteUtf8(output)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: @@ -3255,14 +2490,34 @@ exit: return error; } -#if OPENTHREAD_ENABLE_MAC_FILTER +#endif // OPENTHREAD_ENABLE_DIAG -otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_THREAD_ASSISTING_PORTS(const uint8_t *aValuePtr, uint16_t aValueLen) +{ + spinel_ssize_t parsedLength; + otError error = OT_ERROR_NONE; + uint16_t port; + + parsedLength = spinel_datatype_unpack( + aValuePtr, + aValueLen, + SPINEL_DATATYPE_UINT16_S, + &port + ); + + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); + + error = otIp6AddUnsecurePort(mInstance, port); +exit: + return error; +} + +#if OPENTHREAD_ENABLE_MAC_FILTER + +otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress = NULL; int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED; @@ -3286,42 +2541,30 @@ otError NcpBase::InsertPropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_pro ); } - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkFilterAddAddress(mInstance, extAddress); - VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY, spinelError = ThreadErrorToSpinelStatus(error)); + if (error == OT_ERROR_ALREADY) + { + error = OT_ERROR_NONE; + } + + SuccessOrExit(error); if (rss != OT_MAC_FILTER_FIXED_RSS_DISABLED) { error = otLinkFilterAddRssIn(mInstance, extAddress, rss); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); } - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); - exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress = NULL; parsedLength = spinel_datatype_unpack( @@ -3331,36 +2574,23 @@ otError NcpBase::InsertPropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_pro &extAddress ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkFilterAddAddress(mInstance, extAddress); - VerifyOrExit(error == OT_ERROR_NONE || error == OT_ERROR_ALREADY, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + if (error == OT_ERROR_ALREADY) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } -otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress = NULL; int8_t rss = OT_MAC_FILTER_FIXED_RSS_DISABLED; @@ -3384,38 +2614,20 @@ otError NcpBase::InsertPropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_pro ); } - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkFilterAddRssIn(mInstance, extAddress, rss); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); - exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } #endif // OPENTHREAD_ENABLE_MAC_FILTER -otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; uint16_t port; parsedLength = spinel_datatype_unpack( @@ -3425,42 +2637,26 @@ otError NcpBase::RemovePropertyHandler_THREAD_ASSISTING_PORTS(uint8_t aHeader, s &port ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otIp6RemoveUnsecurePort(mInstance, port); - // If unsecure port was not on the list, "remove" command is successful, - // and we respond with a `SPINEL_STATUS_OK` status. - VerifyOrExit(error != OT_ERROR_NOT_FOUND, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + // If unsecure port was not on the list, "remove" command is successful. + if (error == OT_ERROR_NOT_FOUND) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } #if OPENTHREAD_ENABLE_MAC_FILTER -otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress = NULL; parsedLength = spinel_datatype_unpack( @@ -3470,38 +2666,23 @@ otError NcpBase::RemovePropertyHandler_MAC_WHITELIST(uint8_t aHeader, spinel_pro &extAddress ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkFilterRemoveAddress(mInstance, extAddress); - VerifyOrExit(error != OT_ERROR_NOT_FOUND, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + if (error == OT_ERROR_NOT_FOUND) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } -otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress = NULL; parsedLength = spinel_datatype_unpack( @@ -3511,38 +2692,23 @@ otError NcpBase::RemovePropertyHandler_MAC_BLACKLIST(uint8_t aHeader, spinel_pro &extAddress ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkFilterRemoveAddress(mInstance, extAddress); - VerifyOrExit(error != OT_ERROR_NOT_FOUND, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + if (error == OT_ERROR_NOT_FOUND) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } -otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress = NULL; if (aValueLen > 0) @@ -3554,30 +2720,17 @@ otError NcpBase::RemovePropertyHandler_MAC_FIXED_RSS(uint8_t aHeader, spinel_pro &extAddress ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); } error = otLinkFilterRemoveRssIn(mInstance, extAddress); - VerifyOrExit(error != OT_ERROR_NOT_FOUND, error = SendLastStatus(aHeader, SPINEL_STATUS_OK)); - - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); - -exit: - - if (spinelError != SPINEL_STATUS_OK) + if (error == OT_ERROR_NOT_FOUND) { - error = SendLastStatus(aHeader, spinelError); + error = OT_ERROR_NONE; } +exit: return error; } @@ -3636,16 +2789,9 @@ void NcpBase::HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr) #endif // OPENTHREAD_ENABLE_LEGACY #if OPENTHREAD_ENABLE_LEGACY -otError NcpBase::GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NEST_LEGACY_ULA_PREFIX(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_DATA_S, - mLegacyUlaPrefix, - sizeof(mLegacyUlaPrefix) - ); + return mEncoder.WriteData(mLegacyUlaPrefix, sizeof(mLegacyUlaPrefix)); } otError NcpBase::SetPropertyHandler_NEST_LEGACY_ULA_PREFIX(uint8_t aHeader, spinel_prop_key_t aKey, @@ -3678,55 +2824,38 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_NEST_LEGACY_LAST_NODE_JOINED(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_NEST_LEGACY_LAST_NODE_JOINED(void) { + if (!mLegacyNodeDidJoin) { memset(&mLegacyLastJoinedNode, 0, sizeof(mLegacyLastJoinedNode)); } - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_EUI64_S, - &mLegacyLastJoinedNode, - sizeof(mLegacyLastJoinedNode) - ); + return mEncoder.WriteEui64(mLegacyLastJoinedNode); } #endif // OPENTHREAD_ENABLE_LEGACY -otError NcpBase::GetPropertyHandler_ChannelMaskHelper(uint8_t aHeader, spinel_prop_key_t aKey, uint32_t aChannelMask) +otError NcpBase::GetPropertyHandler_ChannelMaskHelper(uint32_t aChannelMask) { otError error = OT_ERROR_NONE; - SuccessOrExit(error = OutboundFrameBegin(aHeader)); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S, - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey - )); - - for (int i = 0; i < 32; i++) + for (uint8_t i = 0; i < 32; i++) { if (0 != (aChannelMask & (1 << i))) { - SuccessOrExit(error = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT8_S, i)); + SuccessOrExit(error = mEncoder.WriteUint8(i)); } } - SuccessOrExit(error = OutboundFrameSend()); - exit: return error; } -otError NcpBase::GetPropertyHandler_MAC_SCAN_MASK(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_SCAN_MASK(void) { - return GetPropertyHandler_ChannelMaskHelper(aHeader, aKey, mChannelMask); + return GetPropertyHandler_ChannelMaskHelper(mChannelMask); } otError NcpBase::SetPropertyHandler_MAC_SCAN_MASK(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -3749,15 +2878,9 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_MAC_SCAN_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_SCAN_PERIOD(void) { - return SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT16_S, - mScanPeriod - ); + return mEncoder.WriteUint16(mScanPeriod); } otError NcpBase::SetPropertyHandler_MAC_SCAN_PERIOD(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -3782,71 +2905,41 @@ exit: return SendSetPropertyResponse(aHeader, aKey, error); } -otError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_key_t aKey) +otError NcpBase::GetPropertyHandler_MAC_SCAN_STATE(void) { - otError error = OT_ERROR_NONE; + uint8_t scanState = SPINEL_SCAN_STATE_IDLE; #if OPENTHREAD_ENABLE_RAW_LINK_API if (otLinkRawIsEnabled(mInstance)) { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - mCurScanChannel == kInvalidScanChannel - ? SPINEL_SCAN_STATE_IDLE - : SPINEL_SCAN_STATE_ENERGY - ); + scanState = (mCurScanChannel == kInvalidScanChannel) ? SPINEL_SCAN_STATE_IDLE : SPINEL_SCAN_STATE_ENERGY; } else #endif // OPENTHREAD_ENABLE_RAW_LINK_API + { if (otLinkIsActiveScanInProgress(mInstance)) { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - SPINEL_SCAN_STATE_BEACON - ); + scanState = SPINEL_SCAN_STATE_BEACON; + } else if (otLinkIsEnergyScanInProgress(mInstance)) { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - SPINEL_SCAN_STATE_ENERGY - ); + scanState = SPINEL_SCAN_STATE_ENERGY; } else if (otThreadIsDiscoverInProgress(mInstance)) { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - SPINEL_SCAN_STATE_DISCOVER - ); + scanState = SPINEL_SCAN_STATE_DISCOVER; } else { - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - SPINEL_DATATYPE_UINT8_S, - SPINEL_SCAN_STATE_IDLE - ); + scanState = SPINEL_SCAN_STATE_IDLE; } } - return error; + return mEncoder.WriteUint8(scanState); } otError NcpBase::SetPropertyHandler_MAC_SCAN_STATE(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, @@ -3962,7 +3055,7 @@ void NcpBase::HandleActiveScanResult_Jump(otActiveScanResult *aResult, void *aCo void NcpBase::HandleActiveScanResult(otActiveScanResult *aResult) { - otError error; + otError error = OT_ERROR_NONE; if (aResult) { @@ -3978,55 +3071,48 @@ void NcpBase::HandleActiveScanResult(otActiveScanResult *aResult) flags |= SPINEL_BEACON_THREAD_FLAG_NATIVE; } - error = SendPropertyUpdate( - SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, - SPINEL_CMD_PROP_VALUE_INSERTED, - SPINEL_PROP_MAC_SCAN_BEACON, - SPINEL_DATATYPE_MAC_SCAN_RESULT_S( - SPINEL_802_15_4_DATATYPE_MAC_SCAN_RESULT_V1_S, - SPINEL_NET_DATATYPE_MAC_SCAN_RESULT_V2_S - ), - aResult->mChannel, // Channel - aResult->mRssi, // RSSI - // "mac-layer data" - aResult->mExtAddress.m8, // laddr - 0xFFFF, // saddr, not given - aResult->mPanId, // panid - aResult->mLqi, // lqi - // "net-layer data" - SPINEL_PROTOCOL_TYPE_THREAD, // type - flags, // flags - aResult->mNetworkName.m8, // network name - aResult->mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE, // xpanid - aResult->mSteeringData.m8, aResult->mSteeringData.mLength // steering data - ); + SuccessOrExit(error = mEncoder.BeginFrame( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_INSERTED, + SPINEL_PROP_MAC_SCAN_BEACON + )); + SuccessOrExit(error = mEncoder.WriteUint8(aResult->mChannel)); + SuccessOrExit(error = mEncoder.WriteInt8(aResult->mRssi)); - if (error != OT_ERROR_NONE) - { - mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM); - mUpdateChangedPropsTask.Post(); - } + SuccessOrExit(error = mEncoder.OpenStruct()); // "mac-layer data" + SuccessOrExit(error = mEncoder.WriteEui64(aResult->mExtAddress)); + SuccessOrExit(error = mEncoder.WriteUint16(0xffff)); // short address, not given + SuccessOrExit(error = mEncoder.WriteUint16(aResult->mPanId)); + SuccessOrExit(error = mEncoder.WriteUint8(aResult->mLqi)); + SuccessOrExit(error = mEncoder.CloseStruct()); + + SuccessOrExit(error = mEncoder.OpenStruct()); // "net-layer data" + SuccessOrExit(error = mEncoder.WriteUintPacked(SPINEL_PROTOCOL_TYPE_THREAD)); // type + SuccessOrExit(error = mEncoder.WriteUint8(flags)); + SuccessOrExit(error = mEncoder.WriteUtf8(aResult->mNetworkName.m8)); + SuccessOrExit(error = mEncoder.WriteDataWithLen(aResult->mExtendedPanId.m8, OT_EXT_PAN_ID_SIZE)); + SuccessOrExit(error = mEncoder.WriteDataWithLen(aResult->mSteeringData.m8, aResult->mSteeringData.mLength)); + SuccessOrExit(error = mEncoder.CloseStruct()); + + SuccessOrExit(error = mEncoder.EndFrame()); } else { - // We are finished with the scan, so send out - // a property update indicating such. - error = SendPropertyUpdate( - SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, - SPINEL_CMD_PROP_VALUE_IS, - SPINEL_PROP_MAC_SCAN_STATE, - SPINEL_DATATYPE_UINT8_S, - SPINEL_SCAN_STATE_IDLE - ); + // We are finished with the scan, send an unsolicated + // scan state update. + mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE); + mUpdateChangedPropsTask.Post(); + } - // If we could not send the end of scan indicator message now (no - // buffer space), we add the MAC_SCAN_STATE property to changed - // property set so that the update is sent when buffer becomes +exit: + + if (error != OT_ERROR_NONE) + { + // We ran out of buffer adding a scan result so remember to send + // an async `LAST_STATUS(NOMEM)` when buffer space becomes // available. - if (error != OT_ERROR_NONE) - { - mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE); - } + mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM); + mUpdateChangedPropsTask.Post(); } } @@ -4037,52 +3123,36 @@ void NcpBase::HandleEnergyScanResult_Jump(otEnergyScanResult *aResult, void *aCo void NcpBase::HandleEnergyScanResult(otEnergyScanResult *aResult) { - otError error; + otError error = OT_ERROR_NONE; if (aResult) { - error = SendPropertyUpdate( - SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, - SPINEL_CMD_PROP_VALUE_INSERTED, - SPINEL_PROP_MAC_ENERGY_SCAN_RESULT, - ( - SPINEL_DATATYPE_UINT8_S // Channel - SPINEL_DATATYPE_INT8_S // Rssi - ), - aResult->mChannel, - aResult->mMaxRssi - ); - - if (error != OT_ERROR_NONE) - { - mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM); - mUpdateChangedPropsTask.Post(); - } + SuccessOrExit(error = mEncoder.BeginFrame( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_INSERTED, + SPINEL_PROP_MAC_SCAN_BEACON + )); + SuccessOrExit(error = mEncoder.WriteUint8(aResult->mChannel)); + SuccessOrExit(error = mEncoder.WriteInt8(aResult->mMaxRssi)); + SuccessOrExit(error = mEncoder.EndFrame()); } else { - // We are finished with the scan, so send out - // a property update indicating such. - error = SendPropertyUpdate( - SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, - SPINEL_CMD_PROP_VALUE_IS, - SPINEL_PROP_MAC_SCAN_STATE, - SPINEL_DATATYPE_UINT8_S, - SPINEL_SCAN_STATE_IDLE - ); + // We are finished with the scan, send an unsolicated + // scan state update. + mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE); + mUpdateChangedPropsTask.Post(); + } - // If we could not send the end of scan indicator message now (no - // buffer space), we add the MAC_SCAN_STATE property to changed - // property set so that the update is sent when buffer becomes - // available. - if (error != OT_ERROR_NONE) - { - mChangedPropsSet.AddProperty(SPINEL_PROP_MAC_SCAN_STATE); - } +exit: + + if (error != OT_ERROR_NONE) + { + mChangedPropsSet.AddLastStatus(SPINEL_STATUS_NOMEM); + mUpdateChangedPropsTask.Post(); } } - // ---------------------------------------------------------------------------- // MARK: Outbound Datagram Handling // ---------------------------------------------------------------------------- @@ -4099,18 +3169,14 @@ void NcpBase::HandleDatagramFromStack(otMessage *aMessage) bool isSecure = otMessageIsLinkSecurityEnabled(aMessage); uint16_t length = otMessageGetLength(aMessage); - SuccessOrExit(error = OutboundFrameBegin(header)); + SuccessOrExit(error = mEncoder.BeginFrame( + header, + SPINEL_CMD_PROP_VALUE_IS, + isSecure ? SPINEL_PROP_STREAM_NET : SPINEL_PROP_STREAM_NET_INSECURE + )); - SuccessOrExit( - error = OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S, - header, - SPINEL_CMD_PROP_VALUE_IS, - isSecure ? SPINEL_PROP_STREAM_NET : SPINEL_PROP_STREAM_NET_INSECURE, - length - )); - - SuccessOrExit(error = OutboundFrameFeedMessage(aMessage)); + SuccessOrExit(error = mEncoder.WriteUint16(length)); + SuccessOrExit(error = mEncoder.WriteMessage(aMessage)); // Set the `aMessage` pointer to NULL to indicate that it does // not need to be freed at the exit. The `aMessage` is now owned @@ -4121,7 +3187,7 @@ void NcpBase::HandleDatagramFromStack(otMessage *aMessage) // Append any metadata (rssi, lqi, channel, etc) here! - SuccessOrExit(error = OutboundFrameSend()); + SuccessOrExit(error = mEncoder.EndFrame()); exit: diff --git a/src/ncp/ncp_base_radio.cpp b/src/ncp/ncp_base_radio.cpp index 665b6efa7..ace98cade 100644 --- a/src/ncp/ncp_base_radio.cpp +++ b/src/ncp/ncp_base_radio.cpp @@ -68,55 +68,38 @@ void NcpBase::LinkRawReceiveDone(otRadioFrame *aFrame, otError aError) uint16_t flags = 0; uint8_t header = SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0; - SuccessOrExit(OutboundFrameBegin(header)); - if (aFrame->mDidTX) { flags |= SPINEL_MD_FLAG_TX; } // Append frame header and frame length - SuccessOrExit( - OutboundFrameFeedPacked( - SPINEL_DATATYPE_COMMAND_PROP_S SPINEL_DATATYPE_UINT16_S, - header, - SPINEL_CMD_PROP_VALUE_IS, - SPINEL_PROP_STREAM_RAW, - (aError == OT_ERROR_NONE) ? aFrame->mLength : 0 - )); + SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_STREAM_RAW)); + SuccessOrExit(mEncoder.WriteUint16((aError == OT_ERROR_NONE) ? aFrame->mLength : 0)); if (aError == OT_ERROR_NONE) { // Append the frame contents - SuccessOrExit(OutboundFrameFeedData(aFrame->mPsdu, aFrame->mLength)); + SuccessOrExit(mEncoder.WriteData(aFrame->mPsdu, aFrame->mLength)); } // Append metadata (rssi, etc) - 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 - SPINEL_DATATYPE_UINT32_S // The timestamp milliseconds - SPINEL_DATATYPE_UINT16_S // The timestamp microseconds - ) - SPINEL_DATATYPE_STRUCT_S( // Vendor-data - SPINEL_DATATYPE_UINT_PACKED_S - ), - aFrame->mPower, // TX Power - -128, // Noise Floor (Currently unused) - flags, // Flags - aFrame->mChannel, // Receive channel - aFrame->mLqi, // Link quality indicator - aFrame->mMsec, // The timestamp milliseconds - aFrame->mUsec, // The timestamp microseconds, offset to mMsec - aError // Receive error - )); + SuccessOrExit(mEncoder.WriteInt8(aFrame->mPower)); // TX Power + SuccessOrExit(mEncoder.WriteInt8(-128)); // Noise Floor (Currently unused) + SuccessOrExit(mEncoder.WriteUint16(flags)); // Flags - SuccessOrExit(OutboundFrameSend()); + SuccessOrExit(mEncoder.OpenStruct()); // PHY-data + SuccessOrExit(mEncoder.WriteUint8(aFrame->mChannel)); // 802.15.4 channel (Receive channel) + SuccessOrExit(mEncoder.WriteUint8(aFrame->mLqi)); // 802.15.4 LQI + SuccessOrExit(mEncoder.WriteUint32(aFrame->mMsec)); // The timestamp milliseconds + SuccessOrExit(mEncoder.WriteUint16(aFrame->mUsec)); // The timestamp microseconds, offset to mMsec + SuccessOrExit(mEncoder.CloseStruct()); + + SuccessOrExit(mEncoder.OpenStruct()); // Vendor-data + SuccessOrExit(mEncoder.WriteUintPacked(aError)); // Receive error + SuccessOrExit(mEncoder.CloseStruct()); + + SuccessOrExit(mEncoder.EndFrame()); exit: return; @@ -138,40 +121,28 @@ void NcpBase::LinkRawTransmitDone(otRadioFrame *aFrame, otRadioFrame *aAckFrame, // 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 - )); + SuccessOrExit(mEncoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_IS, SPINEL_PROP_LAST_STATUS)); + SuccessOrExit(mEncoder.WriteUintPacked(ThreadErrorToSpinelStatus(aError))); + SuccessOrExit(mEncoder.WriteBool(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(mEncoder.WriteUint16(aAckFrame->mLength)); + SuccessOrExit(mEncoder.WriteData(aAckFrame->mPsdu, aAckFrame->mLength)); + + SuccessOrExit(mEncoder.WriteInt8(aAckFrame->mPower)); // RSSI + SuccessOrExit(mEncoder.WriteInt8(-128)); // Noise Floor (Currently unused) + SuccessOrExit(mEncoder.WriteUint16(0)); // Flags + + SuccessOrExit(mEncoder.OpenStruct()); // PHY-data + + SuccessOrExit(mEncoder.WriteUint8(aAckFrame->mChannel)); // Receive channel + SuccessOrExit(mEncoder.WriteUint8(aAckFrame->mLqi)); // Link Quality Indicator + + SuccessOrExit(mEncoder.CloseStruct()); } - SuccessOrExit(OutboundFrameSend()); + SuccessOrExit(mEncoder.EndFrame()); } exit: @@ -186,15 +157,7 @@ void NcpBase::LinkRawEnergyScanDone(otInstance *, int8_t aEnergyScanMaxRssi) void NcpBase::LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi) { - SendPropertyUpdate( - SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, - SPINEL_CMD_PROP_VALUE_IS, - SPINEL_PROP_MAC_ENERGY_SCAN_RESULT, - SPINEL_DATATYPE_UINT8_S - SPINEL_DATATYPE_INT8_S, - mCurScanChannel, - aEnergyScanMaxRssi - ); + int8_t scanChannel = mCurScanChannel; // Clear current scan channel mCurScanChannel = kInvalidScanChannel; @@ -203,17 +166,32 @@ void NcpBase::LinkRawEnergyScanDone(int8_t aEnergyScanMaxRssi) // since the energy scan could have been on a different channel. otLinkRawReceive(mInstance, mCurReceiveChannel, &NcpBase::LinkRawReceiveDone); + SuccessOrExit( + mEncoder.BeginFrame( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_MAC_ENERGY_SCAN_RESULT + )); + + SuccessOrExit(mEncoder.WriteUint8(static_cast(scanChannel))); + SuccessOrExit(mEncoder.WriteInt8(aEnergyScanMaxRssi)); + SuccessOrExit(mEncoder.EndFrame()); + // We are finished with the scan, so send out // a property update indicating such. - SendPropertyUpdate( - SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, - SPINEL_CMD_PROP_VALUE_IS, - SPINEL_PROP_MAC_SCAN_STATE, - SPINEL_DATATYPE_UINT8_S, - SPINEL_SCAN_STATE_IDLE - ); -} + SuccessOrExit( + mEncoder.BeginFrame( + SPINEL_HEADER_FLAG | SPINEL_HEADER_IID_0, + SPINEL_CMD_PROP_VALUE_IS, + SPINEL_PROP_MAC_SCAN_STATE + )); + SuccessOrExit(mEncoder.WriteUint8(SPINEL_SCAN_STATE_IDLE)); + SuccessOrExit(mEncoder.EndFrame()); + +exit: + return; +} otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_ENABLED(uint8_t aHeader, spinel_prop_key_t aKey, const uint8_t *aValuePtr, uint16_t aValueLen) @@ -273,14 +251,9 @@ otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeade VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); } - error = - SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - aValuePtr, - aValueLen - ); + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: @@ -328,14 +301,9 @@ otError NcpBase::SetPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHe VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); } - error = - SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_IS, - aKey, - aValuePtr, - aValueLen - ); + SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aKey)); + SuccessOrExit(error = mEncoder.WriteData(aValuePtr, aValueLen)); + SuccessOrExit(error = mEncoder.EndFrame()); exit: @@ -347,12 +315,10 @@ exit: return error; } -otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; uint16_t shortAddress; parsedLength = spinel_datatype_unpack( @@ -362,35 +328,18 @@ otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHe &shortAddress ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkRawSrcMatchClearShortEntry(mInstance, shortAddress); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress; parsedLength = spinel_datatype_unpack( @@ -400,35 +349,18 @@ otError NcpBase::RemovePropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t &extAddress ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkRawSrcMatchClearExtEntry(mInstance, extAddress); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_REMOVED, - aKey, - aValuePtr, - aValueLen - ); exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; uint16_t short_address; parsedLength = spinel_datatype_unpack( @@ -438,36 +370,18 @@ otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_SHORT_ADDRESSES(uint8_t aHe &short_address ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkRawSrcMatchAddShortEntry(mInstance, short_address); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); - exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } -otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t aHeader, spinel_prop_key_t aKey, - const uint8_t *aValuePtr, uint16_t aValueLen) +otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(const uint8_t *aValuePtr, uint16_t aValueLen) { spinel_ssize_t parsedLength; otError error = OT_ERROR_NONE; - spinel_status_t spinelError = SPINEL_STATUS_OK; otExtAddress *extAddress = NULL; parsedLength = spinel_datatype_unpack( @@ -477,27 +391,11 @@ otError NcpBase::InsertPropertyHandler_MAC_SRC_MATCH_EXTENDED_ADDRESSES(uint8_t &extAddress ); - VerifyOrExit(parsedLength > 0, spinelError = SPINEL_STATUS_PARSE_ERROR); + VerifyOrExit(parsedLength > 0, error = OT_ERROR_PARSE); error = otLinkRawSrcMatchAddExtEntry(mInstance, extAddress); - VerifyOrExit(error == OT_ERROR_NONE, spinelError = ThreadErrorToSpinelStatus(error)); - - error = SendPropertyUpdate( - aHeader, - SPINEL_CMD_PROP_VALUE_INSERTED, - aKey, - aValuePtr, - aValueLen - ); - exit: - - if (spinelError != SPINEL_STATUS_OK) - { - error = SendLastStatus(aHeader, spinelError); - } - return error; } diff --git a/src/ncp/ncp_buffer.cpp b/src/ncp/ncp_buffer.cpp index a33c8f178..8293797c2 100644 --- a/src/ncp/ncp_buffer.cpp +++ b/src/ncp/ncp_buffer.cpp @@ -211,8 +211,8 @@ uint16_t NcpFrameBuffer::ReadUint16At(uint8_t *aBufPtr, Direction aDirection) return value; } -// Writes a byte at the write tail, discards the frame if buffer gets full. -otError NcpFrameBuffer::InFrameFeedByte(uint8_t aByte) +// Appends a byte at the write tail and updates the tail, discards the frame if buffer gets full. +otError NcpFrameBuffer::InFrameAppend(uint8_t aByte) { otError error = OT_ERROR_NONE; uint8_t *newTail; @@ -254,7 +254,7 @@ otError NcpFrameBuffer::InFrameBeginSegment(void) // Reserve space for the segment header. for (uint16_t i = kSegmentHeaderSize; i; i--) { - SuccessOrExit(error = InFrameFeedByte(0)); + SuccessOrExit(error = InFrameAppend(0)); } // Write the flags at the segment head. @@ -344,6 +344,21 @@ otError NcpFrameBuffer::InFrameBegin(Priority aPriority) return OT_ERROR_NONE; } +otError NcpFrameBuffer::InFrameFeedByte(uint8_t aByte) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE); + + // Begin a new segment (if we are not in middle of segment already). + SuccessOrExit(error = InFrameBeginSegment()); + + error = InFrameAppend(aByte); + +exit: + return error; +} + otError NcpFrameBuffer::InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength) { otError error = OT_ERROR_NONE; @@ -356,7 +371,7 @@ otError NcpFrameBuffer::InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDa // Write the data buffer while (aDataBufferLength--) { - SuccessOrExit(error = InFrameFeedByte(*aDataBuffer++)); + SuccessOrExit(error = InFrameAppend(*aDataBuffer++)); } exit: @@ -383,12 +398,15 @@ exit: return error; } -otError NcpFrameBuffer::InFrameGetPosition(WritePosition &aPosition) const +otError NcpFrameBuffer::InFrameGetPosition(WritePosition &aPosition) { otError error = OT_ERROR_NONE; VerifyOrExit(mWriteDirection != kUnknown, error = OT_ERROR_INVALID_STATE); + // Begin a new segment (if we are not in middle of segment already). + SuccessOrExit(error = InFrameBeginSegment()); + aPosition.mPosition = mWriteSegmentTail; aPosition.mSegmentHead = mWriteSegmentHead; diff --git a/src/ncp/ncp_buffer.hpp b/src/ncp/ncp_buffer.hpp index bc07c1939..2fdacf4bb 100644 --- a/src/ncp/ncp_buffer.hpp +++ b/src/ncp/ncp_buffer.hpp @@ -40,7 +40,6 @@ namespace ot { namespace Ncp { - /** * This class implements a buffer/queue for storing NCP frames. * @@ -52,6 +51,7 @@ namespace Ncp { */ class NcpFrameBuffer { + friend class SpinelEncoder; public: /** @@ -163,6 +163,24 @@ public: */ otError InFrameBegin(Priority aPriority); + /** + * This method adds a single byte to current input frame. + * + * Before using this method `InFrameBegin()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aByte The byte value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given byte to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. + * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. + * + */ + otError InFrameFeedByte(uint8_t aByte); + /** * This method adds data to the current input frame. * @@ -177,7 +195,7 @@ public: * * @retval OT_ERROR_NONE Successfully added new data to the frame. * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add data. - * @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame. + * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. * */ otError InFrameFeedData(const uint8_t *aDataBuffer, uint16_t aDataBufferLength); @@ -198,7 +216,7 @@ public: * * @retval OT_ERROR_NONE Successfully added the message to the frame. * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the message. - * @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame. + * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. * @retval OT_ERROR_INVALID_ARGS If @p aMessage is NULL. * */ @@ -214,10 +232,10 @@ public: * @param[out] aPosition A reference to a `WritePosition` to save the current write position. * * @retval OT_ERROR_NONE Successfully saved current write position in @p aPosition. - * @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame. + * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. * */ - otError InFrameGetPosition(WritePosition &aPosition) const; + otError InFrameGetPosition(WritePosition &aPosition); /** * This method overwrites the previously written content in the current input frame at a given write position. @@ -286,7 +304,7 @@ public: * * @retval OT_ERROR_NONE Successfully ended the input frame. * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message. - * @retval OT_ERROR_INVALID_STATE InFrameBegin() has not been called earlier to start the frame. + * @retval OT_ERROR_INVALID_STATE `InFrameBegin()` has not been called earlier to start the frame. * */ otError InFrameEnd(void); @@ -581,7 +599,7 @@ private: bool HasFrame(Priority aPriority) const; void UpdateReadWriteStartPointers(void); - otError InFrameFeedByte(uint8_t aByte); + otError InFrameAppend(uint8_t aByte); otError InFrameBeginSegment(void); void InFrameEndSegment(uint16_t aSegmentHeaderFlags); void InFrameDiscard(void); diff --git a/src/ncp/spinel_encoder.cpp b/src/ncp/spinel_encoder.cpp new file mode 100644 index 000000000..6ab6ce593 --- /dev/null +++ b/src/ncp/spinel_encoder.cpp @@ -0,0 +1,277 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file implements a spinel encoder. + */ + +#include + +#include "spinel_encoder.hpp" + +#include "common/code_utils.hpp" + +namespace ot { +namespace Ncp { + +otError SpinelEncoder::BeginFrame(NcpFrameBuffer::Priority aPriority) +{ + mNumOpenStructs = 0; + return mNcpBuffer.InFrameBegin(aPriority); +} + +otError SpinelEncoder::BeginFrame(uint8_t aHeader, unsigned int aCommand) +{ + otError error = OT_ERROR_NONE; + + // Non-zero TID indicates this is a response to a spinel command. + + if (SPINEL_HEADER_GET_TID(aHeader) != 0) + { + SuccessOrExit(error = BeginFrame(NcpFrameBuffer::kPriorityHigh)); + } + else + { + SuccessOrExit(error = BeginFrame(NcpFrameBuffer::kPriorityLow)); + } + + SuccessOrExit(error = WriteUint8(aHeader)); + SuccessOrExit(error = WriteUintPacked(aCommand)); + +exit: + return error; +} + +otError SpinelEncoder::BeginFrame(uint8_t aHeader, unsigned int aCommand, spinel_prop_key_t aKey) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = BeginFrame(aHeader, aCommand)); + + // The write position is saved before writing the property key, + // so that if fetching the property fails and we need to + // reply with a `LAST_STATUS` error we can get back to + // this saved write position and update the property key. + // (Also see `OverwriteWithLastStatusError()`). + + SuccessOrExit(error = SavePosition()); + SuccessOrExit(error = WriteUintPacked(aKey)); + +exit: + return error; +} + +otError SpinelEncoder::OverwriteWithLastStatusError(spinel_status_t aStatus) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = ResetToSaved()); + SuccessOrExit(error = WriteUintPacked(SPINEL_PROP_LAST_STATUS)); + SuccessOrExit(error = WriteUintPacked(aStatus)); + +exit: + return error; +} + +otError SpinelEncoder::EndFrame(void) +{ + otError error = OT_ERROR_NONE; + + while (mNumOpenStructs > 0) + { + SuccessOrExit(error = CloseStruct()); + } + + error = mNcpBuffer.InFrameEnd(); + +exit: + return error; +} + +otError SpinelEncoder::WriteUint16(uint16_t aUint16) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint16 >> 0) & 0xff)); + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint16 >> 8) & 0xff)); + +exit: + return error; +} + +otError SpinelEncoder::WriteUint32(uint32_t aUint32) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 0) & 0xff)); + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 8) & 0xff)); + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 16) & 0xff)); + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 24) & 0xff)); + +exit: + return error; +} + +otError SpinelEncoder::WriteUintPacked(unsigned int aUint) +{ + uint8_t buffer[6]; + spinel_ssize_t len; + + len = spinel_packed_uint_encode(buffer, sizeof(buffer), aUint); + + return WriteData(buffer, static_cast(len)); +} + +otError SpinelEncoder::WriteDataWithLen(const uint8_t *aData, uint16_t aDataLen) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = WriteUint16(aDataLen)); + SuccessOrExit(error = WriteData(aData, aDataLen)); + +exit: + return error; +} + +otError SpinelEncoder::WriteUtf8(const char *aUtf8) +{ + otError error; + size_t len = strlen(aUtf8); + + if (len >= 0xffff) + { + len = 0xffff; + } + + SuccessOrExit(error = WriteData(reinterpret_cast(aUtf8), static_cast(len))); + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte(0)); + +exit: + return error; +} + +otError SpinelEncoder::OpenStruct(void) +{ + otError error = OT_ERROR_NONE; + + VerifyOrExit(mNumOpenStructs < kMaxNestedStructs, error = OT_ERROR_INVALID_STATE); + SuccessOrExit(error = mNcpBuffer.InFrameGetPosition(mStructPosition[mNumOpenStructs])); + + // Reserve bytes for the length to be filled when the struct gets closed. + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte(0)); + SuccessOrExit(error = mNcpBuffer.InFrameFeedByte(0)); + + mNumOpenStructs++; + +exit: + return error; +} + +otError SpinelEncoder::CloseStruct(void) +{ + otError error = OT_ERROR_NONE; + uint16_t len; + uint8_t buffer[sizeof(uint16_t)]; + + VerifyOrExit(mNumOpenStructs > 0, error = OT_ERROR_INVALID_STATE); + + mNumOpenStructs--; + + len = mNcpBuffer.InFrameGetDistance(mStructPosition[mNumOpenStructs]); + VerifyOrExit(len >= sizeof(uint16_t), error = OT_ERROR_INVALID_STATE); + + len -= sizeof(uint16_t); + + buffer[0] = (len >> 0 & 0xff); + buffer[1] = (len >> 8 & 0xff); + + SuccessOrExit(error = mNcpBuffer.InFrameOverwrite(mStructPosition[mNumOpenStructs], buffer, sizeof(buffer))); + +exit: + return error; +} + +otError SpinelEncoder::SavePosition(void) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mNcpBuffer.InFrameGetPosition(mSavedPosition)); + mSavedNumOpenStructs = mNumOpenStructs; + +exit: + return error; +} + +otError SpinelEncoder::ResetToSaved(void) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = mNcpBuffer.InFrameReset(mSavedPosition)); + mNumOpenStructs = mSavedNumOpenStructs; + +exit: + return error; +} + +otError SpinelEncoder::WritePacked(const char *aPackFormat, ...) +{ + uint8_t buf[kPackFormatBufferSize]; + otError error = OT_ERROR_NONE; + spinel_ssize_t packedLen; + va_list args; + + va_start(args, aPackFormat); + + packedLen = spinel_datatype_vpack(buf, sizeof(buf), aPackFormat, args); + VerifyOrExit((packedLen > 0) && (packedLen <= static_cast(sizeof(buf))), error = OT_ERROR_NO_BUFS); + + error = mNcpBuffer.InFrameFeedData(buf, static_cast(packedLen)); + + va_end(args); + +exit: + return error; +} + +otError SpinelEncoder::WriteVPacked(const char *aPackFormat, va_list aArgs) +{ + uint8_t buf[kPackFormatBufferSize]; + otError error = OT_ERROR_NONE; + spinel_ssize_t packedLen; + + packedLen = spinel_datatype_vpack(buf, sizeof(buf), aPackFormat, aArgs); + VerifyOrExit((packedLen > 0) && (packedLen <= static_cast(sizeof(buf))), error = OT_ERROR_NO_BUFS); + + error = mNcpBuffer.InFrameFeedData(buf, static_cast(packedLen)); + +exit: + return error; +} + +} // namespace Ncp +} // namespace ot diff --git a/src/ncp/spinel_encoder.hpp b/src/ncp/spinel_encoder.hpp new file mode 100644 index 000000000..c197e0532 --- /dev/null +++ b/src/ncp/spinel_encoder.hpp @@ -0,0 +1,652 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/** + * @file + * This file contains the definitions of a spinel encoder. + */ + +#ifndef SPINEL_ENCODER_HPP_ +#define SPINEL_ENCODER_HPP_ + +#include + +#include +#include +#include + +#include "openthread-core-config.h" +#include "ncp/spinel.h" +#include "ncp/ncp_buffer.hpp" + +namespace ot { +namespace Ncp { + +/** + * This class defines a spinel encoder. + * + */ +class SpinelEncoder +{ +public: + /** + * This constructor initializes a `SpinelEncoder` object. + * + * @param[in] aNcpBuffer A reference to a `NcpFrameBuffer` where the frames are written. + * + */ + SpinelEncoder(NcpFrameBuffer &aNcpBuffer): mNcpBuffer(aNcpBuffer), mNumOpenStructs(0) { } + + /** + * This method begins a new frame to be added/written to the frame buffer. + * + * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling + * `BeginFrame()` will discard and clear the previous unfinished frame. + * + * @param[in] aPriority Priority level of the new input frame. + * + * @retval OT_ERROR_NONE Successfully started a new frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. + * + */ + otError BeginFrame(NcpFrameBuffer::Priority aPriority); + + /** + * This method begins a new spinel command frame to be added/written to the frame buffer. + * + * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling + * `BeginFrame()` will discard and clear the previous unfinished frame. + * + * The spinel transaction ID (TID) in the given spinel header is used to determine the priority level of the new + * frame. Non-zero TID value indicates that the frame is a response and therefore it uses higher priority level. + * + * @param[in] aHeader Spinel header for new the command frame. + * @param[in] aCommand Spinel command. + * + * @retval OT_ERROR_NONE Successfully started a new frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. + * + */ + otError BeginFrame(uint8_t aHeader, unsigned int aCommand); + + /** + * This method begins a new spinel property update command frame to be added/written to the frame buffer. + * + * If there is a previous frame being written (for which `EndFrame()` has not yet been called), calling + * `BeginFrame()` will discard and clear the previous unfinished frame. + * + * The spinel transaction ID (TID) in the given spinel header is used to determine the priority level of the new + * frame. Non-zero TID value indicates that the frame is a response and therefore it uses higher priority level. + * + * This method saves the write position before the property key (see also `SavePosition()`) so that if fetching the + * property fails and the property key should be switched to `LAST_STATUS` with an error status, the saved + * position can be used to update the property key in the frame (see also `OverwriteWithLastStatusError()`) + * + * @param[in] aHeader Spinel header for new the command frame. + * @param[in] aCommand Spinel command. + * @param[in] aKey Spinel property key + * + * @retval OT_ERROR_NONE Successfully started a new frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start a new frame. + * + */ + otError BeginFrame(uint8_t aHeader, unsigned int aCommand, spinel_prop_key_t aKey); + + /** + * This method overwrites the property key with `LAST_STATUS` in a property update command frame. + * + * This method should be only used after a successful `BeginFrame(aHeader, aCommand, aPropertKey)`, otherwise, its + * behavior is undefined. + * + * This method moves the write position back to saved position by `BeginFrame()` and replaces the property key + * `SPINEL_PORP_LAST_STATUS` and writes the given spinel status error. + * + * @param[in] aStatus Spinel error status + * + * @retval OT_ERROR_NONE Successfully updated the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to update the frame. + * + */ + otError OverwriteWithLastStatusError(spinel_status_t aStatus); + + /** + * This method finalizes/ends the current frame being written to the buffer. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new frame. Otherwise, this method + * does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the frame and return error status + * `OT_ERROR_NO_BUFS`. + * + * This method ensures to close any open structure (previously opened using `OpenStruct()` but not closed using + * `CloseStruct()`). + * + * @retval OT_ERROR_NONE Successfully ended the input frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add message. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError EndFrame(void); + + /** + * This method encodes and writes a boolean value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aBool The boolean value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given byte to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteBool(bool aBool) { return mNcpBuffer.InFrameFeedByte( aBool ? 0x01: 0x00); } + + /** + * This method encodes and writes a `uint8_t` value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aUint8 The value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteUint8(uint8_t aUint8) { return mNcpBuffer.InFrameFeedByte(aUint8); } + + /** + * This method encodes and writes an `int8_t` value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aInt8 The value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteInt8(int8_t aInt8) { return WriteUint8(static_cast(aInt8)); } + + /** + * This method encodes and writes a `uint16_t` value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aUint16 The value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteUint16(uint16_t aUint16); + + /** + * This method encodes and writes an `int16_t` value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aInt16 The value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteInt16(int16_t aInt16) { return WriteUint16(static_cast(aInt16)); } + + /** + * This method encodes and writes a `uint32_t` value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aUint32 The value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteUint32(uint32_t aUint32); + + /** + * This method encodes and writes an `int32_t` value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aInt32 The value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteInt32(int32_t aInt32) { return WriteUint32(static_cast(aInt32)); } + + /** + * This method encodes (using spinel packed integer format) and writes a value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aUint The value to add to input frame. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteUintPacked(unsigned int aUint); + + /** + * This method encodes and writes an IPv6 address to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aIp6Addr A reference to the IPv6 address to be added (as `spinel_ipv6addr_t`) + * + * @retval OT_ERROR_NONE Successfully added given address to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteIp6Address(const spinel_ipv6addr_t &aIp6Addr) { return WriteIp6Address(aIp6Addr.bytes); } + + /** + * This method encodes and writes an IPv6 address to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aIp6Addr A reference to the IPv6 address to be added (as `otIp6Address`) + * + * @retval OT_ERROR_NONE Successfully added given address to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteIp6Address(const otIp6Address &aIp6Addr) { return WriteIp6Address(aIp6Addr.mFields.m8); } + + /** + * This method encodes and writes an IPv6 address to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aIp6AddrBuf A pointer to a buffer containing the IPv6 address. + * + * @retval OT_ERROR_NONE Successfully added given address to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the IP address. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteIp6Address(const uint8_t *aIp6AddrBuf) { return WriteData(aIp6AddrBuf, sizeof(spinel_ipv6addr_t)); } + + /** + * This method encodes and writes an EUI64 value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aEui64 A reference to the EUI64 value as a `spinel_eui64_t` type. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteEui64(const spinel_eui64_t &aEui64) { return WriteEui64(aEui64.bytes); } + + /** + * This method encodes and writes an EUI64 value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aExtAddress A reference to an `otExtAddress` + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteEui64(const otExtAddress &aExtAddress) { return WriteEui64(aExtAddress.m8); } + + /** + * This method encodes and writes an EUI64 value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aExtAddress A pointer to a buffer containing the EUI64 value. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI64 value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteEui64(const uint8_t *aEui64) { return WriteData(aEui64, sizeof(spinel_eui64_t)); } + + /** + * This method encodes and writes an EUI48 value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aEui48 A reference to the EUI48 value. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI48 value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteEui48(const spinel_eui48_t &aEui48) { return WriteEui48(aEui48.bytes); } + + /** + * This method encodes and writes an EUI48 value to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aEui48 A pointer to a buffer containing the EUI64 value. + * + * @retval OT_ERROR_NONE Successfully added given value to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the EUI48 value. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteEui48(const uint8_t *aEui48) { return WriteData(aEui48, sizeof(spinel_eui48_t)); } + + /** + * This method encodes and writes a UTF8 string to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aUtf8 A const character pointer (C string). + * + * @retval OT_ERROR_NONE Successfully added given string to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the string. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteUtf8(const char *aUtf8); + + /** + * This method encodes and writes a sequence of bytes to current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aData A pointer to data buffer. + * @param[in] aDataLen The length (number of bytes) in the data buffer. + * + * @retval OT_ERROR_NONE Successfully added given data to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteData(const uint8_t *aData, uint16_t aDataLen) { return mNcpBuffer.InFrameFeedData(aData, aDataLen); } + + /** + * This method encodes and writes a data blob (sequence of bytes) with its length prepended before the data. + * + * The length of the data (in bytes) is prepended (with the length encoded as a `uint16`). The size of the length + * field is not included in the length. This is similar to `SPINEL_DATATYPE_DATA_WLEN` type. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * @param[in] aData A pointer to data buffer. + * @param[in] aDataLen The length (number of bytes) in the data buffer. + * + * @retval OT_ERROR_NONE Successfully added given data to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteDataWithLen(const uint8_t *aData, uint16_t aDataLen); + + /** + * This method adds a message to the current input frame. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the frame and return error status + * `OT_ERROR_NO_BUFS`. + * + * In case of success, the passed-in message @p aMessage will be owned by the frame buffer instance and will be + * freed when either the the frame is removed or discarded. In case of failure @p aMessage remains unchanged. + * + * @param[in] aMessage A message to be added to current frame. + * + * @retval OT_ERROR_NONE Successfully added the message to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the message. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * @retval OT_ERROR_INVALID_ARGS If @p aMessage is NULL. + * + */ + otError WriteMessage(otMessage *aMessage) { return mNcpBuffer.InFrameFeedMessage(aMessage); } + + /** + * This method encodes and writes a set of variables to the current input frame using a given spinel packing format + * string. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * Note that the encoded buffer should fit in `kPackFormatBufferSize` bytes. + * + * @param[in] aPackFormat A string giving the spinel packing format. + * @param[in] ... Variable arguments corresponding to the types given in @p aPackFormat (see + * `spinel_datatype_pack()`). + * + * @retval OT_ERROR_NONE Successfully added given data to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WritePacked(const char *aPackFormat, ...); + + /** + * This method encodes and writes a set of variables to the current input frame using a given spinel packing format + * string. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the current input frame and return the + * error status `OT_ERROR_NO_BUFS`. + * + * Note that the encoded buffer should fit in `kPackFormatBufferSize` bytes. + * + * @param[in] aPackFormat A string giving the spinel packing format. + * @param[in] aArgs Variable arguments corresponding to the types given in @p aPackFormat (see + * `spinel_datatype_pack()`). + * + * @retval OT_ERROR_NONE Successfully added given data to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the byte. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError WriteVPacked(const char *aPackFormat, va_list aArgs); + + /** + * This method opens a struct in the current input frame. + * + * After a successful call to this method, all the subsequent `Write()` methods add the field/value to + * the current open struct until the struct is closed using `CloseStruct()` method. Structs can be nested. Up to + * `kMaxNestedStructs` nested structs can be opened at the same time. + * + * Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this + * method does nothing and returns error status `OT_ERROR_INVALID_STATE`. + * + * If no buffer space is available, this method will discard and clear the frame and return error status + * `OT_ERROR_NO_BUFS`. + * + * @retval OT_ERROR_NONE Successfully added the message to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if we reached + * the maximum number of nested open structures. + * + */ + otError OpenStruct(void); + + /** + * This method closes the most recently opened struct (using `OpenStruct()`) in the current input frame. + * + * Each call to `CloseStruct()` must correspond to an earlier successfully opened struct. If a frame is ended using + * `EndFrame()` with remaining open structs, the `EndFrame()` method will close all the remaining structs. + * + * If no buffer space is available, this method will discard and clear the frame and return error status + * `OT_ERROR_NO_BUFS`. + * + * @retval OT_ERROR_NONE Successfully added the message to the frame. + * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to open the struct. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame or if there is no + * open struct to close + */ + otError CloseStruct(void); + + /** + * This method saves the current write position in the input frame. + * + * The saved position can later be used to discard a portion of written/encoded frame and move the write pointer + * back to the saved position (using `ResetToSaved()`). + * + * @retval OT_ERROR_NONE Successfully saved current write position in @p aPosition. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * + */ + otError SavePosition(void); + + /** + * This method resets the write position of input frame back to a previously saved position. Any added content + * after the write position is discarded. + * + * The saved position must belong to the same input frame saved earlier with `SavePosition()`. This method cannot + * be used if the input frame has an added `otMessage`. + * + * @retval OT_ERROR_NONE Successfully reset the write position of current input frame.. + * @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame. + * @retval OT_ERROR_INVALID_ARGS The saved position is not valid (does not belong to same input frame), or + * the input frame has an added `otMessage`. + * + */ + otError ResetToSaved(void); + +private: + enum + { + kPackFormatBufferSize = 96, ///< Size of buffer used when encoding using `WritePacked()` or `WriteVPacked()`. + kMaxNestedStructs = 4, ///< Maximum number of nested structs. + }; + + NcpFrameBuffer &mNcpBuffer; + NcpFrameBuffer::WritePosition mStructPosition[kMaxNestedStructs]; + uint8_t mNumOpenStructs; + + uint8_t mSavedNumOpenStructs; + NcpFrameBuffer::WritePosition mSavedPosition; +}; + +} // namespace Ncp +} // namespace ot + +#endif // SPINEL_ENCODER_HPP_ diff --git a/tests/unit/Makefile.am b/tests/unit/Makefile.am index ba17b2556..bc17680c5 100644 --- a/tests/unit/Makefile.am +++ b/tests/unit/Makefile.am @@ -97,6 +97,7 @@ check_PROGRAMS = \ test-strlcat \ test-strlcpy \ test-strnlen \ + test-spinel-encoder \ test-timer \ test-toolchain \ $(NULL) @@ -186,6 +187,9 @@ test_strlcpy_SOURCES = test_strlcpy.c test_strnlen_LDADD = $(COMMON_LDADD) test_strnlen_SOURCES = test_strnlen.c +test_spinel_encoder_LDADD = $(COMMON_LDADD) +test_spinel_encoder_SOURCES = test_platform.cpp test_spinel_encoder.cpp + test_timer_LDADD = $(COMMON_LDADD) test_timer_SOURCES = test_platform.cpp test_timer.cpp diff --git a/tests/unit/test_spinel_encoder.cpp b/tests/unit/test_spinel_encoder.cpp new file mode 100644 index 000000000..4ca952b6b --- /dev/null +++ b/tests/unit/test_spinel_encoder.cpp @@ -0,0 +1,515 @@ +/* + * Copyright (c) 2017, The OpenThread Authors. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include + +#include "openthread-instance.h" +#include "common/code_utils.hpp" +#include "ncp/spinel_encoder.hpp" + +#include "test_util.h" + +namespace ot { +namespace Ncp { + +enum +{ + kTestBufferSize = 800, +}; + +// Dump the buffer content to screen. +void DumpBuffer(const char *aTextMessage, uint8_t *aBuffer, uint16_t aBufferLength) +{ + enum + { + kBytesPerLine = 32, // Number of bytes per line. + }; + + char charBuff[kBytesPerLine + 1]; + uint16_t counter; + uint8_t byte; + + printf("\n%s - len = %u\n ", aTextMessage, aBufferLength); + + counter = 0; + + while (aBufferLength--) + { + byte = *aBuffer++; + printf("%02X ", byte); + charBuff[counter] = isprint(byte) ? static_cast(byte) : '.'; + counter++; + + if (counter == kBytesPerLine) + { + charBuff[counter] = 0; + printf(" %s\n ", charBuff); + counter = 0; + } + } + + charBuff[counter] = 0; + + while (counter++ < kBytesPerLine) + { + printf(" "); + } + + printf(" %s\n", charBuff); +} + + +otError ReadFrame(NcpFrameBuffer &aNcpBuffer, uint8_t *aFrame, uint16_t &aFrameLen) +{ + otError error = OT_ERROR_NONE; + + SuccessOrExit(error = aNcpBuffer.OutFrameBegin()); + aFrameLen = aNcpBuffer.OutFrameGetLength(); + VerifyOrExit(aNcpBuffer.OutFrameRead(aFrameLen, aFrame) == aFrameLen, error = OT_ERROR_FAILED); + SuccessOrExit(error = aNcpBuffer.OutFrameRemove()); + +exit: + return error; +} + +void TestSpinelEncoder(void) +{ + uint8_t buffer[kTestBufferSize]; + NcpFrameBuffer ncpBuffer(buffer, kTestBufferSize); + SpinelEncoder encoder(ncpBuffer); + + uint8_t frame[kTestBufferSize]; + uint16_t frameLen; + spinel_ssize_t parsedLen; + + const bool kBool_1 = true; + const bool kBool_2 = false; + const uint8_t kUint8 = 0x42; + const int8_t kInt8 = -73; + const uint16_t kUint16 = 0xabcd; + const int16_t kInt16 = -567; + const uint32_t kUint32 = 0xdeadbeef; + const int32_t kInt32 = -123455678L; + const unsigned int kUint_1 = 9; + const unsigned int kUint_2 = 0xa3; + const unsigned int kUint_3 = 0x8765; + const unsigned int kUint_4 = SPINEL_MAX_UINT_PACKED - 1; + + const spinel_ipv6addr_t kIp6Addr = + { + { 0x6B, 0x41, 0x65, 0x73, 0x42, 0x68, 0x61, 0x76, 0x54, 0x61, 0x72, 0x7A, 0x49, 0x69, 0x61, 0x4E } + }; + + const spinel_eui48_t kEui48 = + { + { 4, 8, 15, 16, 23, 42 } // "Lost" EUI48! + }; + + const spinel_eui64_t kEui64 = + { + { 2, 3, 5, 7, 11, 13, 17, 19 }, // "Prime" EUI64! + }; + + const char kString_1[] = "OpenThread"; + const char kString_2[] = ""; + + const uint16_t kData[] = { 10, 20, 3, 15, 1000, 60, 16 }; // ... then comes 17,18,19,20 :) + + bool b_1, b_2; + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + unsigned int u_1, u_2, u_3, u_4; + spinel_ipv6addr_t *ip6Addr; + spinel_eui48_t *eui48; + spinel_eui64_t *eui64; + const char *utf_1; + const char *utf_2; + const uint8_t *dataPtr; + spinel_size_t dataLen; + + memset(buffer, 0, sizeof(buffer)); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 1: Encoding of simple types"); + + SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed."); + SuccessOrQuit(encoder.WriteBool(kBool_1), "WriteBool() failed."); + SuccessOrQuit(encoder.WriteBool(kBool_2), "WriteBool() failed."); + SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed."); + SuccessOrQuit(encoder.WriteInt8(kInt8), "WriteUint8() failed."); + SuccessOrQuit(encoder.WriteUint16(kUint16), "WriteUint16() failed."); + SuccessOrQuit(encoder.WriteInt16(kInt16), "WriteInt16() failed."); + SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed."); + SuccessOrQuit(encoder.WriteInt32(kInt32), "WriteUint32() failed."); + SuccessOrQuit(encoder.WriteUintPacked(kUint_1), "WriteUintPacked() failed."); + SuccessOrQuit(encoder.WriteUintPacked(kUint_2), "WriteUintPacked() failed."); + SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed."); + SuccessOrQuit(encoder.WriteUintPacked(kUint_4), "WriteUintPacked() failed."); + SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr), "WriteIp6Addr() failed."); + SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed."); + SuccessOrQuit(encoder.WriteEui64(kEui64), "WriteEui64() failed."); + SuccessOrQuit(encoder.WriteUtf8(kString_1), "WriteUtf8() failed."); + SuccessOrQuit(encoder.WriteUtf8(kString_2), "WriteUtf8() failed."); + SuccessOrQuit(encoder.WriteData((const uint8_t *)kData, sizeof(kData)), "WriteData() failed."); + SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed."); + + DumpBuffer("Buffer", buffer, 256); + SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed."); + DumpBuffer("Frame", frame, frameLen); + + parsedLen = spinel_datatype_unpack( + frame, + (spinel_size_t)frameLen, + ( + SPINEL_DATATYPE_BOOL_S + SPINEL_DATATYPE_BOOL_S + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_INT8_S + SPINEL_DATATYPE_UINT16_S + SPINEL_DATATYPE_INT16_S + SPINEL_DATATYPE_UINT32_S + SPINEL_DATATYPE_INT32_S + SPINEL_DATATYPE_UINT_PACKED_S + SPINEL_DATATYPE_UINT_PACKED_S + SPINEL_DATATYPE_UINT_PACKED_S + SPINEL_DATATYPE_UINT_PACKED_S + SPINEL_DATATYPE_IPv6ADDR_S + SPINEL_DATATYPE_EUI48_S + SPINEL_DATATYPE_EUI64_S + SPINEL_DATATYPE_UTF8_S + SPINEL_DATATYPE_UTF8_S + SPINEL_DATATYPE_DATA_S + ), + &b_1, + &b_2, + &u8, + &i8, + &u16, + &i16, + &u32, + &i32, + &u_1, + &u_2, + &u_3, + &u_4, + &ip6Addr, + &eui48, + &eui64, + &utf_1, + &utf_2, + &dataPtr, + &dataLen + ); + + VerifyOrQuit(parsedLen == frameLen, "spinel parse failed"); + VerifyOrQuit(b_1 == kBool_1, "WriteBool() parse failed."); + VerifyOrQuit(b_2 == kBool_2, "WriteBool() parse failed."); + VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed."); + VerifyOrQuit(i8 == kInt8, "WriteUint8() parse failed."); + VerifyOrQuit(u16 == kUint16, "WriteUint16() parse failed."); + VerifyOrQuit(i16 == kInt16, "WriteInt16() parse failed."); + VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed."); + VerifyOrQuit(i32 == kInt32, "WriteUint32() parse failed."); + VerifyOrQuit(u_1 == kUint_1, "WriteUintPacked() parse failed."); + VerifyOrQuit(u_2 == kUint_2, "WriteUintPacked() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "WriteUintPacked() parse failed."); + VerifyOrQuit(u_4 == kUint_4, "WriteUintPacked() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "WriteIp6Address() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "WriteEui48() parse failed."); + VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0, "WriteEui64() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "WriteUtf8() parse failed."); + VerifyOrQuit(memcmp(utf_2, kString_2, sizeof(kString_2)) == 0, "WriteUtf8() parse failed."); + VerifyOrQuit(dataLen == sizeof(kData), "WriteData() parse failed."); + VerifyOrQuit(memcmp(dataPtr, &kData, sizeof(kData)) == 0, "WriteData() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 2: Test a single simple struct."); + + SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed."); + SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed."); + SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed."); + SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed."); + SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed."); + } + SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(encoder.WriteInt16(kInt16), "WriteInt16() failed."); + SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed."); + + DumpBuffer("Buffer", buffer, 256); + SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed."); + DumpBuffer("Frame", frame, frameLen); + + parsedLen = spinel_datatype_unpack( + frame, + (spinel_size_t)frameLen, + ( + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_UINT32_S + SPINEL_DATATYPE_EUI48_S + SPINEL_DATATYPE_UINT_PACKED_S + ) + SPINEL_DATATYPE_INT16_S + + ), + &u8, + &u32, + &eui48, + &u_3, + &i16 + ); + + VerifyOrQuit(parsedLen == frameLen, "spinel parse failed"); + VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed."); + VerifyOrQuit(i16 == kInt16, "WriteInt16() parse failed."); + VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "WriteUintPacked() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "WriteEui48() parse failed."); + + // Parse the struct as a "data with len". + parsedLen = spinel_datatype_unpack( + frame, + (spinel_size_t)frameLen, + ( + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_DATA_WLEN_S + SPINEL_DATATYPE_INT16_S + + ), + &u8, + &dataPtr, + &dataLen, + &i16 + ); + + VerifyOrQuit(parsedLen == frameLen, "spinel parse failed"); + VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed."); + VerifyOrQuit(i16 == kInt16, "WriteInt16() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 3: Test multiple structs and struct within struct."); + + SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed."); + SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed."); + SuccessOrQuit(encoder.WriteUtf8(kString_1), "WriteUtf8() failed."); + SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(encoder.WriteBool(kBool_1), "WriteBool() failed."); + SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr), "WriteIp6Addr() failed."); + + } + SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(encoder.WriteUint16(kUint16), "WriteUint16() failed."); + } + SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed."); + SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed."); + } + SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(encoder.WriteInt32(kInt32), "WriteUint32() failed."); + SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed."); + + DumpBuffer("Buffer", buffer, 256 + 100); + + SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed."); + + parsedLen = spinel_datatype_unpack( + frame, + (spinel_size_t)frameLen, + ( + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_UTF8_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_BOOL_S + SPINEL_DATATYPE_IPv6ADDR_S + ) + SPINEL_DATATYPE_UINT16_S + ) + SPINEL_DATATYPE_EUI48_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_UINT32_S + ) + SPINEL_DATATYPE_INT32_S + ), + &u8, + &utf_1, + &b_1, + &ip6Addr, + &u16, + &eui48, + &u32, + &i32 + ); + + VerifyOrQuit(parsedLen == frameLen, "spinel parse failed"); + VerifyOrQuit(b_1 == kBool_1, "WriteBool() parse failed."); + VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed."); + VerifyOrQuit(u16 == kUint16, "WriteUint16() parse failed."); + VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed."); + VerifyOrQuit(i32 == kInt32, "WriteUint32() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "WriteIp6Address() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "WriteEui48() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "WriteUtf8() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 4: Test unclosed struct."); + + SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed."); + SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed."); + SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed."); + SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed."); + SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed."); + // Do not close the structs expecting `EndFrame()` to close them. + } + } + SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed."); + + SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed."); + + parsedLen = spinel_datatype_unpack( + frame, + (spinel_size_t)frameLen, + ( + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_UINT32_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_EUI48_S + SPINEL_DATATYPE_UINT_PACKED_S + ) + ) + ), + &u8, + &u32, + &eui48, + &u_3 + ); + + VerifyOrQuit(parsedLen == frameLen, "spinel parse failed"); + VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed."); + VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed."); + VerifyOrQuit(u_3 == kUint_3, "WriteUintPacked() parse failed."); + VerifyOrQuit(memcmp(eui48, &kEui48, sizeof(spinel_eui48_t)) == 0, "WriteEui48() parse failed."); + + printf(" -- PASS\n"); + + printf("\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); + printf("\nTest 5: Test saving position and reseting back to a saved position"); + + SuccessOrQuit(encoder.BeginFrame(NcpFrameBuffer::kPriorityLow), "BeginFrame() failed."); + SuccessOrQuit(encoder.WriteUint8(kUint8), "WriteUint8() failed."); + SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed."); + + // Save position in middle a first open struct. + SuccessOrQuit(encoder.SavePosition(), "SavePosition failed."); + SuccessOrQuit(encoder.OpenStruct(), "OpenStruct() failed."); + { + SuccessOrQuit(encoder.WriteEui48(kEui48), "WriteEui48() failed."); + SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed."); + } + + // Reset to saved position in middle of the second open struct which should be discarded. + + SuccessOrQuit(encoder.ResetToSaved(), "ResetToSaved() failed."); + + SuccessOrQuit(encoder.WriteIp6Address(kIp6Addr), "WriteIp6Addr() failed."); + SuccessOrQuit(encoder.WriteEui64(kEui64), "WriteEui64() failed."); + } + SuccessOrQuit(encoder.CloseStruct(), "CloseStruct() failed."); + SuccessOrQuit(encoder.WriteUtf8(kString_1), "WriteUtf8() failed."); + SuccessOrQuit(encoder.EndFrame(), "EndFrame() failed."); + + SuccessOrQuit(ReadFrame(ncpBuffer, frame, frameLen), "ReadFrame() failed."); + + parsedLen = spinel_datatype_unpack( + frame, + (spinel_size_t)frameLen, + ( + SPINEL_DATATYPE_UINT8_S + SPINEL_DATATYPE_STRUCT_S( + SPINEL_DATATYPE_UINT32_S + SPINEL_DATATYPE_IPv6ADDR_S + SPINEL_DATATYPE_EUI64_S + ) + SPINEL_DATATYPE_UTF8_S + ), + &u8, + &u32, + &ip6Addr, + &eui64, + &utf_1 + ); + + VerifyOrQuit(parsedLen == frameLen, "spinel parse failed"); + + VerifyOrQuit(u8 == kUint8, "WriteUint8() parse failed."); + VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed."); + VerifyOrQuit(i32 == kInt32, "WriteUint32() parse failed."); + VerifyOrQuit(memcmp(ip6Addr, &kIp6Addr, sizeof(spinel_ipv6addr_t)) == 0, "WriteIp6Address() parse failed."); + VerifyOrQuit(memcmp(eui64, &kEui64, sizeof(spinel_eui64_t)) == 0, "WriteEui64() parse failed."); + VerifyOrQuit(memcmp(utf_1, kString_1, sizeof(kString_1)) == 0, "WriteUtf8() parse failed."); + + printf(" -- PASS\n"); +} + +} // namespace Ncp +} // namespace ot + +#ifdef ENABLE_TEST_MAIN +int main(void) +{ + ot::Ncp::TestSpinelEncoder(); + printf("\nAll tests passed.\n"); + return 0; +} +#endif