mirror of
https://github.com/espressif/esp-matter.git
synced 2026-04-27 11:03:05 +00:00
3553 lines
149 KiB
C++
3553 lines
149 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/common/gen/af-structs.h"
|
|
#include "app/common/gen/callback.h"
|
|
#include "app/common/gen/ids/Clusters.h"
|
|
#include "app/common/gen/ids/Commands.h"
|
|
#include "app/util/util.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 {
|
|
|
|
// Cluster specific command parsing
|
|
|
|
namespace clusters {
|
|
|
|
namespace ColorControl {
|
|
|
|
void DispatchServerCommand(app::Command * 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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterColorLoopSetCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfColorControlClusterEnhancedMoveHueCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterEnhancedMoveToHueCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterEnhancedMoveToHueAndSaturationCallback(
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterEnhancedStepHueCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterMoveColorCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterMoveColorTemperatureCallback(
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterMoveHueCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfColorControlClusterMoveSaturationCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterMoveToColorCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterMoveToColorTemperatureCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterMoveToHueCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterMoveToHueAndSaturationCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterMoveToSaturationCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterStepColorCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterStepColorTemperatureCallback(
|
|
apCommandObj, stepMode, stepSize, transitionTime, colorTemperatureMinimum, colorTemperatureMaximum, optionsMask,
|
|
optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::StepHue: {
|
|
expectArgumentCount = 5;
|
|
uint8_t stepMode;
|
|
uint8_t stepSize;
|
|
uint8_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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterStepHueCallback(apCommandObj, stepMode, stepSize, transitionTime,
|
|
optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::ColorControl::Commands::Ids::StepSaturation: {
|
|
expectArgumentCount = 5;
|
|
uint8_t stepMode;
|
|
uint8_t stepSize;
|
|
uint8_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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterStepSaturationCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfColorControlClusterStopMoveStepCallback(apCommandObj, optionsMask, optionsOverride);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::ColorControl::Id, aCommandId,
|
|
(chip::app::CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id,
|
|
Protocols::InteractionModel::ProtocolCode::UnsupportedCommand);
|
|
ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::ColorControl::Id);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::ColorControl::Id, aCommandId,
|
|
(chip::app::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, TLVUnpackError, currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace ColorControl
|
|
|
|
namespace GeneralCommissioning {
|
|
|
|
void DispatchServerCommand(app::Command * 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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfGeneralCommissioningClusterArmFailSafeCallback(apCommandObj, expiryLengthSeconds, breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::GeneralCommissioning::Commands::Ids::CommissioningComplete: {
|
|
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfGeneralCommissioningClusterCommissioningCompleteCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfGeneralCommissioningClusterSetRegulatoryConfigCallback(
|
|
apCommandObj, location, const_cast<uint8_t *>(countryCode), breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::GeneralCommissioning::Id, aCommandId,
|
|
(chip::app::CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id,
|
|
Protocols::InteractionModel::ProtocolCode::UnsupportedCommand);
|
|
ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::GeneralCommissioning::Id);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::GeneralCommissioning::Id, aCommandId,
|
|
(chip::app::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, TLVUnpackError, currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace GeneralCommissioning
|
|
|
|
namespace LevelControl {
|
|
|
|
void DispatchServerCommand(app::Command * 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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfLevelControlClusterMoveCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfLevelControlClusterMoveToLevelCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfLevelControlClusterMoveToLevelWithOnOffCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfLevelControlClusterMoveWithOnOffCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfLevelControlClusterStepCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfLevelControlClusterStepWithOnOffCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfLevelControlClusterStopCallback(apCommandObj, optionMask, optionOverride);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::LevelControl::Commands::Ids::StopWithOnOff: {
|
|
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfLevelControlClusterStopWithOnOffCallback(apCommandObj);
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::LevelControl::Id, aCommandId,
|
|
(chip::app::CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id,
|
|
Protocols::InteractionModel::ProtocolCode::UnsupportedCommand);
|
|
ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::LevelControl::Id);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::LevelControl::Id, aCommandId,
|
|
(chip::app::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, TLVUnpackError, currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace LevelControl
|
|
|
|
namespace NetworkCommissioning {
|
|
|
|
void DispatchServerCommand(app::Command * 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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
operationalDataset = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfNetworkCommissioningClusterAddThreadNetworkCallback(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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
ssid = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
break;
|
|
case 1: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
credentials = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfNetworkCommissioningClusterAddWiFiNetworkCallback(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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
networkID = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfNetworkCommissioningClusterDisableNetworkCallback(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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
networkID = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfNetworkCommissioningClusterEnableNetworkCallback(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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfNetworkCommissioningClusterGetLastNetworkCommissioningResultCallback(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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
NetworkID = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfNetworkCommissioningClusterRemoveNetworkCallback(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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
ssid = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfNetworkCommissioningClusterScanNetworksCallback(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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
operationalDataset = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfNetworkCommissioningClusterUpdateThreadNetworkCallback(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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
ssid = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
break;
|
|
case 1: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
credentials = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfNetworkCommissioningClusterUpdateWiFiNetworkCallback(apCommandObj, ssid, credentials,
|
|
breadcrumb, timeoutMs);
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::NetworkCommissioning::Id, aCommandId,
|
|
(chip::app::CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id,
|
|
Protocols::InteractionModel::ProtocolCode::UnsupportedCommand);
|
|
ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::NetworkCommissioning::Id);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::NetworkCommissioning::Id, aCommandId,
|
|
(chip::app::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, TLVUnpackError, currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace NetworkCommissioning
|
|
|
|
namespace OnOff {
|
|
|
|
void DispatchServerCommand(app::Command * 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: {
|
|
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOnOffClusterOffCallback(apCommandObj);
|
|
break;
|
|
}
|
|
case Clusters::OnOff::Commands::Ids::On: {
|
|
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOnOffClusterOnCallback(apCommandObj);
|
|
break;
|
|
}
|
|
case Clusters::OnOff::Commands::Ids::Toggle: {
|
|
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOnOffClusterToggleCallback(apCommandObj);
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::OnOff::Id, aCommandId,
|
|
(chip::app::CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id,
|
|
Protocols::InteractionModel::ProtocolCode::UnsupportedCommand);
|
|
ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::OnOff::Id);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::OnOff::Id, aCommandId,
|
|
(chip::app::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, TLVUnpackError, currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace OnOff
|
|
|
|
namespace OperationalCredentials {
|
|
|
|
void DispatchServerCommand(app::Command * 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::AddOpCert: {
|
|
expectArgumentCount = 4;
|
|
chip::ByteSpan NOCArray;
|
|
chip::ByteSpan IPKValue;
|
|
chip::NodeId CaseAdminNode;
|
|
uint16_t AdminVendorId;
|
|
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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
NOCArray = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
break;
|
|
case 1: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
IPKValue = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(CaseAdminNode);
|
|
break;
|
|
case 3:
|
|
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 && 4 == validArgumentCount)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOperationalCredentialsClusterAddOpCertCallback(apCommandObj, NOCArray, 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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
RootCertificate = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOperationalCredentialsClusterAddTrustedRootCertificateCallback(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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
CSRNonce = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOperationalCredentialsClusterOpCSRRequestCallback(apCommandObj, CSRNonce);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::RemoveAllFabrics: {
|
|
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOperationalCredentialsClusterRemoveAllFabricsCallback(apCommandObj);
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::RemoveFabric: {
|
|
expectArgumentCount = 3;
|
|
chip::FabricId FabricId;
|
|
chip::NodeId NodeId;
|
|
uint16_t VendorId;
|
|
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(FabricId);
|
|
break;
|
|
case 1:
|
|
TLVUnpackError = aDataTlv.Get(NodeId);
|
|
break;
|
|
case 2:
|
|
TLVUnpackError = aDataTlv.Get(VendorId);
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOperationalCredentialsClusterRemoveFabricCallback(apCommandObj, FabricId, NodeId, VendorId);
|
|
}
|
|
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: {
|
|
const uint8_t * data = nullptr;
|
|
TLVUnpackError = aDataTlv.GetDataPtr(data);
|
|
TrustedRootIdentifier = chip::ByteSpan(data, aDataTlv.GetLength());
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfOperationalCredentialsClusterRemoveTrustedRootCertificateCallback(apCommandObj, TrustedRootIdentifier);
|
|
}
|
|
break;
|
|
}
|
|
case Clusters::OperationalCredentials::Commands::Ids::SetFabric: {
|
|
expectArgumentCount = 1;
|
|
uint16_t VendorId;
|
|
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(VendorId);
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled = emberAfOperationalCredentialsClusterSetFabricCallback(apCommandObj, VendorId);
|
|
}
|
|
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)
|
|
{
|
|
// TODO(#5098) We should pass the Command Object and EndpointId to the cluster callbacks.
|
|
wasHandled =
|
|
emberAfOperationalCredentialsClusterUpdateFabricLabelCallback(apCommandObj, const_cast<uint8_t *>(Label));
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
// Unrecognized command ID, error status will apply.
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::OperationalCredentials::Id, aCommandId,
|
|
(chip::app::CommandPathFlags::kEndpointIdValid) };
|
|
apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kNotFound,
|
|
Protocols::SecureChannel::Id,
|
|
Protocols::InteractionModel::ProtocolCode::UnsupportedCommand);
|
|
ChipLogError(Zcl, "Unknown command %" PRIx32 " for cluster %" PRIx32, aCommandId, Clusters::OperationalCredentials::Id);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled)
|
|
{
|
|
chip::app::CommandPathParams returnStatusParam = { aEndpointId,
|
|
0, // GroupId
|
|
Clusters::OperationalCredentials::Id, aCommandId,
|
|
(chip::app::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, TLVUnpackError, currentDecodeTagId);
|
|
}
|
|
}
|
|
|
|
} // namespace OperationalCredentials
|
|
|
|
} // namespace clusters
|
|
|
|
void DispatchSingleClusterCommand(chip::ClusterId aClusterId, chip::CommandId aCommandId, chip::EndpointId aEndPointId,
|
|
chip::TLV::TLVReader & aReader, Command * 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)
|
|
{
|
|
case Clusters::ColorControl::Id:
|
|
clusters::ColorControl::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;
|
|
default:
|
|
// Unrecognized cluster ID, error status will apply.
|
|
chip::app::CommandPathParams returnStatusParam = { aEndPointId,
|
|
0, // GroupId
|
|
aClusterId, aCommandId,
|
|
(chip::app::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);
|
|
}
|
|
|
|
} // namespace app
|
|
} // namespace chip
|