[ncp] add vendor hook for property get/set handlers for vendor properties (#2725)

This commit is contained in:
Abtin Keshavarzian
2018-05-24 01:55:59 -07:00
committed by Jonathan Hui
parent 67d68009b7
commit 8f7dfead41
3 changed files with 175 additions and 14 deletions
+65 -1
View File
@@ -41,7 +41,8 @@ otError NcpBase::VendorCommandHandler(uint8_t aHeader, unsigned int aCommand)
{
otError error = OT_ERROR_NONE;
switch (aCommand) {
switch (aCommand)
{
// TODO: Implement your command handlers here.
@@ -52,6 +53,69 @@ otError NcpBase::VendorCommandHandler(uint8_t aHeader, unsigned int aCommand)
return error;
}
void NcpBase::VendorHandleFrameRemovedFromNcpBuffer(NcpFrameBuffer::FrameTag aFrameTag)
{
// This method is a callback which mirrors `NcpBase::HandleFrameRemovedFromNcpBuffer()`.
// It is called when a spinel frame is sent and removed from NCP buffer.
//
// (a) This can be used to track and verify that a vendor spinel frame response is
// delivered to the host (tracking the frame using its tag).
//
// (b) It indicates that NCP buffer space is now available (since a spinel frame is
// removed). This can be used to implement reliability mechanisms to re-send
// a failed spinel command response (or an async spinel frame) transmission
// (failed earlier due to NCP buffer being full).
OT_UNUSED_VARIABLE(aFrameTag);
}
otError NcpBase::VendorGetPropertyHandler(spinel_prop_key_t aPropKey)
{
otError error = OT_ERROR_NONE;
switch (aPropKey)
{
// TODO: Implement your property get handlers here.
//
// Get handler should retrieve the property value and then encode and write the
// value into the NCP buffer. If the "get" operation itself fails, handler should
// write a `LAST_STATUS` with the error status into the NCP buffer. `OT_ERROR_NO_BUFS`
// should be returned if NCP buffer is full and response cannot be written.
default:
error = OT_ERROR_NOT_FOUND;
break;
}
return error;
}
otError NcpBase::VendorSetPropertyHandler(spinel_prop_key_t aPropKey)
{
otError error = OT_ERROR_NONE;
switch (aPropKey)
{
// TODO: Implement your property set handlers here.
//
// Set handler should first decode the value from the input Spinel frame and then
// perform the corresponding set operation. The handler should not prepare the
// spinel response and therefore should not write anything to the NCP buffer.
// The error returned from handler (other than `OT_ERROR_NOT_FOUND`) indicates the
// error in either parsing of the input or the error of the set operation. In case
// of a successful "set", `NcpBase` set command handler will invoke the
// `VendorGetPropertyHandler()` for the same property key to prepare the response.
default:
error = OT_ERROR_NOT_FOUND;
break;
}
return error;
}
} // namespace Ncp
} // namespace ot
+44 -8
View File
@@ -1383,7 +1383,13 @@ otError NcpBase::HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKe
otError error = OT_ERROR_NONE;
PropertyHandler handler = FindSetPropertyHandler(aKey);
if (handler == NULL)
if (handler != NULL)
{
mDisableStreamWrite = false;
error = (this->*handler)();
mDisableStreamWrite = true;
}
else
{
// If there is no "set" handler, check if this property is one of the
// ones that require different treatment.
@@ -1392,15 +1398,26 @@ otError NcpBase::HandleCommandPropertySet(uint8_t aHeader, spinel_prop_key_t aKe
VerifyOrExit(!didHandle);
ExitNow(error = PrepareLastStatusResponse(aHeader, SPINEL_STATUS_PROP_NOT_FOUND));
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
if (aKey >= SPINEL_PROP_VENDOR__BEGIN && aKey < SPINEL_PROP_VENDOR__END)
{
mDisableStreamWrite = false;
error = VendorSetPropertyHandler(aKey);
mDisableStreamWrite = true;
// An `OT_ERROR_NOT_FOUND` status from vendor handler indicates
// that it does not support the given property key. In that
// case, `didHandle` is set to `false` so a `LAST_STATUS` with
// `PROP_NOT_FOUND` is emitted. Otherwise, we fall through to
// prepare the response.
didHandle = (error != OT_ERROR_NOT_FOUND);
}
#endif
VerifyOrExit(didHandle, error = PrepareLastStatusResponse(aHeader, SPINEL_STATUS_PROP_NOT_FOUND));
}
mDisableStreamWrite = false;
error = (this->*handler)();
mDisableStreamWrite = true;
if (error == OT_ERROR_NONE)
{
error = PrepareSetResponse(aHeader, aKey);
@@ -1505,6 +1522,25 @@ otError NcpBase::WritePropertyValueIsFrame(uint8_t aHeader, spinel_prop_key_t aP
ExitNow(error = mEncoder.EndFrame());
}
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
if (aPropKey >= SPINEL_PROP_VENDOR__BEGIN && aPropKey < SPINEL_PROP_VENDOR__END)
{
SuccessOrExit(error = mEncoder.BeginFrame(aHeader, SPINEL_CMD_PROP_VALUE_IS, aPropKey));
error = VendorGetPropertyHandler(aPropKey);
// An `OT_ERROR_NOT_FOUND` status from vendor handler indicates that
// it did not support the given property key. In that case, we fall
// through to prepare a `LAST_STATUS` response.
if (error != OT_ERROR_NOT_FOUND)
{
SuccessOrExit(error);
ExitNow(error = mEncoder.EndFrame());
}
}
#endif
if (aIsGetResponse)
{
SuccessOrExit(error = WriteLastStatusFrame(aHeader, SPINEL_STATUS_PROP_NOT_FOUND));
+66 -5
View File
@@ -303,11 +303,6 @@ protected:
void HandleTmfProxyStream(otMessage *aMessage, uint16_t aLocator, uint16_t aPort);
#endif // OPENTHREAD_FTD && OPENTHREAD_ENABLE_TMF_PROXY
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand);
void VendorHandleFrameRemovedFromNcpBuffer(NcpFrameBuffer::FrameTag aFrameTag);
#endif // OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
otError CommandHandler_NOOP(uint8_t aHeader);
otError CommandHandler_RESET(uint8_t aHeader);
// Combined command handler for `VALUE_GET`, `VALUE_SET`, `VALUE_INSERT` and `VALUE_REMOVE`.
@@ -723,6 +718,72 @@ protected:
static uint8_t ConvertLogLevel(otLogLevel aLogLevel);
static unsigned int ConvertLogRegion(otLogRegion aLogRegion);
#if OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
/**
* This method defines a vendor "command handler" hook to process vendor-specific spinel commands.
*
* @param[in] aHeader The spinel frame header.
* @param[in] aCommand The spinel command key.
*
* @retval OT_ERROR_NONE The response is prepared.
* @retval OT_ERROR_NO_BUFS Out of buffer while preparing the response.
*
*/
otError VendorCommandHandler(uint8_t aHeader, unsigned int aCommand);
/**
* This method is a callback which mirrors `NcpBase::HandleFrameRemovedFromNcpBuffer()`. It is called when a
* spinel frame is sent and removed from NCP buffer.
*
* (a) This can be used to track and verify that a vendor spinel frame response is delivered to the host (tracking
* the frame using its tag).
*
* (b) It indicates that NCP buffer space is now available (since a spinel frame is removed). This can be used to
* implement mechanisms to re-send a failed/pending response or an async spinel frame.
*
* @param[in] aFrameTag The tag of the frame removed from NCP buffer.
*
*/
void VendorHandleFrameRemovedFromNcpBuffer(NcpFrameBuffer::FrameTag aFrameTag);
/**
* This method defines a vendor "get property handler" hook to process vendor spinel properties.
*
* The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "get" operation for the
* given property key. Otherwise, the vendor handler should behave like other property get handlers, i.e., it
* should retrieve the property value and then encode and write the value into the NCP buffer. If the "get"
* operation itself fails, handler should write a `LAST_STATUS` with the error status into the NCP buffer.
*
* @param[in] aPropKey The spinel property key.
*
* @retval OT_ERROR_NONE Successfully retrieved the property value and prepared the response.
* @retval OT_ERROR_NOT_FOUND Does not support the given property key.
* @retval OT_ERROR_NO_BUFS Out of buffer while preparing the response.
*
*/
otError VendorGetPropertyHandler(spinel_prop_key_t aPropKey);
/**
* This method defines a vendor "set property handler" hook to process vendor spinel properties.
*
* The vendor handler should return `OT_ERROR_NOT_FOUND` status if it does not support "set" operation for the
* given property key. Otherwise, the vendor handler should behave like other property set handlers, i.e., it
* should first decode the value from the input spinel frame and then perform the corresponding set operation. The
* handler should not prepare the spinel response and therefore should not write anything to the NCP buffer. The
* `otError` returned from handler (other than `OT_ERROR_NOT_FOUND`) indicates the error in either parsing of the
* input or the error of the set operation. In case of a successful "set", `NcpBase` set command handler will call
* the `VendorGetPropertyHandler()` for the same property key to prepare the response.
*
* @param[in] aPropKey The spinel property key.
*
* @returns OT_ERROR_NOT_FOUND if it does not support the given property key, otherwise the error in either parsing
* of the input or the "set" operation.
*
*/
otError VendorSetPropertyHandler(spinel_prop_key_t aPropKey);
#endif // OPENTHREAD_ENABLE_NCP_VENDOR_HOOK
protected:
static NcpBase *sNcpInstance;
static spinel_status_t ThreadErrorToSpinelStatus(otError aError);