mirror of
https://github.com/espressif/esp-matter.git
synced 2026-04-27 19:13:13 +00:00
a54b1e0f42
The test_event_6_esp branch fixes some errors for esp32h2 platform based on TE6 branch
3948 lines
164 KiB
C++
3948 lines
164 KiB
C++
/*
|
|
*
|
|
* Copyright (c) 2021 Project CHIP Authors
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
// THIS FILE IS GENERATED BY ZAP
|
|
|
|
#include <cinttypes>
|
|
#include <cstdint>
|
|
|
|
#include "app/util/util.h"
|
|
#include <app-common/zap-generated/af-structs.h>
|
|
#include <app-common/zap-generated/callback.h>
|
|
#include <app-common/zap-generated/ids/Clusters.h>
|
|
#include <app-common/zap-generated/ids/Commands.h>
|
|
|
|
#include <app/InteractionModelEngine.h>
|
|
|
|
// Currently we need some work to keep compatible with ember lib.
|
|
#include <app/util/ember-compatibility-functions.h>
|
|
|
|
namespace chip {
|
|
namespace app {
|
|
|
|
namespace {
|
|
void ReportCommandUnsupported(Command * aCommandObj, EndpointId aEndpointId, ClusterId aClusterId, CommandId aCommandId)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
aClusterId, aCommandId, (CommandPathFlags::kEndpointIdValid) };
|
|
aCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::UnsupportedCommand);
|
|
ChipLogError(Zcl, "Unknown command " ChipLogFormatMEI " for cluster " ChipLogFormatMEI, ChipLogValueMEI(aCommandId),
|
|
ChipLogValueMEI(aClusterId));
|
|
}
|
|
} // anonymous namespace
|
|
|
|
// Cluster specific command parsing
|
|
|
|
namespace clusters {
|
|
|
|
namespace AdministratorCommissioning {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::AdministratorCommissioning::Commands::Ids::OpenBasicCommissioningWindow: {
|
|
expectArgumentCount = 1;
|
|
uint16_t CommissioningTimeout;
|
|
bool argExists[1];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 1)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(CommissioningTimeout);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfAdministratorCommissioningClusterOpenBasicCommissioningWindowCallback(aEndpointId, apCommandObj,
|
|
CommissioningTimeout);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::AdministratorCommissioning::Commands::Ids::OpenCommissioningWindow: {
|
|
expectArgumentCount = 6;
|
|
uint16_t CommissioningTimeout;
|
|
chip::ByteSpan PAKEVerifier;
|
|
uint16_t Discriminator;
|
|
uint32_t Iterations;
|
|
chip::ByteSpan Salt;
|
|
uint16_t PasscodeID;
|
|
bool argExists[6];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 6)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(CommissioningTimeout);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(PAKEVerifier);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(Discriminator);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(Iterations);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(Salt);
|
|
break;
|
|
case 5:
|
|
TLVUnpackError = aDataTlv.Get(PasscodeID);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 6 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfAdministratorCommissioningClusterOpenCommissioningWindowCallback(
|
|
aEndpointId, apCommandObj, CommissioningTimeout, PAKEVerifier, Discriminator, Iterations, Salt, PasscodeID);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::AdministratorCommissioning::Commands::Ids::RevokeCommissioning: {
|
|
|
|
wasHandled = emberAfAdministratorCommissioningClusterRevokeCommissioningCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::AdministratorCommissioning::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::AdministratorCommissioning::Id, aCommandId,
|
|
(CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace AdministratorCommissioning
|
|
|
|
namespace ColorControl {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::ColorControl::Commands::Ids::ColorLoopSet: {
|
|
expectArgumentCount = 7;
|
|
uint8_t updateFlags;
|
|
uint8_t action;
|
|
uint8_t direction;
|
|
uint16_t time;
|
|
uint16_t startHue;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[7];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 7)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(updateFlags);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(action);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(direction);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(time);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(startHue);
|
|
break;
|
|
case 5:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 6:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 7 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterColorLoopSetCallback(
|
|
aEndpointId, apCommandObj, updateFlags, action, direction, time, startHue, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::EnhancedMoveHue: {
|
|
expectArgumentCount = 4;
|
|
uint8_t moveMode;
|
|
uint16_t rate;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(moveMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(rate);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterEnhancedMoveHueCallback(aEndpointId, apCommandObj, moveMode, rate,
|
|
optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::EnhancedMoveToHue: {
|
|
expectArgumentCount = 5;
|
|
uint16_t enhancedHue;
|
|
uint8_t direction;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(enhancedHue);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(direction);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterEnhancedMoveToHueCallback(aEndpointId, apCommandObj, enhancedHue, direction,
|
|
transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::EnhancedMoveToHueAndSaturation: {
|
|
expectArgumentCount = 5;
|
|
uint16_t enhancedHue;
|
|
uint8_t saturation;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(enhancedHue);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(saturation);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterEnhancedMoveToHueAndSaturationCallback(
|
|
aEndpointId, apCommandObj, enhancedHue, saturation, transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::EnhancedStepHue: {
|
|
expectArgumentCount = 5;
|
|
uint8_t stepMode;
|
|
uint16_t stepSize;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(stepMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(stepSize);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterEnhancedStepHueCallback(aEndpointId, apCommandObj, stepMode, stepSize,
|
|
transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveColor: {
|
|
expectArgumentCount = 4;
|
|
int16_t rateX;
|
|
int16_t rateY;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(rateX);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(rateY);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveColorCallback(aEndpointId, apCommandObj, rateX, rateY, optionsMask,
|
|
optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveColorTemperature: {
|
|
expectArgumentCount = 6;
|
|
uint8_t moveMode;
|
|
uint16_t rate;
|
|
uint16_t colorTemperatureMinimum;
|
|
uint16_t colorTemperatureMaximum;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[6];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 6)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(moveMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(rate);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(colorTemperatureMinimum);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(colorTemperatureMaximum);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 5:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 6 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveColorTemperatureCallback(
|
|
aEndpointId, apCommandObj, moveMode, rate, colorTemperatureMinimum, colorTemperatureMaximum, optionsMask,
|
|
optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveHue: {
|
|
expectArgumentCount = 4;
|
|
uint8_t moveMode;
|
|
uint8_t rate;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(moveMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(rate);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveHueCallback(aEndpointId, apCommandObj, moveMode, rate, optionsMask,
|
|
optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveSaturation: {
|
|
expectArgumentCount = 4;
|
|
uint8_t moveMode;
|
|
uint8_t rate;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(moveMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(rate);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveSaturationCallback(aEndpointId, apCommandObj, moveMode, rate,
|
|
optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveToColor: {
|
|
expectArgumentCount = 5;
|
|
uint16_t colorX;
|
|
uint16_t colorY;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(colorX);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(colorY);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveToColorCallback(aEndpointId, apCommandObj, colorX, colorY,
|
|
transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveToColorTemperature: {
|
|
expectArgumentCount = 4;
|
|
uint16_t colorTemperature;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(colorTemperature);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveToColorTemperatureCallback(aEndpointId, apCommandObj, colorTemperature,
|
|
transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveToHue: {
|
|
expectArgumentCount = 5;
|
|
uint8_t hue;
|
|
uint8_t direction;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(hue);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(direction);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveToHueCallback(aEndpointId, apCommandObj, hue, direction, transitionTime,
|
|
optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveToHueAndSaturation: {
|
|
expectArgumentCount = 5;
|
|
uint8_t hue;
|
|
uint8_t saturation;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(hue);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(saturation);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveToHueAndSaturationCallback(aEndpointId, apCommandObj, hue, saturation,
|
|
transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::MoveToSaturation: {
|
|
expectArgumentCount = 4;
|
|
uint8_t saturation;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(saturation);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterMoveToSaturationCallback(aEndpointId, apCommandObj, saturation,
|
|
transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::StepColor: {
|
|
expectArgumentCount = 5;
|
|
int16_t stepX;
|
|
int16_t stepY;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(stepX);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(stepY);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterStepColorCallback(aEndpointId, apCommandObj, stepX, stepY, transitionTime,
|
|
optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::StepColorTemperature: {
|
|
expectArgumentCount = 7;
|
|
uint8_t stepMode;
|
|
uint16_t stepSize;
|
|
uint16_t transitionTime;
|
|
uint16_t colorTemperatureMinimum;
|
|
uint16_t colorTemperatureMaximum;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[7];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 7)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(stepMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(stepSize);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(colorTemperatureMinimum);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(colorTemperatureMaximum);
|
|
break;
|
|
case 5:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 6:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 7 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterStepColorTemperatureCallback(
|
|
aEndpointId, apCommandObj, stepMode, stepSize, transitionTime, colorTemperatureMinimum, colorTemperatureMaximum,
|
|
optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::StepHue: {
|
|
expectArgumentCount = 5;
|
|
uint8_t stepMode;
|
|
uint8_t stepSize;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(stepMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(stepSize);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterStepHueCallback(aEndpointId, apCommandObj, stepMode, stepSize,
|
|
transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::StepSaturation: {
|
|
expectArgumentCount = 5;
|
|
uint8_t stepMode;
|
|
uint8_t stepSize;
|
|
uint16_t transitionTime;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(stepMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(stepSize);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfColorControlClusterStepSaturationCallback(aEndpointId, apCommandObj, stepMode, stepSize,
|
|
transitionTime, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::StopMoveStep: {
|
|
expectArgumentCount = 2;
|
|
uint8_t optionsMask;
|
|
uint8_t optionsOverride;
|
|
bool argExists[2];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 2)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(optionsMask);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(optionsOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount)
|
|
{
|
|
wasHandled =
|
|
emberAfColorControlClusterStopMoveStepCallback(aEndpointId, apCommandObj, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::ColorControl::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::ColorControl::Id, aCommandId, (CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace ColorControl
|
|
|
|
namespace DiagnosticLogs {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::DiagnosticLogs::Commands::Ids::RetrieveLogsRequest: {
|
|
expectArgumentCount = 3;
|
|
uint8_t intent;
|
|
uint8_t requestedProtocol;
|
|
chip::ByteSpan transferFileDesignator;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(intent);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(requestedProtocol);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transferFileDesignator);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfDiagnosticLogsClusterRetrieveLogsRequestCallback(aEndpointId, apCommandObj, intent,
|
|
requestedProtocol, transferFileDesignator);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::DiagnosticLogs::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::DiagnosticLogs::Id, aCommandId, (CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace DiagnosticLogs
|
|
|
|
namespace GeneralCommissioning {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::GeneralCommissioning::Commands::Ids::ArmFailSafe: {
|
|
expectArgumentCount = 3;
|
|
uint16_t expiryLengthSeconds;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(expiryLengthSeconds);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfGeneralCommissioningClusterArmFailSafeCallback(aEndpointId, apCommandObj, expiryLengthSeconds,
|
|
breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::GeneralCommissioning::Commands::Ids::CommissioningComplete: {
|
|
|
|
wasHandled = emberAfGeneralCommissioningClusterCommissioningCompleteCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
case Clusters::GeneralCommissioning::Commands::Ids::SetRegulatoryConfig: {
|
|
expectArgumentCount = 4;
|
|
uint8_t location;
|
|
const uint8_t * countryCode;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(location);
|
|
break;
|
|
case 1:
|
|
// TODO(#5542): The cluster handlers should accept a ByteSpan for all string types.
|
|
TLVUnpackError = aDataTlv.GetDataPtr(countryCode);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback(
|
|
aEndpointId, apCommandObj, location, const_cast<uint8_t *>(countryCode), breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::GeneralCommissioning::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::GeneralCommissioning::Id, aCommandId,
|
|
(CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace GeneralCommissioning
|
|
|
|
namespace LevelControl {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::LevelControl::Commands::Ids::Move: {
|
|
expectArgumentCount = 4;
|
|
uint8_t moveMode;
|
|
uint8_t rate;
|
|
uint8_t optionMask;
|
|
uint8_t optionOverride;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(moveMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(rate);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(optionMask);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled =
|
|
emberAfLevelControlClusterMoveCallback(aEndpointId, apCommandObj, moveMode, rate, optionMask, optionOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::LevelControl::Commands::Ids::MoveToLevel: {
|
|
expectArgumentCount = 4;
|
|
uint8_t level;
|
|
uint16_t transitionTime;
|
|
uint8_t optionMask;
|
|
uint8_t optionOverride;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(level);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(optionMask);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfLevelControlClusterMoveToLevelCallback(aEndpointId, apCommandObj, level, transitionTime,
|
|
optionMask, optionOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::LevelControl::Commands::Ids::MoveToLevelWithOnOff: {
|
|
expectArgumentCount = 2;
|
|
uint8_t level;
|
|
uint16_t transitionTime;
|
|
bool argExists[2];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 2)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(level);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount)
|
|
{
|
|
wasHandled =
|
|
emberAfLevelControlClusterMoveToLevelWithOnOffCallback(aEndpointId, apCommandObj, level, transitionTime);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::LevelControl::Commands::Ids::MoveWithOnOff: {
|
|
expectArgumentCount = 2;
|
|
uint8_t moveMode;
|
|
uint8_t rate;
|
|
bool argExists[2];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 2)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(moveMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(rate);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfLevelControlClusterMoveWithOnOffCallback(aEndpointId, apCommandObj, moveMode, rate);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::LevelControl::Commands::Ids::Step: {
|
|
expectArgumentCount = 5;
|
|
uint8_t stepMode;
|
|
uint8_t stepSize;
|
|
uint16_t transitionTime;
|
|
uint8_t optionMask;
|
|
uint8_t optionOverride;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(stepMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(stepSize);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(optionMask);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(optionOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfLevelControlClusterStepCallback(aEndpointId, apCommandObj, stepMode, stepSize, transitionTime,
|
|
optionMask, optionOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::LevelControl::Commands::Ids::StepWithOnOff: {
|
|
expectArgumentCount = 3;
|
|
uint8_t stepMode;
|
|
uint8_t stepSize;
|
|
uint16_t transitionTime;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(stepMode);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(stepSize);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(transitionTime);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled =
|
|
emberAfLevelControlClusterStepWithOnOffCallback(aEndpointId, apCommandObj, stepMode, stepSize, transitionTime);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::LevelControl::Commands::Ids::Stop: {
|
|
expectArgumentCount = 2;
|
|
uint8_t optionMask;
|
|
uint8_t optionOverride;
|
|
bool argExists[2];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 2)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(optionMask);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(optionOverride);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfLevelControlClusterStopCallback(aEndpointId, apCommandObj, optionMask, optionOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::LevelControl::Commands::Ids::StopWithOnOff: {
|
|
|
|
wasHandled = emberAfLevelControlClusterStopWithOnOffCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::LevelControl::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::LevelControl::Id, aCommandId, (CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace LevelControl
|
|
|
|
namespace NetworkCommissioning {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::NetworkCommissioning::Commands::Ids::AddThreadNetwork: {
|
|
expectArgumentCount = 3;
|
|
chip::ByteSpan operationalDataset;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(operationalDataset);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfNetworkCommissioningClusterAddThreadNetworkCallback(aEndpointId, apCommandObj,
|
|
operationalDataset, breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::NetworkCommissioning::Commands::Ids::AddWiFiNetwork: {
|
|
expectArgumentCount = 4;
|
|
chip::ByteSpan ssid;
|
|
chip::ByteSpan credentials;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(ssid);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(credentials);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfNetworkCommissioningClusterAddWiFiNetworkCallback(aEndpointId, apCommandObj, ssid, credentials,
|
|
breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::NetworkCommissioning::Commands::Ids::DisableNetwork: {
|
|
expectArgumentCount = 3;
|
|
chip::ByteSpan networkID;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(networkID);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfNetworkCommissioningClusterDisableNetworkCallback(aEndpointId, apCommandObj, networkID,
|
|
breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::NetworkCommissioning::Commands::Ids::EnableNetwork: {
|
|
expectArgumentCount = 3;
|
|
chip::ByteSpan networkID;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(networkID);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfNetworkCommissioningClusterEnableNetworkCallback(aEndpointId, apCommandObj, networkID,
|
|
breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::NetworkCommissioning::Commands::Ids::GetLastNetworkCommissioningResult: {
|
|
expectArgumentCount = 1;
|
|
uint32_t timeoutMs;
|
|
bool argExists[1];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 1)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfNetworkCommissioningClusterGetLastNetworkCommissioningResultCallback(aEndpointId, apCommandObj,
|
|
timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::NetworkCommissioning::Commands::Ids::RemoveNetwork: {
|
|
expectArgumentCount = 3;
|
|
chip::ByteSpan NetworkID;
|
|
uint64_t Breadcrumb;
|
|
uint32_t TimeoutMs;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(NetworkID);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(Breadcrumb);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(TimeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfNetworkCommissioningClusterRemoveNetworkCallback(aEndpointId, apCommandObj, NetworkID,
|
|
Breadcrumb, TimeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::NetworkCommissioning::Commands::Ids::ScanNetworks: {
|
|
expectArgumentCount = 3;
|
|
chip::ByteSpan ssid;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(ssid);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled =
|
|
emberAfNetworkCommissioningClusterScanNetworksCallback(aEndpointId, apCommandObj, ssid, breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::NetworkCommissioning::Commands::Ids::UpdateThreadNetwork: {
|
|
expectArgumentCount = 3;
|
|
chip::ByteSpan operationalDataset;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[3];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 3)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(operationalDataset);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 3 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfNetworkCommissioningClusterUpdateThreadNetworkCallback(
|
|
aEndpointId, apCommandObj, operationalDataset, breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::NetworkCommissioning::Commands::Ids::UpdateWiFiNetwork: {
|
|
expectArgumentCount = 4;
|
|
chip::ByteSpan ssid;
|
|
chip::ByteSpan credentials;
|
|
uint64_t breadcrumb;
|
|
uint32_t timeoutMs;
|
|
bool argExists[4];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 4)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(ssid);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(credentials);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(breadcrumb);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(timeoutMs);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfNetworkCommissioningClusterUpdateWiFiNetworkCallback(aEndpointId, apCommandObj, ssid,
|
|
credentials, breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::NetworkCommissioning::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::NetworkCommissioning::Id, aCommandId,
|
|
(CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace NetworkCommissioning
|
|
|
|
namespace OnOff {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::OnOff::Commands::Ids::Off: {
|
|
|
|
wasHandled = emberAfOnOffClusterOffCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
case Clusters::OnOff::Commands::Ids::On: {
|
|
|
|
wasHandled = emberAfOnOffClusterOnCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
case Clusters::OnOff::Commands::Ids::Toggle: {
|
|
|
|
wasHandled = emberAfOnOffClusterToggleCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::OnOff::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::OnOff::Id, aCommandId, (CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace OnOff
|
|
|
|
namespace OperationalCredentials {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::OperationalCredentials::Commands::Ids::AddNOC: {
|
|
expectArgumentCount = 5;
|
|
chip::ByteSpan NOCValue;
|
|
chip::ByteSpan ICACValue;
|
|
chip::ByteSpan IPKValue;
|
|
chip::NodeId CaseAdminNode;
|
|
uint16_t AdminVendorId;
|
|
bool argExists[5];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 5)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(NOCValue);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(ICACValue);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(IPKValue);
|
|
break;
|
|
case 3:
|
|
TLVUnpackError = aDataTlv.Get(CaseAdminNode);
|
|
break;
|
|
case 4:
|
|
TLVUnpackError = aDataTlv.Get(AdminVendorId);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 5 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfOperationalCredentialsClusterAddNOCCallback(aEndpointId, apCommandObj, NOCValue, ICACValue,
|
|
IPKValue, CaseAdminNode, AdminVendorId);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::AddTrustedRootCertificate: {
|
|
expectArgumentCount = 1;
|
|
chip::ByteSpan RootCertificate;
|
|
bool argExists[1];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 1)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(RootCertificate);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfOperationalCredentialsClusterAddTrustedRootCertificateCallback(aEndpointId, apCommandObj,
|
|
RootCertificate);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::OpCSRRequest: {
|
|
expectArgumentCount = 1;
|
|
chip::ByteSpan CSRNonce;
|
|
bool argExists[1];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 1)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(CSRNonce);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfOperationalCredentialsClusterOpCSRRequestCallback(aEndpointId, apCommandObj, CSRNonce);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::RemoveFabric: {
|
|
expectArgumentCount = 1;
|
|
uint8_t FabricIndex;
|
|
bool argExists[1];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 1)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(FabricIndex);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfOperationalCredentialsClusterRemoveFabricCallback(aEndpointId, apCommandObj, FabricIndex);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::RemoveTrustedRootCertificate: {
|
|
expectArgumentCount = 1;
|
|
chip::ByteSpan TrustedRootIdentifier;
|
|
bool argExists[1];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 1)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(TrustedRootIdentifier);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfOperationalCredentialsClusterRemoveTrustedRootCertificateCallback(aEndpointId, apCommandObj,
|
|
TrustedRootIdentifier);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::UpdateFabricLabel: {
|
|
expectArgumentCount = 1;
|
|
const uint8_t * Label;
|
|
bool argExists[1];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 1)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
// TODO(#5542): The cluster handlers should accept a ByteSpan for all string types.
|
|
TLVUnpackError = aDataTlv.GetDataPtr(Label);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 1 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfOperationalCredentialsClusterUpdateFabricLabelCallback(aEndpointId, apCommandObj,
|
|
const_cast<uint8_t *>(Label));
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::UpdateNOC: {
|
|
expectArgumentCount = 2;
|
|
chip::ByteSpan NOCValue;
|
|
chip::ByteSpan ICACValue;
|
|
bool argExists[2];
|
|
|
|
memset(argExists, 0, sizeof argExists);
|
|
|
|
while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR)
|
|
{
|
|
// Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element.
|
|
// Skip this element if it is not a ContextTag, not consider it as an error if other values are valid.
|
|
if (!TLV::IsContextTag(aDataTlv.GetTag()))
|
|
{
|
|
continue;
|
|
}
|
|
currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag());
|
|
if (currentDecodeTagId < 2)
|
|
{
|
|
if (argExists[currentDecodeTagId])
|
|
{
|
|
ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag()));
|
|
TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
argExists[currentDecodeTagId] = true;
|
|
validArgumentCount++;
|
|
}
|
|
}
|
|
switch (currentDecodeTagId)
|
|
{
|
|
case 0:
|
|
TLVUnpackError = aDataTlv.Get(NOCValue);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(ICACValue);
|
|
break;
|
|
default:
|
|
// Unsupported tag, ignore it.
|
|
ChipLogProgress(Zcl, "Unknown TLV tag during processing.");
|
|
break;
|
|
}
|
|
if (CHIP_NO_ERROR != TLVUnpackError)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (CHIP_END_OF_TLV == TLVError)
|
|
{
|
|
// CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error.
|
|
TLVError = CHIP_NO_ERROR;
|
|
}
|
|
|
|
if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 2 == validArgumentCount)
|
|
{
|
|
wasHandled = emberAfOperationalCredentialsClusterUpdateNOCCallback(aEndpointId, apCommandObj, NOCValue, ICACValue);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::OperationalCredentials::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::OperationalCredentials::Id, aCommandId,
|
|
(CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace OperationalCredentials
|
|
|
|
namespace SoftwareDiagnostics {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::SoftwareDiagnostics::Commands::Ids::ResetWatermarks: {
|
|
|
|
wasHandled = emberAfSoftwareDiagnosticsClusterResetWatermarksCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::SoftwareDiagnostics::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::SoftwareDiagnostics::Id, aCommandId,
|
|
(CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace SoftwareDiagnostics
|
|
|
|
namespace ThreadNetworkDiagnostics {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::ThreadNetworkDiagnostics::Commands::Ids::ResetCounts: {
|
|
|
|
wasHandled = emberAfThreadNetworkDiagnosticsClusterResetCountsCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::ThreadNetworkDiagnostics::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::ThreadNetworkDiagnostics::Id, aCommandId,
|
|
(CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace ThreadNetworkDiagnostics
|
|
|
|
namespace WiFiNetworkDiagnostics {
|
|
|
|
void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv)
|
|
{
|
|
// We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV
|
|
// When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error.
|
|
// Any error value TLVUnpackError means we have received an illegal value.
|
|
// The following variables are used for all commands to save code size.
|
|
CHIP_ERROR TLVError = CHIP_NO_ERROR;
|
|
CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR;
|
|
uint32_t validArgumentCount = 0;
|
|
uint32_t expectArgumentCount = 0;
|
|
uint32_t currentDecodeTagId = 0;
|
|
bool wasHandled = false;
|
|
{
|
|
switch (aCommandId)
|
|
{
|
|
case Clusters::WiFiNetworkDiagnostics::Commands::Ids::ResetCounts: {
|
|
|
|
wasHandled = emberAfWiFiNetworkDiagnosticsClusterResetCountsCallback(aEndpointId, apCommandObj);
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::WiFiNetworkDiagnostics::Id, aCommandId);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::WiFiNetworkDiagnostics::Id, aCommandId,
|
|
(CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogProgress(Zcl,
|
|
"Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT
|
|
", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32,
|
|
validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId);
|
|
// A command with no arguments would never write currentDecodeTagId. If
|
|
// progress logging is also disabled, it would look unused. Silence that
|
|
// warning.
|
|
UNUSED_VAR(currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace WiFiNetworkDiagnostics
|
|
|
|
} // namespace clusters
|
|
|
|
void DispatchSingleClusterCommand(ClusterId aClusterId, CommandId aCommandId, EndpointId aEndPointId, TLV::TLVReader & aReader,
|
|
CommandHandler * apCommandObj)
|
|
{
|
|
ChipLogDetail(Zcl, "Received Cluster Command: Cluster=" ChipLogFormatMEI " Command=" ChipLogFormatMEI " Endpoint=%" PRIx16,
|
|
ChipLogValueMEI(aClusterId), ChipLogValueMEI(aCommandId), aEndPointId);
|
|
Compatibility::SetupEmberAfObjects(apCommandObj, aClusterId, aCommandId, aEndPointId);
|
|
TLV::TLVType dataTlvType;
|
|
SuccessOrExit(aReader.EnterContainer(dataTlvType));
|
|
switch (aClusterId)
|
|
{
|
|
case Clusters::AdministratorCommissioning::Id:
|
|
clusters::AdministratorCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::ColorControl::Id:
|
|
clusters::ColorControl::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::DiagnosticLogs::Id:
|
|
clusters::DiagnosticLogs::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::GeneralCommissioning::Id:
|
|
clusters::GeneralCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::LevelControl::Id:
|
|
clusters::LevelControl::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::NetworkCommissioning::Id:
|
|
clusters::NetworkCommissioning::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::OnOff::Id:
|
|
clusters::OnOff::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::OperationalCredentials::Id:
|
|
clusters::OperationalCredentials::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::SoftwareDiagnostics::Id:
|
|
clusters::SoftwareDiagnostics::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::ThreadNetworkDiagnostics::Id:
|
|
clusters::ThreadNetworkDiagnostics::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
case Clusters::WiFiNetworkDiagnostics::Id:
|
|
clusters::WiFiNetworkDiagnostics::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader);
|
|
break;
|
|
default:
|
|
// Unrecognized cluster ID, error status will apply.
|
|
CommandPathParams returnStatusParam = { aEndPointId,
|
|
0, // GroupId
|
|
aClusterId, aCommandId, (CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogError(Zcl, "Unknown cluster %" PRIx32, aClusterId);
|
|
break;
|
|
}
|
|
exit:
|
|
Compatibility::ResetEmberAfObjects();
|
|
aReader.ExitContainer(dataTlvType);
|
|
}
|
|
|
|
void DispatchSingleClusterResponseCommand(ClusterId aClusterId, CommandId aCommandId, EndpointId aEndPointId,
|
|
TLV::TLVReader & aReader, CommandSender * apCommandObj)
|
|
{
|
|
ChipLogDetail(Zcl, "Received Cluster Command: Cluster=%" PRIx32 " Command=%" PRIx32 " Endpoint=%" PRIx16, aClusterId,
|
|
aCommandId, aEndPointId);
|
|
Compatibility::SetupEmberAfObjects(apCommandObj, aClusterId, aCommandId, aEndPointId);
|
|
TLV::TLVType dataTlvType;
|
|
SuccessOrExit(aReader.EnterContainer(dataTlvType));
|
|
switch (aClusterId)
|
|
{
|
|
default:
|
|
// Unrecognized cluster ID, error status will apply.
|
|
CommandPathParams returnStatusParam = { aEndPointId,
|
|
0, // GroupId
|
|
aClusterId, aCommandId, (CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand);
|
|
ChipLogError(Zcl, "Unknown cluster " ChipLogFormatMEI, ChipLogValueMEI(aClusterId));
|
|
break;
|
|
}
|
|
exit:
|
|
Compatibility::ResetEmberAfObjects();
|
|
aReader.ExitContainer(dataTlvType);
|
|
}
|
|
|
|
} // namespace app
|
|
} // namespace chip
|