From 7abe3b8457053a7859eb03f1f58250b9d9420777 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Mon, 7 Nov 2022 16:30:11 -0500 Subject: [PATCH 01/79] Implementation of persistant storage of scene table along with test. --- scripts/examples/gn_efr32_example.sh | 11 +- src/app/chip_data_model.gni | 5 + .../clusters/scenes/ExtensionFieldsSets.cpp | 95 ++++ src/app/clusters/scenes/ExtensionFieldsSets.h | 100 ++++ src/app/clusters/scenes/SceneTable.h | 243 +++++++++ src/app/clusters/scenes/SceneTableImpl.cpp | 467 ++++++++++++++++++ src/app/clusters/scenes/SceneTableImpl.h | 109 ++++ src/lib/core/DataModelTypes.h | 1 + src/lib/core/SceneId.h | 66 +++ src/lib/support/DefaultStorageKeyAllocator.h | 13 +- src/lib/support/TestSceneTable.h | 140 ++++++ 11 files changed, 1248 insertions(+), 2 deletions(-) create mode 100644 src/app/clusters/scenes/ExtensionFieldsSets.cpp create mode 100644 src/app/clusters/scenes/ExtensionFieldsSets.h create mode 100644 src/app/clusters/scenes/SceneTable.h create mode 100644 src/app/clusters/scenes/SceneTableImpl.cpp create mode 100644 src/app/clusters/scenes/SceneTableImpl.h create mode 100644 src/lib/core/SceneId.h create mode 100644 src/lib/support/TestSceneTable.h diff --git a/scripts/examples/gn_efr32_example.sh b/scripts/examples/gn_efr32_example.sh index 09bdf90afb0312..5e5a9bdef2e32e 100755 --- a/scripts/examples/gn_efr32_example.sh +++ b/scripts/examples/gn_efr32_example.sh @@ -137,6 +137,10 @@ else shift while [ $# -gt 0 ]; do case $1 in + --clean) + DIR_CLEAN=true + shift + ;; --wifi) if [ -z "$2" ]; then echo "--wifi requires rs9116 or SiWx917 or wf200" @@ -147,7 +151,7 @@ else elif [ "$2" = "SiWx917" ]; then optArgs+="use_SiWx917=true " elif [ "$2" = "wf200" ]; then - optArgs+="use_wf200=true " + optArgs+="use_wf200=true" else echo "Wifi usage: --wifi rs9116|SiWx917|wf200" exit 1 @@ -219,6 +223,11 @@ else BUILD_DIR=$OUTDIR/$SILABS_BOARD echo BUILD_DIR="$BUILD_DIR" + + if [ "$DIR_CLEAN" == true ]; then + rm -rf "$BUILD_DIR" + fi + if [ "$USE_WIFI" == true ]; then gn gen --check --fail-on-unused-args --export-compile-commands --root="$ROOT" --dotfile="$ROOT"/build_for_wifi_gnfile.gn --args="silabs_board=\"$SILABS_BOARD\" $optArgs" "$BUILD_DIR" else diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index 1233b8458c101c..cfbd9c5911492c 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -157,6 +157,11 @@ template("chip_data_model") { "${_app_root}/clusters/identify-server/identify-server.h", "${_app_root}/clusters/level-control/level-control.h", "${_app_root}/clusters/on-off-server/on-off-server.h", + "${_app_root}/clusters/scenes/ExtensionFieldsSets.cpp", + "${_app_root}/clusters/scenes/ExtensionFieldsSets.h", + "${_app_root}/clusters/scenes/SceneTable.h", + "${_app_root}/clusters/scenes/SceneTableImpl.cpp", + "${_app_root}/clusters/scenes/SceneTableImpl.h", "${_app_root}/clusters/scenes/scenes-tokens.h", "${_app_root}/clusters/scenes/scenes.h", "${_app_root}/util/ClientMonitoringRegistrationTable.cpp", diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.cpp b/src/app/clusters/scenes/ExtensionFieldsSets.cpp new file mode 100644 index 00000000000000..66d578940bd266 --- /dev/null +++ b/src/app/clusters/scenes/ExtensionFieldsSets.cpp @@ -0,0 +1,95 @@ +/* + * + * Copyright (c) 2023 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ + +#include "ExtensionFieldsSets.h" + +namespace chip { +namespace scenes { + +ExtensionFieldsSets::ExtensionFieldsSets() +{ + // check if any of the clusters with scene attributes are enabled + if (this->kExentesionFieldsSetsSize == 1) + { + // a size of 1 byte indicates an empty struct, or a struct that only contains : + // the on-off cluster + // the Mode select cluster + // the door lock cluster +#ifdef ZCL_USING_ON_OFF_CLUSTER_SERVER + this->enabledFieldSets.onOff = false; + +#elif defined(ZCL_USING_MODE_SELECT_CLUSTER_SERVER) + this->enabledFieldSets.currentMode = 0; +#elif defined(ZCL_USING_DOOR_LOCK_CLUSTER_SERVER) + this->enabledFieldSets.lockState = 0; +#else + this->empty = true; +#endif + } + else if (this->kExentesionFieldsSetsSize > 1) + { + memset(&this->enabledFieldSets, 0, kExentesionFieldsSetsSize); + } +} + +CHIP_ERROR ExtensionFieldsSets::Serialize(TLV::TLVWriter & writer) const +{ + if (!this->empty) + { + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); + + ReturnErrorOnFailure( + writer.PutBytes(TagEnabledFielsSets(), (uint8_t *) &this->enabledFieldSets, kExentesionFieldsSetsSize)); + + return writer.EndContainer(container); + } + else + { + return CHIP_NO_ERROR; + } +} + +CHIP_ERROR ExtensionFieldsSets::Deserialize(TLV::TLVReader & reader) +{ + if (!this->empty) + { + TLV::TLVType container; + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(reader.Next(TagEnabledFielsSets())); + ReturnErrorOnFailure(reader.GetBytes((uint8_t *) &this->enabledFieldSets, kExentesionFieldsSetsSize)); + + return reader.ExitContainer(container); + } + else + { + return CHIP_NO_ERROR; + } +} +void ExtensionFieldsSets::clear() +{ + if (!this->empty) + { + memset(&this->enabledFieldSets, 0, sizeof(this->enabledFieldSets)); + } +} + +} // namespace scenes + +} // namespace chip \ No newline at end of file diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldsSets.h new file mode 100644 index 00000000000000..cae1d41499ce5a --- /dev/null +++ b/src/app/clusters/scenes/ExtensionFieldsSets.h @@ -0,0 +1,100 @@ +/** + * + * Copyright (c) 2023 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include + +namespace chip { +namespace scenes { + +typedef struct fieldSets_s +{ +#ifdef ZCL_USING_ON_OFF_CLUSTER_SERVER + bool onOff; +#endif + +#ifdef ZCL_USING_LEVEL_CONTROL_CLUSTER_SERVER + uint8_t currentLevel; + uint16_t currentFrequency; +#endif + +#ifdef ZCL_USING_MODE_SELECT_CLUSTER_SERVER + uint8_t currentMode; +#endif + +#ifdef ZCL_USING_COLOR_CONTROL_CLUSTER_SERVER + uint8_t currentSaturation; + uint16_t currentX; + uint16_t currentY; + uint16_t colorTemperatureMireds; + uint16_t enhancedCurrentHue; + uint8_t enhancedColorMode; + uint8_t colorLoopActive; + uint8_t colorLoopDirection; + uint16_t colorLoopTime; +#endif + +#ifdef ZCL_USING_THERMOSTAT_CLUSTER_SERVER + uint16_t occupiedCoolingSetpoint; + uint16_t occupiedHeatingSetpoint; + uint8_t systemMode; +#endif + +#ifdef ZCL_USING_DOOR_LOCK_CLUSTER_SERVER + uint8_t lockState; +#endif + +#ifdef ZCL_USING_WINDOW_COVERING_CLUSTER_SERVER + uint8_t currentPositionLiftPercentage; + uint8_t currentPositionTiltPercentage; + uint8_t targetPositionLiftPercent100ths; + uint8_t targetPositionTiltPercent100ths; +#endif +} fieldSets_t; + +class ExtensionFieldsSets +{ +public: + static constexpr size_t kExentesionFieldsSetsSize = sizeof(fieldSets_t); + static constexpr TLV::Tag TagEnabledFielsSets() { return TLV::ContextTag(1); } + fieldSets_t enabledFieldSets; + bool empty = false; + + ExtensionFieldsSets(); + virtual ~ExtensionFieldsSets() = default; + + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const; + CHIP_ERROR Deserialize(TLV::TLVReader & reader); + + void clear(); + + bool operator==(const ExtensionFieldsSets & other) + { + return (!memcmp(&this->enabledFieldSets, &other.enabledFieldSets, kExentesionFieldsSetsSize)); + } + + void operator=(const ExtensionFieldsSets & other) + { + memcpy(&this->enabledFieldSets, &other.enabledFieldSets, kExentesionFieldsSetsSize); + } +}; +} // namespace scenes +} // namespace chip diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h new file mode 100644 index 00000000000000..82f89ca3d55152 --- /dev/null +++ b/src/app/clusters/scenes/SceneTable.h @@ -0,0 +1,243 @@ +/* + * + * Copyright (c) 2022 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ +#pragma once + +#include +#include +#include +#include + +namespace chip { +namespace scenes { + +class SceneTable +{ +public: + static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_GROUP_CONCURRENT_ITERATORS; + static constexpr size_t kSceneNameMax = ZCL_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; + static constexpr uint8_t kMaxScenePerFabric = SCENE_MAX_PER_FABRIC; + /// @brief struct used to identify a scene in storage by 3 ids, endpoint, group and scene + struct SceneStorageId + { + static constexpr TLV::Tag TagFirstSceneEndpointID() { return TLV::ContextTag(1); } + static constexpr TLV::Tag TagFirstSceneGroupID() { return TLV::ContextTag(2); } + static constexpr TLV::Tag TagFirstSceneID() { return TLV::ContextTag(3); } + + // Identifies endpoint to which this scene applies to + EndpointId sceneEndpointId = kInvalidEndpointId; + // Identifies group within the scope of the given fabric + SceneGroupID sceneGroupId = kGlobalGroupSceneId; + SceneId sceneId = kUndefinedSceneId; + + SceneStorageId() = default; + SceneStorageId(EndpointId endpoint, SceneId id, SceneGroupID groupId = kGlobalGroupSceneId) : + sceneEndpointId(endpoint), sceneGroupId(groupId), sceneId(id) + {} + SceneStorageId(const SceneStorageId & storageId) : + sceneEndpointId(storageId.sceneEndpointId), sceneGroupId(storageId.sceneGroupId), sceneId(storageId.sceneId) + {} + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const + { + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); + + ReturnErrorOnFailure(writer.Put(TagFirstSceneEndpointID(), static_cast(this->sceneEndpointId))); + ReturnErrorOnFailure(writer.Put(TagFirstSceneGroupID(), static_cast(this->sceneGroupId))); + ReturnErrorOnFailure(writer.Put(TagFirstSceneID(), static_cast(this->sceneId))); + + return writer.EndContainer(container); + } + CHIP_ERROR Deserialize(TLV::TLVReader & reader) + { + TLV::TLVType container; + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(reader.Next(TagFirstSceneEndpointID())); + ReturnErrorOnFailure(reader.Get(this->sceneEndpointId)); + ReturnErrorOnFailure(reader.Next(TagFirstSceneGroupID())); + ReturnErrorOnFailure(reader.Get(this->sceneGroupId)); + ReturnErrorOnFailure(reader.Next(TagFirstSceneID())); + ReturnErrorOnFailure(reader.Get(this->sceneId)); + + return reader.ExitContainer(container); + } + + void clear() + { + sceneEndpointId = kInvalidEndpointId; + sceneGroupId = kGlobalGroupSceneId; + sceneId = kUndefinedSceneId; + } + bool operator==(const SceneStorageId & other) + { + return (this->sceneEndpointId == other.sceneEndpointId && this->sceneGroupId == other.sceneGroupId && + this->sceneId == other.sceneId); + } + void operator=(const SceneStorageId & other) + { + this->sceneEndpointId = other.sceneEndpointId; + this->sceneGroupId = other.sceneGroupId; + this->sceneId = other.sceneId; + } + }; + + /// @brief struct used to store data held in a scene + struct SceneData + { + static constexpr TLV::Tag TagSceneName() { return TLV::ContextTag(1); } + static constexpr TLV::Tag TagSceneTransitionTime() { return TLV::ContextTag(2); } + static constexpr TLV::Tag TagSceneTransitionTime100() { return TLV::ContextTag(3); } + + char name[kSceneNameMax] = { 0 }; + SceneTransitionTime sceneTransitionTime = 0; + ExtensionFieldsSets extentsionFieldsSets; + TransitionTime100ms transitionTime100 = 0; + + SceneData() = default; + SceneData(const char * sceneName, SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : + sceneTransitionTime(time), transitionTime100(time100ms) + { + SetName(sceneName); + } + SceneData(const char * sceneName, ExtensionFieldsSets fields, SceneTransitionTime time = 0, + TransitionTime100ms time100ms = 0) : + sceneTransitionTime(time), + transitionTime100(time100ms) + { + SetName(sceneName); + extentsionFieldsSets = fields; + } + SceneData(const SceneData & data) : sceneTransitionTime(data.sceneTransitionTime), transitionTime100(data.transitionTime100) + { + SetName(data.name); + extentsionFieldsSets = data.extentsionFieldsSets; + } + + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const + { + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); + + size_t name_size = strnlen(this->name, kSceneNameMax); + ReturnErrorOnFailure(writer.PutString(TagSceneName(), this->name, static_cast(name_size))); + ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime(), static_cast(this->sceneTransitionTime))); + ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime100(), static_cast(this->transitionTime100))); + ReturnErrorOnFailure(this->extentsionFieldsSets.Serialize(writer)); + + return writer.EndContainer(container); + } + CHIP_ERROR Deserialize(TLV::TLVReader & reader) + { + TLV::TLVType container; + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(reader.Next(TagSceneName())); + ReturnErrorOnFailure(reader.GetString(this->name, sizeof(this->name))); + size_t name_size = strnlen(this->name, kSceneNameMax); // TODO : verify use of strnlen is ok + this->name[name_size] = 0; // Putting a null terminator + ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime())); + ReturnErrorOnFailure(reader.Get(this->sceneTransitionTime)); + ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime100())); + ReturnErrorOnFailure(reader.Get(this->transitionTime100)); + ReturnErrorOnFailure(this->extentsionFieldsSets.Deserialize(reader)); + + return reader.ExitContainer(container); + } + void SetName(const char * sceneName) + { + if (nullptr == sceneName) + { + name[0] = 0; + } + else + { + Platform::CopyString(name, sceneName); + } + } + + void clear() + { + this->SetName(nullptr); + sceneTransitionTime = 0; + transitionTime100 = 0; + extentsionFieldsSets.clear(); + } + + bool operator==(const SceneData & other) + { + return (!strncmp(this->name, other.name, kSceneNameMax) && (this->sceneTransitionTime == other.sceneTransitionTime) && + (this->transitionTime100 == other.transitionTime100) && + (this->extentsionFieldsSets == other.extentsionFieldsSets)); + } + + void operator=(const SceneData & other) + { + this->SetName(other.name); + this->extentsionFieldsSets = other.extentsionFieldsSets; + this->sceneTransitionTime = other.sceneTransitionTime; + this->transitionTime100 = other.transitionTime100; + } + }; + + /// @brief Struct combining both ID and data of a table entry + struct SceneTableEntry + { + + // ID + SceneStorageId storageId; + + // DATA + SceneData storageData; + + SceneTableEntry() = default; + SceneTableEntry(SceneStorageId id) : storageId(id) {} + SceneTableEntry(const SceneStorageId id, const SceneData data) : storageId(id), storageData(data) {} + + bool operator==(const SceneTableEntry & other) { return (this->storageId == other.storageId); } + + void operator=(const SceneTableEntry & other) + { + this->storageId = other.storageId; + this->storageData = other.storageData; + } + }; + + SceneTable(){}; + virtual ~SceneTable() = default; + + // Not copyable + SceneTable(const SceneTable &) = delete; + SceneTable & operator=(const SceneTable &) = delete; + + virtual CHIP_ERROR Init() = 0; + virtual void Finish() = 0; + + // Data + virtual CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) = 0; + virtual CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) = 0; + virtual CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) = 0; + + // Iterators + using SceneEntryIterator = CommonIterator; + + virtual SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) = 0; +}; + +} // namespace scenes +} // namespace chip diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp new file mode 100644 index 00000000000000..306c6016aa8e9a --- /dev/null +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -0,0 +1,467 @@ +/* + * + * Copyright (c) 2022 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ + +#include +#include +#include +#include + +namespace chip { +namespace scenes { + +using SceneTableEntry = SceneTableImpl::SceneTableEntry; +using SceneStorageId = SceneTableImpl::SceneStorageId; +using SceneData = SceneTableImpl::SceneData; + +struct FabricList : public CommonPersistentData::FabricList +{ + CHIP_ERROR UpdateKey(StorageKeyName & key) override + { + key = DefaultStorageKeyAllocator::SceneFabricList(); + return CHIP_NO_ERROR; + } +}; + +static constexpr size_t kPersistentBufferMax = 128; + +/** + * @brief Linked list of all scenes in a fabric, stored in persistent memory + * + * FabricSceneData is an access to a linked list of scenes + */ +struct FabricSceneData : public PersistentData +{ + // static constexpr TLV::Tag TagTableID() { return TLV::ContextTag(1); } + static constexpr TLV::Tag TagSceneCount() { return TLV::ContextTag(1); } + static constexpr TLV::Tag TagNext() { return TLV::ContextTag(2); } + + chip::FabricIndex fabric_index = kUndefinedFabricIndex; + SceneTableImpl::SceneStorageId first_scene; + uint16_t scene_count = 0; + FabricIndex next = kUndefinedFabricIndex; + + FabricSceneData() = default; + FabricSceneData(FabricIndex fabric) : fabric_index(fabric) {} + + CHIP_ERROR UpdateKey(StorageKeyName & key) override + { + VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX); + key = DefaultStorageKeyAllocator::FabricScenesKey(fabric_index); + return CHIP_NO_ERROR; + } + + void Clear() override + { + first_scene.clear(); + scene_count = 0; + next = kUndefinedFabricIndex; + } + + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override + { + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); + + ReturnErrorOnFailure(first_scene.Serialize(writer)); + ReturnErrorOnFailure(writer.Put(TagSceneCount(), static_cast(scene_count))); + ReturnErrorOnFailure(writer.Put(TagNext(), static_cast(next))); + + return writer.EndContainer(container); + } + + CHIP_ERROR Deserialize(TLV::TLVReader & reader) override + { + ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); + + TLV::TLVType container; + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(first_scene.Deserialize(reader)); + ReturnErrorOnFailure(reader.Next(TagSceneCount())); + ReturnErrorOnFailure(reader.Get(scene_count)); + ReturnErrorOnFailure(reader.Next(TagNext())); + ReturnErrorOnFailure(reader.Get(next)); + + return reader.ExitContainer(container); + } + + // Register the fabric in the fabrics' linked-list + CHIP_ERROR Register(PersistentStorageDelegate * storage) + { + FabricList fabric_list; + CHIP_ERROR err = fabric_list.Load(storage); + if (CHIP_ERROR_NOT_FOUND == err) + { + // New fabric list + fabric_list.first_entry = fabric_index; + fabric_list.entry_count = 1; + return fabric_list.Save(storage); + } + ReturnErrorOnFailure(err); + + // Existing fabric list, search for existing entry + FabricSceneData fabric(fabric_list.first_entry); + for (size_t i = 0; i < fabric_list.entry_count; i++) + { + err = fabric.Load(storage); + if (CHIP_NO_ERROR != err) + { + break; + } + if (fabric.fabric_index == this->fabric_index) + { + // Fabric already registered + return CHIP_NO_ERROR; + } + fabric.fabric_index = fabric.next; + } + // Add this fabric to the fabric list + this->next = fabric_list.first_entry; + fabric_list.first_entry = this->fabric_index; + fabric_list.entry_count++; + return fabric_list.Save(storage); + } + + // Remove the fabric from the fabrics' linked list + CHIP_ERROR Unregister(PersistentStorageDelegate * storage) const + { + FabricList fabric_list; + CHIP_ERROR err = fabric_list.Load(storage); + VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); + + // Existing fabric list, search for existing entry + FabricSceneData fabric(fabric_list.first_entry); + FabricSceneData prev; + + for (size_t i = 0; i < fabric_list.entry_count; i++) + { + err = fabric.Load(storage); + if (CHIP_NO_ERROR != err) + { + break; + } + if (fabric.fabric_index == this->fabric_index) + { + // Fabric found + if (i == 0) + { + // Remove first fabric + fabric_list.first_entry = this->next; + } + else + { + // Remove intermediate fabric + prev.next = this->next; + ReturnErrorOnFailure(prev.Save(storage)); + } + VerifyOrReturnError(fabric_list.entry_count > 0, CHIP_ERROR_INTERNAL); + fabric_list.entry_count--; + return fabric_list.Save(storage); + } + prev = fabric; + fabric.fabric_index = fabric.next; + } + // Fabric not in the list + return CHIP_ERROR_NOT_FOUND; + } + + // Check the fabric is registered in the fabrics' linked list + CHIP_ERROR Validate(PersistentStorageDelegate * storage) const + { + FabricList fabric_list; + ReturnErrorOnFailure(fabric_list.Load(storage)); + + // Existing fabric list, search for existing entry + FabricSceneData fabric(fabric_list.first_entry); + + for (size_t i = 0; i < fabric_list.entry_count; i++) + { + ReturnErrorOnFailure(fabric.Load(storage)); + if (fabric.fabric_index == this->fabric_index) + { + return CHIP_NO_ERROR; + } + fabric.fabric_index = fabric.next; + } + // Fabric not in the list + return CHIP_ERROR_NOT_FOUND; + } + + CHIP_ERROR Save(PersistentStorageDelegate * storage) override + { + ReturnErrorOnFailure(Register(storage)); + return PersistentData::Save(storage); + } + + CHIP_ERROR Delete(PersistentStorageDelegate * storage) override + { + ReturnErrorOnFailure(Unregister(storage)); + return PersistentData::Delete(storage); + } +}; + +struct SceneTableData : public SceneTableEntry, PersistentData +{ + FabricIndex fabric_index = kUndefinedFabricIndex; + uint8_t index = 0; + SceneStorageId next; + SceneStorageId prev; + bool first = true; + + SceneTableData() : SceneTableEntry() {} + SceneTableData(FabricIndex fabric) : fabric_index(fabric) {} + SceneTableData(FabricIndex fabric, SceneStorageId storageId) : SceneTableEntry(storageId), fabric_index(fabric) {} + SceneTableData(FabricIndex fabric, SceneStorageId storageId, SceneData data) : + SceneTableEntry(storageId, data), fabric_index(fabric) + {} + + CHIP_ERROR UpdateKey(StorageKeyName & key) override + { + VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX); + key = DefaultStorageKeyAllocator::FabricSceneKey(fabric_index, storageId.sceneEndpointId, storageId.sceneGroupId, + storageId.sceneId); + return CHIP_NO_ERROR; + } + + void Clear() override + { + storageData.clear(); + next.clear(); + } + + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override + { + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); + + ReturnErrorOnFailure(storageId.Serialize(writer)); + ReturnErrorOnFailure(storageData.Serialize(writer)); + ReturnErrorOnFailure(next.Serialize(writer)); + + return writer.EndContainer(container); + } + + CHIP_ERROR Deserialize(TLV::TLVReader & reader) override + { + ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); + + TLV::TLVType container; + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(storageId.Deserialize(reader)); + ReturnErrorOnFailure(storageData.Deserialize(reader)); + ReturnErrorOnFailure(next.Deserialize(reader)); + + return reader.ExitContainer(container); + } + + bool Find(PersistentStorageDelegate * storage, const FabricSceneData & fabric, SceneTableImpl::SceneStorageId target_scene) + { + fabric_index = fabric.fabric_index; + storageId = fabric.first_scene; + index = 0; + first = true; + + while (index < fabric.scene_count) + { + if (CHIP_NO_ERROR != Load(storage)) + { + break; + } + if (storageId == target_scene) + { + // Target index found + return true; + } + first = false; + prev = storageId; + storageId = next; + index++; + } + return false; + } +}; + +void SceneTableImpl::SetStorageDelegate(PersistentStorageDelegate * storage) +{ + VerifyOrDie(storage != nullptr); + mStorage = storage; +} + +CHIP_ERROR SceneTableImpl::Init() +{ + if (mStorage == nullptr) + { + return CHIP_ERROR_INCORRECT_STATE; + } + return CHIP_NO_ERROR; +} + +void SceneTableImpl::Finish() +{ + mSceneEntryIterators.ReleaseAll(); +} + +CHIP_ERROR SceneTableImpl::SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) +{ + VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL); + + FabricSceneData fabric(fabric_index); + SceneTableData scene; + + // Load fabric data (defaults to zero) + CHIP_ERROR err = fabric.Load(mStorage); + VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); + + if (scene.Find(mStorage, fabric, entry.storageId)) + { + // Existing scene + scene.storageData = entry.storageData; + return scene.Save(mStorage); + } + + scene.storageId = entry.storageId; + scene.storageData = entry.storageData; + + VerifyOrReturnError(fabric.scene_count < mMaxScenePerFabric, CHIP_ERROR_INVALID_LIST_LENGTH); + fabric.scene_count++; + + if (scene.first) + { + fabric.first_scene = scene.storageId; + } + else + { + // Update previous scene's next + SceneTableData prev(fabric_index, scene.prev); + ReturnErrorOnFailure(prev.Load(mStorage)); + prev.next = scene.storageId; + ReturnErrorOnFailure(prev.Save(mStorage)); + } + + ReturnErrorOnFailure(fabric.Save(mStorage)); + + return scene.Save(mStorage); +} +CHIP_ERROR SceneTableImpl::GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) +{ + FabricSceneData fabric(fabric_index); + SceneTableData scene; + + ReturnErrorOnFailure(fabric.Load(mStorage)); + VerifyOrReturnError(scene.Find(mStorage, fabric, scene_id), CHIP_ERROR_NOT_FOUND); + + entry.storageId = scene.storageId; + entry.storageData = scene.storageData; + return CHIP_NO_ERROR; +} +CHIP_ERROR SceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) +{ + FabricSceneData fabric(fabric_index); + SceneTableData scene; + + ReturnErrorOnFailure(fabric.Load(mStorage)); + VerifyOrReturnError(scene.Find(mStorage, fabric, scene_id), CHIP_ERROR_NOT_FOUND); + + ReturnErrorOnFailure(scene.Delete(mStorage)); + if (scene.first) + { + // Remove first scene + fabric.first_scene = scene.next; + } + else + { + // Update previous scene's next + SceneTableData prev(fabric_index, scene.prev); + ReturnErrorOnFailure(prev.Load(mStorage)); + prev.next = scene.next; + ReturnErrorOnFailure(prev.Save(mStorage)); + } + if (fabric.scene_count > 0) + { + fabric.scene_count--; + } + + // Update fabric info + ReturnErrorOnFailure(fabric.Save(mStorage)); + + return CHIP_NO_ERROR; +} + +SceneTableImpl::SceneEntryIterator * SceneTableImpl::IterateSceneEntry(FabricIndex fabric_index) +{ + VerifyOrReturnError(IsInitialized(), nullptr); + return mSceneEntryIterators.CreateObject(*this, fabric_index); +} + +SceneTableImpl::SceneEntryIteratorImpl::SceneEntryIteratorImpl(SceneTableImpl & provider, FabricIndex fabric_index) : + mProvider(provider), mFabric(fabric_index) +{ + FabricSceneData fabric(fabric_index); + if (CHIP_NO_ERROR == fabric.Load(provider.mStorage)) + { + + mNextSceneId = fabric.first_scene; + mTotalScene = fabric.scene_count; + mSceneCount = 0; + } +} + +size_t SceneTableImpl::SceneEntryIteratorImpl::Count() +{ + return mTotalScene; +} + +bool SceneTableImpl::SceneEntryIteratorImpl::Next(SceneTableEntry & output) +{ + VerifyOrReturnError(mSceneCount < mTotalScene, false); + + SceneTableData scene(mFabric, mNextSceneId); + VerifyOrReturnError(CHIP_NO_ERROR == scene.Load(mProvider.mStorage), false); + + mSceneCount++; + mNextSceneId = scene.next; + output.storageId = scene.storageId; + output.storageData = scene.storageData; + return true; +} + +void SceneTableImpl::SceneEntryIteratorImpl::Release() +{ + mProvider.mSceneEntryIterators.ReleaseObject(this); +} + +namespace { + +SceneTableImpl * gSceneTable = nullptr; + +} // namespace + +SceneTableImpl * GetSceneTable() +{ + return gSceneTable; +} + +void SetSceneTable(SceneTableImpl * provider) +{ + gSceneTable = provider; +} + +} // namespace scenes +} // namespace chip \ No newline at end of file diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h new file mode 100644 index 00000000000000..760caa0e562a66 --- /dev/null +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -0,0 +1,109 @@ +/** + * + * Copyright (c) 2022 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ + +#pragma once +#include +#include +#include +#include +#include + +namespace chip { +namespace scenes { + +/** + * @brief Implementation of a storage in permanent memory of the scene table. + * + * SceneTableImpl is an implementation that allows to store scenes in a permenent manner. + * It handles the storage of scenes by their ID, GroupID and EnpointID over multiple fabrics. + * It is meant to be used exclusively when the scene cluster is enable for at least one endpoint + * on the device. + */ +class SceneTableImpl : public SceneTable +{ +public: + SceneTableImpl() = default; + + ~SceneTableImpl() override {} + /** + * @brief Set the storage implementation used for non-volatile storage of configuration data. + * This method MUST be called before Init(). + * + * @param storage Pointer to storage instance to set. Cannot be nullptr, will assert. + */ + void SetStorageDelegate(PersistentStorageDelegate * storage); + + CHIP_ERROR Init(); + void Finish(); + + // + // Scene Data + // + + // By id + CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry); + CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, SceneTableImpl::SceneStorageId scene_id, SceneTableEntry & entry); + CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneTableImpl::SceneStorageId scene_id); + + // Iterators + SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; + +protected: + class SceneEntryIteratorImpl : public SceneEntryIterator + { + public: + SceneEntryIteratorImpl(SceneTableImpl & provider, FabricIndex fabric_index); + size_t Count() override; + bool Next(SceneTableEntry & output) override; + void Release() override; + + protected: + SceneTableImpl & mProvider; + FabricIndex mFabric = kUndefinedFabricIndex; + SceneStorageId mNextSceneId; + size_t mSceneCount = 0; + size_t mTotalScene = 0; + }; + bool IsInitialized() { return (mStorage != nullptr); } + + chip::PersistentStorageDelegate * mStorage = nullptr; + ObjectPool mSceneEntryIterators; + + const uint8_t mMaxScenePerFabric = kMaxScenePerFabric; +}; // class SceneTableImpl + +/** + * Instance getter for the global SceneTable. + * + * Callers have to externally synchronize usage of this function. + * + * @return The global Scene Table + */ +SceneTableImpl * GetSceneTable(); + +/** + * Instance setter for the global Scene Table. + * + * Callers have to externally synchronize usage of this function. + * + * The `provider` can be set to nullptr if the owner is done with it fully. + * + * @param[in] provider pointer to the Scene Table global isntance to use + */ +void SetSceneTable(SceneTableImpl * provider); +} // namespace scenes +} // namespace chip diff --git a/src/lib/core/DataModelTypes.h b/src/lib/core/DataModelTypes.h index fb79584c5c6988..308b679057778e 100644 --- a/src/lib/core/DataModelTypes.h +++ b/src/lib/core/DataModelTypes.h @@ -23,6 +23,7 @@ #include #include #include +#include namespace chip { diff --git a/src/lib/core/SceneId.h b/src/lib/core/SceneId.h new file mode 100644 index 00000000000000..83645e3671069f --- /dev/null +++ b/src/lib/core/SceneId.h @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2022 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. + */ + +#pragma once + +#include +#include + +/** + * @brief Indicates the absence of a Scene table entry. + */ +#define SCENE_TABLE_NULL_INDEX 0xFF +/** + * @brief Value used when setting or getting the endpoint in a Scene table + * entry. It indicates that the entry is not in use. + */ +#define SCENE_TABLE_UNUSED_ENDPOINT_ID 0x00 +/** + * @brief Maximum length of Scene names, not including the length byte. + */ +#define ZCL_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH 16 +/** + * @brief The group identifier for the global scene. + */ +#define ZCL_SCENES_GLOBAL_SCENE_GROUP_ID 0x0000 +/** + * @brief The scene identifier for the global scene. + */ +#define ZCL_SCENES_GLOBAL_SCENE_SCENE_ID 0x00 + +/** + * @brief The maximum number of scenes according to spec + */ +#define SCENE_MAX_NUMBER 16 + +/** + * @brief The maximum number of scenes allowed on a single fabric + */ +#define SCENE_MAX_PER_FABRIC SCENE_MAX_NUMBER / 2 + +namespace chip { + +typedef GroupId SceneGroupID; +typedef uint8_t SceneId; +typedef uint16_t SceneTransitionTime; +typedef uint8_t TransitionTime100ms; + +constexpr SceneGroupID kGlobalGroupSceneId = ZCL_SCENES_GLOBAL_SCENE_GROUP_ID; +constexpr SceneId kUndefinedSceneId = SCENE_TABLE_NULL_INDEX; +constexpr SceneId kUnusedEndpointId = SCENE_TABLE_UNUSED_ENDPOINT_ID; + +} // namespace chip \ No newline at end of file diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index c5a612db7fe8ea..a534632a5be064 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } @@ -191,12 +191,23 @@ class DefaultStorageKeyAllocator // Event number counter. static StorageKeyName IMEventNumber() { return StorageKeyName::FromConst("g/im/ec"); } +<<<<<<< HEAD // Subscription resumption static StorageKeyName SubscriptionResumption(size_t index) { return StorageKeyName::Formatted("g/su/%x", static_cast(index)); } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } +======= + // Scene Storage + static StorageKeyName SceneFabricList() { return StorageKeyName::FromConst("g/sfl"); } + static StorageKeyName FabricScenesKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } + static StorageKeyName FabricSceneKey(chip::FabricIndex fabric, chip::EndpointId endpoint, chip::GroupId group, + chip::SceneId scene) + { + return StorageKeyName::Formatted("f/%x/s/e%xg%xs%x", fabric, endpoint, group, scene); + } +>>>>>>> 47da6c11b4 (Implementation of persistant storage of scene table along with test.) }; } // namespace chip diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h new file mode 100644 index 00000000000000..0a38834dc35c28 --- /dev/null +++ b/src/lib/support/TestSceneTable.h @@ -0,0 +1,140 @@ +/* + * + * Copyright (c) 2022 Project CHIP Authors + * All rights reserved. + * + * 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ + +#pragma once + +#include + +namespace chip { + +namespace SceneTesting { + +using FabricIndex = chip::FabricIndex; +using SceneTableEntry = chip::scenes::SceneTableImpl::SceneTableEntry; +using SceneTableImpl = chip::scenes::SceneTableImpl; +using SceneStorageId = chip::scenes::SceneTableImpl::SceneStorageId; +using SceneData = chip::scenes::SceneTableImpl::SceneData; + +CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + SceneTableEntry temp; + + LogErrorOnFailure(provider->SetSceneTableEntry(fabric_index, entry)); + LogErrorOnFailure(provider->GetSceneTableEntry(fabric_index, entry.storageId, temp)); + VerifyOrReturnError(temp.storageId == entry.storageId, CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(temp.storageData == entry.storageData, CHIP_ERROR_WRITE_FAILED); + + return err; +} + +CHIP_ERROR scene_iterator_test(SceneTableImpl * provider, FabricIndex fabric_index, const SceneTableEntry & entry1, + const SceneTableEntry & entry2, const SceneTableEntry & entry3) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + SceneTableEntry temp; + + auto * iterator = provider->IterateSceneEntry(fabric_index); + if (iterator) + { + VerifyOrReturnError(iterator->Count() == 3, CHIP_ERROR_INVALID_ARGUMENT); + + VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); + VerifyOrReturnError(temp.storageId == entry1.storageId, CHIP_ERROR_INVALID_ARGUMENT); + + VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); + VerifyOrReturnError(temp.storageId == entry2.storageId, CHIP_ERROR_INVALID_ARGUMENT); + + VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); + VerifyOrReturnError(temp.storageId == entry3.storageId, CHIP_ERROR_INVALID_ARGUMENT); + + // Iterator should return false here + VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); + + iterator->Release(); + } + + return err; +} + +CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry1, + SceneTableEntry & entry2, SceneTableEntry & entry3) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + SceneTableEntry temp; + + LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry2.storageId)); + + auto * iterator = provider->IterateSceneEntry(fabric_index); + VerifyOrReturnError(iterator->Count() == 2, CHIP_ERROR_INVALID_ARGUMENT); + iterator->Next(temp); + VerifyOrReturnError(temp.storageId == entry1.storageId, CHIP_ERROR_INVALID_ARGUMENT); + iterator->Release(); + + LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry1.storageId)); + iterator = provider->IterateSceneEntry(fabric_index); + VerifyOrReturnError(iterator->Count() == 1, CHIP_ERROR_INVALID_ARGUMENT); + iterator->Next(temp); + VerifyOrReturnError(temp.storageId == entry3.storageId, CHIP_ERROR_INVALID_ARGUMENT); + + LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry3.storageId)); + iterator = provider->IterateSceneEntry(fabric_index); + VerifyOrReturnError(iterator->Count() == 0, CHIP_ERROR_INVALID_ARGUMENT); + + // Iterator should return false here + VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); + + return err; +} + +CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + // Scene storage ID + static const SceneStorageId sceneId1(1, 0xAA, 0x101); + static const SceneStorageId sceneId2(1, 0xBB, 0x00); + static const SceneStorageId sceneId3(1, 0xCC, 0x102); + + // Scene data + static const SceneData sceneData1("Scene #1"); + static const SceneData sceneData2("Scene #2", 2, 5); + static const SceneData sceneData3("Scene #3", 25); + // Scenes + SceneTableEntry scene1(sceneId1, sceneData1); + SceneTableEntry scene2(sceneId2, sceneData2); + SceneTableEntry scene3(sceneId3, sceneData3); + + // Tests + err = scene_store_test(provider, fabric_index, scene1); + LogErrorOnFailure(err); + err = scene_store_test(provider, fabric_index, scene2); + LogErrorOnFailure(err); + err = scene_store_test(provider, fabric_index, scene3); + LogErrorOnFailure(err); + + err = scene_iterator_test(provider, fabric_index, scene1, scene2, scene3); + LogErrorOnFailure(err); + err = scene_remove_test(provider, fabric_index, scene1, scene2, scene3); + LogErrorOnFailure(err); + + return err; +} + +} // namespace SceneTesting + +} // namespace chip From a4d79efa971b6a746a11be4e16847aac2cfe75c6 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Fri, 20 Jan 2023 16:55:00 -0500 Subject: [PATCH 02/79] Applied restyler --- src/app/clusters/scenes/ExtensionFieldsSets.cpp | 2 +- src/app/clusters/scenes/SceneTableImpl.cpp | 2 +- src/lib/core/SceneId.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.cpp b/src/app/clusters/scenes/ExtensionFieldsSets.cpp index 66d578940bd266..fd2c5433025d16 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSets.cpp @@ -92,4 +92,4 @@ void ExtensionFieldsSets::clear() } // namespace scenes -} // namespace chip \ No newline at end of file +} // namespace chip diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 306c6016aa8e9a..4178a713bcd5ba 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -464,4 +464,4 @@ void SetSceneTable(SceneTableImpl * provider) } } // namespace scenes -} // namespace chip \ No newline at end of file +} // namespace chip diff --git a/src/lib/core/SceneId.h b/src/lib/core/SceneId.h index 83645e3671069f..907e7353915aeb 100644 --- a/src/lib/core/SceneId.h +++ b/src/lib/core/SceneId.h @@ -63,4 +63,4 @@ constexpr SceneGroupID kGlobalGroupSceneId = ZCL_SCENES_GLOBAL_SCENE_GROUP_ID; constexpr SceneId kUndefinedSceneId = SCENE_TABLE_NULL_INDEX; constexpr SceneId kUnusedEndpointId = SCENE_TABLE_UNUSED_ENDPOINT_ID; -} // namespace chip \ No newline at end of file +} // namespace chip From b8d3800586977cea87984b4fea2fdc770b1c8a7d Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 20 Jan 2023 21:55:39 +0000 Subject: [PATCH 03/79] Restyled by clang-format --- src/app/clusters/scenes/SceneTable.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 82f89ca3d55152..8dafe2cb88fe83 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -219,6 +219,7 @@ class SceneTable }; SceneTable(){}; + virtual ~SceneTable() = default; // Not copyable From fc0e91363ebb61f2276eb9dba20aa6dd72d6c545 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 20 Jan 2023 21:55:41 +0000 Subject: [PATCH 04/79] Restyled by shfmt --- scripts/examples/gn_efr32_example.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/examples/gn_efr32_example.sh b/scripts/examples/gn_efr32_example.sh index 5e5a9bdef2e32e..8f451665dd8836 100755 --- a/scripts/examples/gn_efr32_example.sh +++ b/scripts/examples/gn_efr32_example.sh @@ -137,6 +137,7 @@ else shift while [ $# -gt 0 ]; do case $1 in + --clean) DIR_CLEAN=true shift From 9c4f7ce763ea7249d762fd957a19eebd942e3f7c Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Fri, 20 Jan 2023 21:55:39 +0000 Subject: [PATCH 05/79] Restyled by clang-format --- src/app/clusters/scenes/SceneTable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 8dafe2cb88fe83..9bbdd415d21d11 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -223,7 +223,7 @@ class SceneTable virtual ~SceneTable() = default; // Not copyable - SceneTable(const SceneTable &) = delete; + SceneTable(const SceneTable &) = delete; SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init() = 0; From 851e38e523107f29cb583d2dc0786ceb1d2b1087 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Mon, 23 Jan 2023 10:52:39 -0500 Subject: [PATCH 06/79] Update src/lib/core/SceneId.h Co-authored-by: Tennessee Carmel-Veilleux --- src/lib/core/SceneId.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/SceneId.h b/src/lib/core/SceneId.h index 907e7353915aeb..235c5d961817c7 100644 --- a/src/lib/core/SceneId.h +++ b/src/lib/core/SceneId.h @@ -50,7 +50,7 @@ /** * @brief The maximum number of scenes allowed on a single fabric */ -#define SCENE_MAX_PER_FABRIC SCENE_MAX_NUMBER / 2 +#define SCENE_MAX_PER_FABRIC (SCENE_MAX_NUMBER / 2) namespace chip { From db0d5b6a0127232b1549376a0d61bcf3776e6437 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Mon, 23 Jan 2023 10:52:52 -0500 Subject: [PATCH 07/79] Update src/app/clusters/scenes/SceneTableImpl.h Co-authored-by: Tennessee Carmel-Veilleux --- src/app/clusters/scenes/SceneTableImpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 760caa0e562a66..0b54c2a8da8afb 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -26,7 +26,7 @@ namespace chip { namespace scenes { /** - * @brief Implementation of a storage in permanent memory of the scene table. + * @brief Implementation of a storage in nonvolatile storage of the scene table. * * SceneTableImpl is an implementation that allows to store scenes in a permenent manner. * It handles the storage of scenes by their ID, GroupID and EnpointID over multiple fabrics. From 73c3da75b02c2928c09979f263162993d6a79f6d Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Mon, 23 Jan 2023 10:57:42 -0500 Subject: [PATCH 08/79] Update src/app/clusters/scenes/SceneTableImpl.h Co-authored-by: Tennessee Carmel-Veilleux --- src/app/clusters/scenes/SceneTableImpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 0b54c2a8da8afb..c5e05ae3594fc5 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -28,7 +28,7 @@ namespace scenes { /** * @brief Implementation of a storage in nonvolatile storage of the scene table. * - * SceneTableImpl is an implementation that allows to store scenes in a permenent manner. + * SceneTableImpl is an implementation that allows to store scenes using PersistentStorageDelegate. * It handles the storage of scenes by their ID, GroupID and EnpointID over multiple fabrics. * It is meant to be used exclusively when the scene cluster is enable for at least one endpoint * on the device. From c56257526dbe376b611e520b244cad572e85ca47 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Mon, 23 Jan 2023 17:31:50 -0500 Subject: [PATCH 09/79] Modified naming convention related issues and others --- scripts/examples/gn_efr32_example.sh | 1 - .../clusters/scenes/ExtensionFieldsSets.cpp | 13 ++-- src/app/clusters/scenes/ExtensionFieldsSets.h | 17 ++--- src/app/clusters/scenes/SceneTable.h | 15 +++-- src/app/clusters/scenes/SceneTableImpl.cpp | 63 +++++++++---------- src/app/clusters/scenes/SceneTableImpl.h | 32 ++++------ src/lib/core/CHIPConfig.h | 56 +++++++++++++++-- src/lib/core/DataModelTypes.h | 8 ++- src/lib/support/DefaultStorageKeyAllocator.h | 3 - 9 files changed, 126 insertions(+), 82 deletions(-) diff --git a/scripts/examples/gn_efr32_example.sh b/scripts/examples/gn_efr32_example.sh index 8f451665dd8836..5e5a9bdef2e32e 100755 --- a/scripts/examples/gn_efr32_example.sh +++ b/scripts/examples/gn_efr32_example.sh @@ -137,7 +137,6 @@ else shift while [ $# -gt 0 ]; do case $1 in - --clean) DIR_CLEAN=true shift diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.cpp b/src/app/clusters/scenes/ExtensionFieldsSets.cpp index fd2c5433025d16..2b25d9a3253042 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSets.cpp @@ -23,7 +23,7 @@ namespace scenes { ExtensionFieldsSets::ExtensionFieldsSets() { // check if any of the clusters with scene attributes are enabled - if (this->kExentesionFieldsSetsSize == 1) + if (this->kExtensionFieldsSetsSize == 1) { // a size of 1 byte indicates an empty struct, or a struct that only contains : // the on-off cluster @@ -40,9 +40,9 @@ ExtensionFieldsSets::ExtensionFieldsSets() this->empty = true; #endif } - else if (this->kExentesionFieldsSetsSize > 1) + else if (this->kExtensionFieldsSetsSize > 1) { - memset(&this->enabledFieldSets, 0, kExentesionFieldsSetsSize); + memset(&this->enabledFieldSets, 0, kExtensionFieldsSetsSize); } } @@ -53,8 +53,7 @@ CHIP_ERROR ExtensionFieldsSets::Serialize(TLV::TLVWriter & writer) const TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure( - writer.PutBytes(TagEnabledFielsSets(), (uint8_t *) &this->enabledFieldSets, kExentesionFieldsSetsSize)); + ReturnErrorOnFailure(writer.PutBytes(TagEnabledFielsSets(), (uint8_t *) &this->enabledFieldSets, kExtensionFieldsSetsSize)); return writer.EndContainer(container); } @@ -73,7 +72,7 @@ CHIP_ERROR ExtensionFieldsSets::Deserialize(TLV::TLVReader & reader) ReturnErrorOnFailure(reader.EnterContainer(container)); ReturnErrorOnFailure(reader.Next(TagEnabledFielsSets())); - ReturnErrorOnFailure(reader.GetBytes((uint8_t *) &this->enabledFieldSets, kExentesionFieldsSetsSize)); + ReturnErrorOnFailure(reader.GetBytes((uint8_t *) &this->enabledFieldSets, kExtensionFieldsSetsSize)); return reader.ExitContainer(container); } @@ -82,7 +81,7 @@ CHIP_ERROR ExtensionFieldsSets::Deserialize(TLV::TLVReader & reader) return CHIP_NO_ERROR; } } -void ExtensionFieldsSets::clear() +void ExtensionFieldsSets::Clear() { if (!this->empty) { diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldsSets.h index cae1d41499ce5a..ca1e080aa9dbf4 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.h +++ b/src/app/clusters/scenes/ExtensionFieldsSets.h @@ -25,8 +25,9 @@ namespace chip { namespace scenes { -typedef struct fieldSets_s +typedef struct { + #ifdef ZCL_USING_ON_OFF_CLUSTER_SERVER bool onOff; #endif @@ -68,32 +69,32 @@ typedef struct fieldSets_s uint8_t targetPositionLiftPercent100ths; uint8_t targetPositionTiltPercent100ths; #endif -} fieldSets_t; +} FieldSets; class ExtensionFieldsSets { public: - static constexpr size_t kExentesionFieldsSetsSize = sizeof(fieldSets_t); + static constexpr size_t kExtensionFieldsSetsSize = sizeof(FieldSets); static constexpr TLV::Tag TagEnabledFielsSets() { return TLV::ContextTag(1); } - fieldSets_t enabledFieldSets; + FieldSets enabledFieldSets; bool empty = false; ExtensionFieldsSets(); - virtual ~ExtensionFieldsSets() = default; + ~ExtensionFieldsSets(){}; CHIP_ERROR Serialize(TLV::TLVWriter & writer) const; CHIP_ERROR Deserialize(TLV::TLVReader & reader); - void clear(); + void Clear(); bool operator==(const ExtensionFieldsSets & other) { - return (!memcmp(&this->enabledFieldSets, &other.enabledFieldSets, kExentesionFieldsSetsSize)); + return (!memcmp(&this->enabledFieldSets, &other.enabledFieldSets, kExtensionFieldsSetsSize)); } void operator=(const ExtensionFieldsSets & other) { - memcpy(&this->enabledFieldSets, &other.enabledFieldSets, kExentesionFieldsSetsSize); + memcpy(&this->enabledFieldSets, &other.enabledFieldSets, kExtensionFieldsSetsSize); } }; } // namespace scenes diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 9bbdd415d21d11..baaa41e9f1dae8 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -24,12 +24,15 @@ namespace chip { namespace scenes { +typedef uint16_t SceneTransitionTime; +typedef uint8_t TransitionTime100ms; + class SceneTable { public: static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_GROUP_CONCURRENT_ITERATORS; - static constexpr size_t kSceneNameMax = ZCL_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; - static constexpr uint8_t kMaxScenePerFabric = SCENE_MAX_PER_FABRIC; + static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; + static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; /// @brief struct used to identify a scene in storage by 3 ids, endpoint, group and scene struct SceneStorageId { @@ -77,7 +80,7 @@ class SceneTable return reader.ExitContainer(container); } - void clear() + void Clear() { sceneEndpointId = kInvalidEndpointId; sceneGroupId = kGlobalGroupSceneId; @@ -171,12 +174,12 @@ class SceneTable } } - void clear() + void Clear() { this->SetName(nullptr); sceneTransitionTime = 0; transitionTime100 = 0; - extentsionFieldsSets.clear(); + extentsionFieldsSets.Clear(); } bool operator==(const SceneData & other) @@ -223,7 +226,7 @@ class SceneTable virtual ~SceneTable() = default; // Not copyable - SceneTable(const SceneTable &) = delete; + SceneTable(const SceneTable &) = delete; SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init() = 0; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 4178a713bcd5ba..552efb232fc1ba 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -23,11 +23,11 @@ namespace chip { namespace scenes { -using SceneTableEntry = SceneTableImpl::SceneTableEntry; -using SceneStorageId = SceneTableImpl::SceneStorageId; -using SceneData = SceneTableImpl::SceneData; +using SceneTableEntry = DefaultSceneTableImpl::SceneTableEntry; +using SceneStorageId = DefaultSceneTableImpl::SceneStorageId; +using SceneData = DefaultSceneTableImpl::SceneData; -struct FabricList : public CommonPersistentData::FabricList +struct FabricHavingSceneList : public CommonPersistentData::FabricList { CHIP_ERROR UpdateKey(StorageKeyName & key) override { @@ -50,7 +50,7 @@ struct FabricSceneData : public PersistentData static constexpr TLV::Tag TagNext() { return TLV::ContextTag(2); } chip::FabricIndex fabric_index = kUndefinedFabricIndex; - SceneTableImpl::SceneStorageId first_scene; + DefaultSceneTableImpl::SceneStorageId first_scene; uint16_t scene_count = 0; FabricIndex next = kUndefinedFabricIndex; @@ -66,7 +66,7 @@ struct FabricSceneData : public PersistentData void Clear() override { - first_scene.clear(); + first_scene.Clear(); scene_count = 0; next = kUndefinedFabricIndex; } @@ -100,10 +100,10 @@ struct FabricSceneData : public PersistentData return reader.ExitContainer(container); } - // Register the fabric in the fabrics' linked-list + // Register the fabric in the list of fabrics having scenes CHIP_ERROR Register(PersistentStorageDelegate * storage) { - FabricList fabric_list; + FabricHavingSceneList fabric_list; CHIP_ERROR err = fabric_list.Load(storage); if (CHIP_ERROR_NOT_FOUND == err) { @@ -140,7 +140,7 @@ struct FabricSceneData : public PersistentData // Remove the fabric from the fabrics' linked list CHIP_ERROR Unregister(PersistentStorageDelegate * storage) const { - FabricList fabric_list; + FabricHavingSceneList fabric_list; CHIP_ERROR err = fabric_list.Load(storage); VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); @@ -183,7 +183,7 @@ struct FabricSceneData : public PersistentData // Check the fabric is registered in the fabrics' linked list CHIP_ERROR Validate(PersistentStorageDelegate * storage) const { - FabricList fabric_list; + FabricHavingSceneList fabric_list; ReturnErrorOnFailure(fabric_list.Load(storage)); // Existing fabric list, search for existing entry @@ -240,8 +240,8 @@ struct SceneTableData : public SceneTableEntry, PersistentData mSceneEntryIterators; const uint8_t mMaxScenePerFabric = kMaxScenePerFabric; -}; // class SceneTableImpl +}; // class DefaultSceneTableImpl /** * Instance getter for the global SceneTable. @@ -93,7 +87,7 @@ class SceneTableImpl : public SceneTable * * @return The global Scene Table */ -SceneTableImpl * GetSceneTable(); +DefaultSceneTableImpl * GetSceneTable(); /** * Instance setter for the global Scene Table. @@ -104,6 +98,6 @@ SceneTableImpl * GetSceneTable(); * * @param[in] provider pointer to the Scene Table global isntance to use */ -void SetSceneTable(SceneTableImpl * provider); +void SetSceneTable(DefaultSceneTableImpl * provider); } // namespace scenes } // namespace chip diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index c66d7f2974d5a6..e951b485e753ef 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1354,10 +1354,6 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_MAX_CLIENT_REG_PER_FABRIC 1 #endif // CHIP_CONFIG_MAX_CLIENT_REG_PER_FABRIC -/** - * @} - */ - /** * @def CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS * @@ -1368,3 +1364,55 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #ifndef CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS #define CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS 2 #endif +/** + * @brief Indicates the absence of a Scene table entry. + */ +#ifndef CHIP_CONFIG_SCENES_TABLE_NULL_INDEX +#define CHIP_CONFIG_SCENES_TABLE_NULL_INDEX 0xFF +#endif + +/** + * @brief Value used when setting or getting the endpoint in a Scene table + * entry. It indicates that the entry is not in use. + */ +#ifndef CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID +#define CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID 0x00 +#endif +/** + * @brief The maximum number of scenes according to spec + */ +#ifndef CHIP_CONFIG_SCENES_MAX_NUMBER +#define CHIP_CONFIG_SCENES_MAX_NUMBER 16 +#endif + +/** + * @brief Maximum length of Scene names, not including the length byte. + */ +#ifndef CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH +#define CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH 16 +#endif + +/** + * @brief The group identifier for the global scene. + */ +#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID +#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID 0x0000 +#endif + +/** + * @brief The scene identifier for the global scene. + */ +#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID +#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID 0x00 +#endif + +/** + * @brief The maximum number of scenes allowed on a single fabric + */ +#ifndef CHIP_CONFIG_SCENES_MAX_PER_FABRIC +#define CHIP_CONFIG_SCENES_MAX_PER_FABRIC (CHIP_CONFIG_SCENES_MAX_NUMBER / 2) +#endif + +/** + * @} + */ diff --git a/src/lib/core/DataModelTypes.h b/src/lib/core/DataModelTypes.h index 308b679057778e..5bfbec2f3b6131 100644 --- a/src/lib/core/DataModelTypes.h +++ b/src/lib/core/DataModelTypes.h @@ -19,11 +19,11 @@ #include +#include #include // For VendorId #include #include #include -#include namespace chip { @@ -47,6 +47,8 @@ typedef uint32_t TransactionId; typedef uint16_t KeysetId; typedef uint8_t InteractionModelRevision; typedef uint32_t SubscriptionId; +typedef GroupId SceneGroupID; +typedef uint8_t SceneId; constexpr CompressedFabricId kUndefinedCompressedFabricId = 0ULL; constexpr FabricId kUndefinedFabricId = 0ULL; @@ -60,6 +62,10 @@ constexpr EndpointId kRootEndpointId = 0; constexpr ListIndex kInvalidListIndex = 0xFFFF; // List index is a uint16 thus 0xFFFF is a invalid list index. constexpr KeysetId kInvalidKeysetId = 0xFFFF; +constexpr SceneGroupID kGlobalGroupSceneId = CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID; +constexpr SceneId kUndefinedSceneId = CHIP_CONFIG_SCENES_TABLE_NULL_INDEX; +constexpr SceneId kUnusedEndpointId = CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID; + // Invalid IC identifier is provisional. Value will most likely change when identifying token is defined // https://github.com/project-chip/connectedhomeip/issues/24251 constexpr uint64_t kInvalidIcId = 0; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index a534632a5be064..aa78b876547683 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -191,14 +191,12 @@ class DefaultStorageKeyAllocator // Event number counter. static StorageKeyName IMEventNumber() { return StorageKeyName::FromConst("g/im/ec"); } -<<<<<<< HEAD // Subscription resumption static StorageKeyName SubscriptionResumption(size_t index) { return StorageKeyName::Formatted("g/su/%x", static_cast(index)); } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } -======= // Scene Storage static StorageKeyName SceneFabricList() { return StorageKeyName::FromConst("g/sfl"); } static StorageKeyName FabricScenesKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } @@ -207,7 +205,6 @@ class DefaultStorageKeyAllocator { return StorageKeyName::Formatted("f/%x/s/e%xg%xs%x", fabric, endpoint, group, scene); } ->>>>>>> 47da6c11b4 (Implementation of persistant storage of scene table along with test.) }; } // namespace chip From eb3bb691e5b02aa3ecf0dc495f63452adf4fb88a Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Tue, 24 Jan 2023 19:39:22 -0500 Subject: [PATCH 10/79] Added verification for SceneName in logging and applied correction to scene implementation --- src/app/clusters/scenes/SceneTable.h | 48 ++- src/app/clusters/scenes/SceneTableImpl.cpp | 27 +- src/app/clusters/scenes/SceneTableImpl.h | 17 +- src/app/tests/BUILD.gn | 18 ++ src/app/tests/TestSceneTable.cpp | 333 +++++++++++++++++++++ src/lib/support/CommonPersistentData.h | 1 + src/lib/support/TestSceneTable.h | 9 +- 7 files changed, 428 insertions(+), 25 deletions(-) create mode 100644 src/app/tests/TestSceneTable.cpp diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index baaa41e9f1dae8..7121cea2abbdc1 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -20,6 +20,7 @@ #include #include #include +#include namespace chip { namespace scenes { @@ -111,13 +112,12 @@ class SceneTable ExtensionFieldsSets extentsionFieldsSets; TransitionTime100ms transitionTime100 = 0; - SceneData() = default; - SceneData(const char * sceneName, SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : + SceneData(const char * sceneName = nullptr, SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : sceneTransitionTime(time), transitionTime100(time100ms) { SetName(sceneName); } - SceneData(const char * sceneName, ExtensionFieldsSets fields, SceneTransitionTime time = 0, + SceneData(ExtensionFieldsSets fields, const char * sceneName = nullptr, SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : sceneTransitionTime(time), transitionTime100(time100ms) @@ -136,8 +136,13 @@ class SceneTable TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); - size_t name_size = strnlen(this->name, kSceneNameMax); - ReturnErrorOnFailure(writer.PutString(TagSceneName(), this->name, static_cast(name_size))); + // assumes a 0 size means the name wasn't used so it doesn't get stored + if (this->name[0] != 0) + { + size_t name_size = strnlen(this->name, kSceneNameMax); + ReturnErrorOnFailure(writer.PutString(TagSceneName(), this->name, static_cast(name_size))); + } + ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime(), static_cast(this->sceneTransitionTime))); ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime100(), static_cast(this->transitionTime100))); ReturnErrorOnFailure(this->extentsionFieldsSets.Serialize(writer)); @@ -150,10 +155,20 @@ class SceneTable ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TagSceneName())); - ReturnErrorOnFailure(reader.GetString(this->name, sizeof(this->name))); - size_t name_size = strnlen(this->name, kSceneNameMax); // TODO : verify use of strnlen is ok - this->name[name_size] = 0; // Putting a null terminator + ReturnErrorOnFailure(reader.Next()); + TLV::Tag currTag = reader.GetTag(); + VerifyOrReturnError(TagSceneName() == currTag || TagSceneTransitionTime() == currTag, CHIP_ERROR_WRONG_TLV_TYPE); + + // If there was no error, a name is expected from the storage, if there was an unexpectec TLV element, + if (currTag == TagSceneName()) + { + size_t name_size = reader.GetLength(); + VerifyOrReturnError(name_size <= (kSceneNameMax - 1), CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(reader.GetString(this->name, name_size)); + this->name[name_size] = 0; + } + + // Putting a null terminator ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime())); ReturnErrorOnFailure(reader.Get(this->sceneTransitionTime)); ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime100())); @@ -212,7 +227,10 @@ class SceneTable SceneTableEntry(SceneStorageId id) : storageId(id) {} SceneTableEntry(const SceneStorageId id, const SceneData data) : storageId(id), storageData(data) {} - bool operator==(const SceneTableEntry & other) { return (this->storageId == other.storageId); } + bool operator==(const SceneTableEntry & other) + { + return (this->storageId == other.storageId && this->storageData == other.storageData); + } void operator=(const SceneTableEntry & other) { @@ -229,8 +247,8 @@ class SceneTable SceneTable(const SceneTable &) = delete; SceneTable & operator=(const SceneTable &) = delete; - virtual CHIP_ERROR Init() = 0; - virtual void Finish() = 0; + virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; + virtual void Finish() = 0; // Data virtual CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) = 0; @@ -241,6 +259,12 @@ class SceneTable using SceneEntryIterator = CommonIterator; virtual SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) = 0; + + // Fabrics + virtual CHIP_ERROR RemoveFabric(FabricIndex fabric_index) = 0; + +protected: + const uint8_t mMaxScenePerFabric = kMaxScenePerFabric; }; } // namespace scenes diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 552efb232fc1ba..0ef66965c42c0f 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -16,7 +16,6 @@ */ #include -#include #include #include @@ -401,6 +400,32 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index return CHIP_NO_ERROR; } +CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) +{ + FabricSceneData fabric(fabric_index); + + CHIP_ERROR err = fabric.Load(mStorage); + VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); + + // Remove scene entries + SceneTableData scene(fabric_index, fabric.first_scene); + size_t scene_count = 0; + + while (scene_count < fabric.scene_count) + { + if (CHIP_NO_ERROR != scene.Load(mStorage)) + { + break; + } + RemoveSceneTableEntry(fabric_index, scene.storageId); + scene.storageId = scene.next; + scene_count++; + } + + // Remove fabric + return fabric.Delete(mStorage); +} + DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntry(FabricIndex fabric_index) { VerifyOrReturnError(IsInitialized(), nullptr); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 5a8988db72de93..f191b19d243d08 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -40,22 +40,25 @@ class DefaultSceneTableImpl : public SceneTable ~DefaultSceneTableImpl() override {} - CHIP_ERROR Init(PersistentStorageDelegate * storage); - void Finish(); + CHIP_ERROR Init(PersistentStorageDelegate * storage) override; + void Finish() override; // // Scene Data // // By id - CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry); + CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) override; CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id, - SceneTableEntry & entry); - CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id); + SceneTableEntry & entry) override; + CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id) override; // Iterators SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; + // Fabrics + CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; + protected: class SceneEntryIteratorImpl : public SceneEntryIterator { @@ -76,8 +79,6 @@ class DefaultSceneTableImpl : public SceneTable chip::PersistentStorageDelegate * mStorage = nullptr; ObjectPool mSceneEntryIterators; - - const uint8_t mMaxScenePerFabric = kMaxScenePerFabric; }; // class DefaultSceneTableImpl /** @@ -96,7 +97,7 @@ DefaultSceneTableImpl * GetSceneTable(); * * The `provider` can be set to nullptr if the owner is done with it fully. * - * @param[in] provider pointer to the Scene Table global isntance to use + * @param[in] provider pointer to the Scene Table global instance to use */ void SetSceneTable(DefaultSceneTableImpl * provider); } // namespace scenes diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 8e291bb904feb0..632d01333bc281 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -79,6 +79,22 @@ source_set("ota-requestor-test-srcs") { ] } +source_set("scenes-table-test-srcs") { + sources = [ + "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSets.cpp", + "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSets.h", + "${chip_root}/src/app/clusters/scenes/SceneTable.h", + "${chip_root}/src/app/clusters/scenes/SceneTableImpl.cpp", + "${chip_root}/src/app/clusters/scenes/SceneTableImpl.h", + "${chip_root}/src/app/clusters/scenes/scenes-tokens.h", + ] + + public_deps = [ + "${chip_root}/src/app/common:cluster-objects", + "${chip_root}/src/lib/core", + ] +} + chip_test_suite("tests") { output_name = "libAppTests" @@ -105,6 +121,7 @@ chip_test_suite("tests") { "TestPendingNotificationMap.cpp", "TestReadInteraction.cpp", "TestReportingEngine.cpp", + "TestSceneTable.cpp", "TestStatusIB.cpp", "TestStatusResponseMessage.cpp", "TestTimedHandler.cpp", @@ -140,6 +157,7 @@ chip_test_suite("tests") { ":binding-test-srcs", ":client-monitoring-test-srcs", ":ota-requestor-test-srcs", + ":scenes-table-test-srcs", "${chip_root}/src/app", "${chip_root}/src/app/common:cluster-objects", "${chip_root}/src/app/tests:helpers", diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp new file mode 100644 index 00000000000000..383ff35e4e5675 --- /dev/null +++ b/src/app/tests/TestSceneTable.cpp @@ -0,0 +1,333 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include + +using FabricIndex = chip::FabricIndex; +using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; +using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; +using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; +using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; + +namespace { + +static chip::TestPersistentStorageDelegate testStorage; +static SceneTableImpl sSceneTable; + +// Test fabrics, adding more requires to modify the "ResetSceneTable" function +constexpr chip::FabricIndex kFabric1 = 1; +constexpr chip::FabricIndex kFabric2 = 7; + +// Scene storage ID +static const SceneStorageId sceneId1(1, 0xAA, 0x101); +static const SceneStorageId sceneId2(1, 0xBB, 0x00); +static const SceneStorageId sceneId3(1, 0xCC, 0x102); +static const SceneStorageId sceneId4(1, 0xBE, 0x00); +static const SceneStorageId sceneId5(1, 0x45, 0x103); +static const SceneStorageId sceneId6(1, 0x65, 0x00); +static const SceneStorageId sceneId7(1, 0x77, 0x101); +static const SceneStorageId sceneId8(1, 0xEE, 0x101); +static const SceneStorageId sceneId9(1, 0xAB, 0x101); + +// Scene data +static const SceneData sceneData1("Scene #1"); +static const SceneData sceneData2("Scene #2", 2, 5); +static const SceneData sceneData3("Scene #3", 25); +static const SceneData sceneData4("Scene num4", 5); +static const SceneData sceneData5(nullptr); +static const SceneData sceneData6("Scene #6", 3, 15); +static const SceneData sceneData7("Scene #7", 20, 5); +static const SceneData sceneData8("Scene num8", 10); +static const SceneData sceneData9("NAME TOO LOOONNG", 30, 15); +static const SceneData sceneData10("Scene #10", 10, 1); +static const SceneData sceneData11("Scene #11", 20, 10); +static const SceneData sceneData12("Scene #12", 30, 5); + +// Scenes +SceneTableEntry scene1(sceneId1, sceneData1); +SceneTableEntry scene2(sceneId2, sceneData2); +SceneTableEntry scene3(sceneId3, sceneData3); +SceneTableEntry scene4(sceneId4, sceneData4); +SceneTableEntry scene5(sceneId5, sceneData5); +SceneTableEntry scene6(sceneId6, sceneData6); +SceneTableEntry scene7(sceneId7, sceneData7); +SceneTableEntry scene8(sceneId8, sceneData8); +SceneTableEntry scene9(sceneId9, sceneData9); +SceneTableEntry scene10(sceneId1, sceneData10); +SceneTableEntry scene11(sceneId5, sceneData11); +SceneTableEntry scene12(sceneId8, sceneData12); + +void ResetSceneTable(SceneTableImpl * sceneTable) +{ + sceneTable->RemoveFabric(kFabric1); + sceneTable->RemoveFabric(kFabric2); +} + +void TestStoreScenes(nlTestSuite * aSuite, void * aContext) +{ + SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + NL_TEST_ASSERT(aSuite, sceneTable); + + // Reset test + ResetSceneTable(sceneTable); + + SceneTableEntry scene; + + // Set test + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene3)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene4)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene5)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene6)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene7)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene8)); + + // Too many scenes 1 fabric + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_LIST_LENGTH == sceneTable->SetSceneTableEntry(kFabric1, scene9)); + + // Not Found + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->SetSceneTableEntry(kFabric1, scene9)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId4, scene)); + NL_TEST_ASSERT(aSuite, scene == scene4); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); + NL_TEST_ASSERT(aSuite, scene == scene5); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId6, scene)); + NL_TEST_ASSERT(aSuite, scene == scene6); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId7, scene)); + NL_TEST_ASSERT(aSuite, scene == scene7); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); + NL_TEST_ASSERT(aSuite, scene == scene8); +} + +void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) +{ + SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + NL_TEST_ASSERT(aSuite, sceneTable); + + SceneTableEntry scene; + // Overwriting the first entry + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene10)); + // Overwriting in the middle + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene11)); + // Overwriting the last entry + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene12)); + + // Scene 10 has the same sceneId as scene 1, Get->sceneId1 should thus return scene 10, etc. + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene10); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); + NL_TEST_ASSERT(aSuite, scene == scene11); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); + NL_TEST_ASSERT(aSuite, scene == scene12); +} + +void TestIterateScenes(nlTestSuite * aSuite, void * aContext) +{ + SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + NL_TEST_ASSERT(aSuite, sceneTable); + + SceneTableEntry scene; + auto * iterator = sceneTable->IterateSceneEntry(kFabric1); + + if (iterator) + { + NL_TEST_ASSERT(aSuite, iterator->Count() == 8); + + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene10); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene4); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene11); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene6); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene7); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene12); + + NL_TEST_ASSERT(aSuite, iterator->Next(scene) == false); + + iterator->Release(); + } +} + +void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) +{ + SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + NL_TEST_ASSERT(aSuite, sceneTable); + + SceneTableEntry scene; + + // Remove middle + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene5.storageId)); + auto * iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 7); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + iterator->Release(); + + // Remove first + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.storageId)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 6); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + + // Remove Next + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene3.storageId)); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene4); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene2.storageId)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 4); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene4); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene4.storageId)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 3); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene6); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene6.storageId)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 2); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene7); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene7.storageId)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 2); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene8); + + // Remove last + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.storageId)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 0); + NL_TEST_ASSERT(aSuite, iterator->Next(scene) == false); + + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.storageId)); + + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 0); + auto * iterator = sceneTable->IterateSceneEntry(kFabric1); +} + +void TestFabricScenes(nlTestSuite * aSuite, void * aContext) +{ + SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + NL_TEST_ASSERT(aSuite, sceneTable); + + // Reset test + ResetSceneTable(sceneTable); + + SceneTableEntry scene; + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene3)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene3)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + + // Remove Fabric 1 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric1)); + // Verify Fabric 1 removed + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveFabric(kFabric1)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); + + // Confirm Fabric 2 still there + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + + // Remove Fabric 2 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric2)); + // Verify Fabric 1 removed + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveFabric(kFabric2)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); +} + +} // namespace + +int TestSetup(void * inContext) +{ + VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); + VerifyOrReturnError(CHIP_NO_ERROR == sSceneTable.Init(&testStorage), FAILURE); + + SetSceneTable(&sSceneTable); +} + +int TestSceneTable() +{ + static nlTest sTests[] = { + NL_TEST_DEF("TestFabricScenes", TestFabricScenes), NL_TEST_DEF("TestStoreScenes", TestStoreScenes), + NL_TEST_DEF("TestOverwriteScenes", TestOverwriteScenes), NL_TEST_DEF("TestIterateScenes", TestIterateScenes), + NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), NL_TEST_SENTINEL() + }; + + nlTestSuite theSuite = { + "SceneTable", + &sTests[0], + nullptr, + nullptr, + }; + nlTestRunner(&theSuite, nullptr); + return (nlTestRunnerStats(&theSuite)); +} + +CHIP_REGISTER_TEST_SUITE(TestSceneTable) \ No newline at end of file diff --git a/src/lib/support/CommonPersistentData.h b/src/lib/support/CommonPersistentData.h index f04ba591959c4e..df0acff14616e4 100644 --- a/src/lib/support/CommonPersistentData.h +++ b/src/lib/support/CommonPersistentData.h @@ -19,6 +19,7 @@ * @file * Contains a class handling creation of linked list of stored persistent data. */ +#pragma once #include #include diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h index 0a38834dc35c28..fe67352c4fe068 100644 --- a/src/lib/support/TestSceneTable.h +++ b/src/lib/support/TestSceneTable.h @@ -25,10 +25,10 @@ namespace chip { namespace SceneTesting { using FabricIndex = chip::FabricIndex; -using SceneTableEntry = chip::scenes::SceneTableImpl::SceneTableEntry; -using SceneTableImpl = chip::scenes::SceneTableImpl; -using SceneStorageId = chip::scenes::SceneTableImpl::SceneStorageId; -using SceneData = chip::scenes::SceneTableImpl::SceneData; +using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; +using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; +using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; +using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry) { @@ -98,6 +98,7 @@ CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index // Iterator should return false here VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); + iterator->Release(); return err; } From f5bdaf16c7fc2739a313d7f806be4eee44f6d602 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Tue, 31 Jan 2023 16:18:20 -0500 Subject: [PATCH 11/79] Refactored sceneData to support logging without name, added test functionnal with test unit --- src/app/clusters/scenes/SceneTable.h | 52 ++++++++++-------- src/app/clusters/scenes/SceneTableImpl.cpp | 7 ++- src/app/tests/BUILD.gn | 1 + src/app/tests/TestSceneTable.cpp | 61 +++++++++++++++------- 4 files changed, 77 insertions(+), 44 deletions(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 7121cea2abbdc1..ddc96f69036c95 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -21,6 +21,7 @@ #include #include #include +#include namespace chip { namespace scenes { @@ -108,27 +109,30 @@ class SceneTable static constexpr TLV::Tag TagSceneTransitionTime100() { return TLV::ContextTag(3); } char name[kSceneNameMax] = { 0 }; + size_t nameLength = 0; SceneTransitionTime sceneTransitionTime = 0; ExtensionFieldsSets extentsionFieldsSets; TransitionTime100ms transitionTime100 = 0; + CharSpan nameSpan; - SceneData(const char * sceneName = nullptr, SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : + SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : sceneTransitionTime(time), transitionTime100(time100ms) { - SetName(sceneName); + this->SetName(sceneName); } - SceneData(ExtensionFieldsSets fields, const char * sceneName = nullptr, SceneTransitionTime time = 0, + SceneData(ExtensionFieldsSets fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : sceneTransitionTime(time), transitionTime100(time100ms) { - SetName(sceneName); + this->SetName(sceneName); extentsionFieldsSets = fields; } - SceneData(const SceneData & data) : sceneTransitionTime(data.sceneTransitionTime), transitionTime100(data.transitionTime100) + SceneData(const SceneData & other) : + sceneTransitionTime(other.sceneTransitionTime), transitionTime100(other.transitionTime100) { - SetName(data.name); - extentsionFieldsSets = data.extentsionFieldsSets; + this->SetName(other.nameSpan); + extentsionFieldsSets = other.extentsionFieldsSets; } CHIP_ERROR Serialize(TLV::TLVWriter & writer) const @@ -136,11 +140,10 @@ class SceneTable TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); - // assumes a 0 size means the name wasn't used so it doesn't get stored - if (this->name[0] != 0) + // A 0 size means the name wasn't used so it won't get stored + if (!this->nameSpan.empty()) { - size_t name_size = strnlen(this->name, kSceneNameMax); - ReturnErrorOnFailure(writer.PutString(TagSceneName(), this->name, static_cast(name_size))); + ReturnErrorOnFailure(writer.PutString(TagSceneName(), this->nameSpan)); } ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime(), static_cast(this->sceneTransitionTime))); @@ -162,14 +165,13 @@ class SceneTable // If there was no error, a name is expected from the storage, if there was an unexpectec TLV element, if (currTag == TagSceneName()) { - size_t name_size = reader.GetLength(); - VerifyOrReturnError(name_size <= (kSceneNameMax - 1), CHIP_ERROR_BUFFER_TOO_SMALL); - ReturnErrorOnFailure(reader.GetString(this->name, name_size)); - this->name[name_size] = 0; + ReturnErrorOnFailure(reader.Get(this->nameSpan)); + this->SetName(this->nameSpan); + + // Putting a null terminator + ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime())); } - // Putting a null terminator - ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime())); ReturnErrorOnFailure(reader.Get(this->sceneTransitionTime)); ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime100())); ReturnErrorOnFailure(reader.Get(this->transitionTime100)); @@ -177,21 +179,25 @@ class SceneTable return reader.ExitContainer(container); } - void SetName(const char * sceneName) + + void SetName(const CharSpan & sceneName) { - if (nullptr == sceneName) + if (nullptr == sceneName.data()) { - name[0] = 0; + name[0] = 0; + nameLength = 0; } else { Platform::CopyString(name, sceneName); + nameLength = sceneName.size(); } + nameSpan = CharSpan(name, nameLength); } void Clear() { - this->SetName(nullptr); + this->SetName(CharSpan()); sceneTransitionTime = 0; transitionTime100 = 0; extentsionFieldsSets.Clear(); @@ -199,14 +205,14 @@ class SceneTable bool operator==(const SceneData & other) { - return (!strncmp(this->name, other.name, kSceneNameMax) && (this->sceneTransitionTime == other.sceneTransitionTime) && + return (this->nameSpan.data_equal(other.nameSpan) && (this->sceneTransitionTime == other.sceneTransitionTime) && (this->transitionTime100 == other.transitionTime100) && (this->extentsionFieldsSets == other.extentsionFieldsSets)); } void operator=(const SceneData & other) { - this->SetName(other.name); + this->SetName(other.nameSpan); this->extentsionFieldsSets = other.extentsionFieldsSets; this->sceneTransitionTime = other.sceneTransitionTime; this->transitionTime100 = other.transitionTime100; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 0ef66965c42c0f..c3c20d0c749dfe 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -273,6 +273,7 @@ struct SceneTableData : public SceneTableEntry, PersistentDataSetSceneTableEntry(kFabric1, scene9)); // Not Found - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->SetSceneTableEntry(kFabric1, scene9)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId9, scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); @@ -194,7 +195,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) auto * iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); - NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, scene == scene10); iterator->Release(); // Remove first @@ -206,6 +207,10 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove Next NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene3.storageId)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 5); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene4); @@ -229,9 +234,9 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene7.storageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); - NL_TEST_ASSERT(aSuite, iterator->Count() == 2); + NL_TEST_ASSERT(aSuite, iterator->Count() == 1); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); - NL_TEST_ASSERT(aSuite, scene == scene8); + NL_TEST_ASSERT(aSuite, scene == scene12); // Remove last NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.storageId)); @@ -243,7 +248,6 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); - auto * iterator = sceneTable->IterateSceneEntry(kFabric1); } void TestFabricScenes(nlTestSuite * aSuite, void * aContext) @@ -304,14 +308,32 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) } // namespace +/** + * Tear down the test suite. + */ int TestSetup(void * inContext) { VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); VerifyOrReturnError(CHIP_NO_ERROR == sSceneTable.Init(&testStorage), FAILURE); SetSceneTable(&sSceneTable); + + return SUCCESS; } +/** + * Tear down the test suite. + */ +int TestTeardown(void * inContext) +{ + SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + if (nullptr != sceneTable) + { + sceneTable->Finish(); + } + chip::Platform::MemoryShutdown(); + return SUCCESS; +} int TestSceneTable() { static nlTest sTests[] = { @@ -323,9 +345,10 @@ int TestSceneTable() nlTestSuite theSuite = { "SceneTable", &sTests[0], - nullptr, - nullptr, + TestSetup, + TestTeardown, }; + nlTestRunner(&theSuite, nullptr); return (nlTestRunnerStats(&theSuite)); } From 180f75634956c66158e238add4fd4d362e340524 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Fri, 3 Feb 2023 15:45:56 -0500 Subject: [PATCH 12/79] implemented and tested EFSs handlers for the scene table --- src/app/chip_data_model.gni | 3 +- .../clusters/scenes/ExtensionFieldsSets.cpp | 94 ---------- src/app/clusters/scenes/ExtensionFieldsSets.h | 77 +-------- .../scenes/ExtensionFieldsSetsImpl.cpp | 152 +++++++++++++++++ .../clusters/scenes/ExtensionFieldsSetsImpl.h | 160 ++++++++++++++++++ src/app/clusters/scenes/SceneTable.h | 9 +- src/app/clusters/scenes/SceneTableImpl.cpp | 109 ++++++++++++ src/app/clusters/scenes/SceneTableImpl.h | 108 +++++++++++- src/app/tests/BUILD.gn | 4 +- src/app/tests/TestSceneTable.cpp | 145 +++++++++++++++- src/lib/core/CHIPConfig.h | 14 ++ 11 files changed, 690 insertions(+), 185 deletions(-) delete mode 100644 src/app/clusters/scenes/ExtensionFieldsSets.cpp create mode 100644 src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp create mode 100644 src/app/clusters/scenes/ExtensionFieldsSetsImpl.h diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index cfbd9c5911492c..221312a60c3906 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -157,8 +157,9 @@ template("chip_data_model") { "${_app_root}/clusters/identify-server/identify-server.h", "${_app_root}/clusters/level-control/level-control.h", "${_app_root}/clusters/on-off-server/on-off-server.h", - "${_app_root}/clusters/scenes/ExtensionFieldsSets.cpp", "${_app_root}/clusters/scenes/ExtensionFieldsSets.h", + "${_app_root}/clusters/scenes/ExtensionFieldsSetsImpl.cpp", + "${_app_root}/clusters/scenes/ExtensionFieldsSetsImpl.h", "${_app_root}/clusters/scenes/SceneTable.h", "${_app_root}/clusters/scenes/SceneTableImpl.cpp", "${_app_root}/clusters/scenes/SceneTableImpl.h", diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.cpp b/src/app/clusters/scenes/ExtensionFieldsSets.cpp deleted file mode 100644 index 2b25d9a3253042..00000000000000 --- a/src/app/clusters/scenes/ExtensionFieldsSets.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/* - * - * Copyright (c) 2023 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 - * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ - * - * 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. - */ - -#include "ExtensionFieldsSets.h" - -namespace chip { -namespace scenes { - -ExtensionFieldsSets::ExtensionFieldsSets() -{ - // check if any of the clusters with scene attributes are enabled - if (this->kExtensionFieldsSetsSize == 1) - { - // a size of 1 byte indicates an empty struct, or a struct that only contains : - // the on-off cluster - // the Mode select cluster - // the door lock cluster -#ifdef ZCL_USING_ON_OFF_CLUSTER_SERVER - this->enabledFieldSets.onOff = false; - -#elif defined(ZCL_USING_MODE_SELECT_CLUSTER_SERVER) - this->enabledFieldSets.currentMode = 0; -#elif defined(ZCL_USING_DOOR_LOCK_CLUSTER_SERVER) - this->enabledFieldSets.lockState = 0; -#else - this->empty = true; -#endif - } - else if (this->kExtensionFieldsSetsSize > 1) - { - memset(&this->enabledFieldSets, 0, kExtensionFieldsSetsSize); - } -} - -CHIP_ERROR ExtensionFieldsSets::Serialize(TLV::TLVWriter & writer) const -{ - if (!this->empty) - { - TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); - - ReturnErrorOnFailure(writer.PutBytes(TagEnabledFielsSets(), (uint8_t *) &this->enabledFieldSets, kExtensionFieldsSetsSize)); - - return writer.EndContainer(container); - } - else - { - return CHIP_NO_ERROR; - } -} - -CHIP_ERROR ExtensionFieldsSets::Deserialize(TLV::TLVReader & reader) -{ - if (!this->empty) - { - TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); - ReturnErrorOnFailure(reader.EnterContainer(container)); - - ReturnErrorOnFailure(reader.Next(TagEnabledFielsSets())); - ReturnErrorOnFailure(reader.GetBytes((uint8_t *) &this->enabledFieldSets, kExtensionFieldsSetsSize)); - - return reader.ExitContainer(container); - } - else - { - return CHIP_NO_ERROR; - } -} -void ExtensionFieldsSets::Clear() -{ - if (!this->empty) - { - memset(&this->enabledFieldSets, 0, sizeof(this->enabledFieldSets)); - } -} - -} // namespace scenes - -} // namespace chip diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldsSets.h index ca1e080aa9dbf4..eedd3834e97dc3 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.h +++ b/src/app/clusters/scenes/ExtensionFieldsSets.h @@ -17,85 +17,22 @@ #pragma once -#include #include -#include #include namespace chip { namespace scenes { -typedef struct -{ - -#ifdef ZCL_USING_ON_OFF_CLUSTER_SERVER - bool onOff; -#endif - -#ifdef ZCL_USING_LEVEL_CONTROL_CLUSTER_SERVER - uint8_t currentLevel; - uint16_t currentFrequency; -#endif - -#ifdef ZCL_USING_MODE_SELECT_CLUSTER_SERVER - uint8_t currentMode; -#endif - -#ifdef ZCL_USING_COLOR_CONTROL_CLUSTER_SERVER - uint8_t currentSaturation; - uint16_t currentX; - uint16_t currentY; - uint16_t colorTemperatureMireds; - uint16_t enhancedCurrentHue; - uint8_t enhancedColorMode; - uint8_t colorLoopActive; - uint8_t colorLoopDirection; - uint16_t colorLoopTime; -#endif - -#ifdef ZCL_USING_THERMOSTAT_CLUSTER_SERVER - uint16_t occupiedCoolingSetpoint; - uint16_t occupiedHeatingSetpoint; - uint8_t systemMode; -#endif - -#ifdef ZCL_USING_DOOR_LOCK_CLUSTER_SERVER - uint8_t lockState; -#endif - -#ifdef ZCL_USING_WINDOW_COVERING_CLUSTER_SERVER - uint8_t currentPositionLiftPercentage; - uint8_t currentPositionTiltPercentage; - uint8_t targetPositionLiftPercent100ths; - uint8_t targetPositionTiltPercent100ths; -#endif -} FieldSets; - class ExtensionFieldsSets { public: - static constexpr size_t kExtensionFieldsSetsSize = sizeof(FieldSets); - static constexpr TLV::Tag TagEnabledFielsSets() { return TLV::ContextTag(1); } - FieldSets enabledFieldSets; - bool empty = false; - - ExtensionFieldsSets(); - ~ExtensionFieldsSets(){}; - - CHIP_ERROR Serialize(TLV::TLVWriter & writer) const; - CHIP_ERROR Deserialize(TLV::TLVReader & reader); - - void Clear(); - - bool operator==(const ExtensionFieldsSets & other) - { - return (!memcmp(&this->enabledFieldSets, &other.enabledFieldSets, kExtensionFieldsSetsSize)); - } + ExtensionFieldsSets(){}; + virtual ~ExtensionFieldsSets() = default; - void operator=(const ExtensionFieldsSets & other) - { - memcpy(&this->enabledFieldSets, &other.enabledFieldSets, kExtensionFieldsSetsSize); - } + virtual CHIP_ERROR Serialize(TLV::TLVWriter & writer) const = 0; + virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; + virtual void Clear() = 0; + virtual bool is_empty() const = 0; }; } // namespace scenes -} // namespace chip +} // namespace chip \ No newline at end of file diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp new file mode 100644 index 00000000000000..ed3dac591463b3 --- /dev/null +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -0,0 +1,152 @@ +/* + * + * Copyright (c) 2023 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ + +#include + +namespace chip { +namespace scenes { + +ExtensionFieldsSetsImpl::ExtensionFieldsSetsImpl() : ExtensionFieldsSets() {} + +CHIP_ERROR ExtensionFieldsSetsImpl::Serialize(TLV::TLVWriter & writer) const +{ + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.Put(TagFieldNum(), static_cast(this->fieldNum))); + if (!this->is_empty()) + { + for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + { + if (!this->EFS[i].is_empty()) + { + LogErrorOnFailure(this->EFS[i].Serialize(writer)); + } + } + } + + return writer.EndContainer(container); +} + +CHIP_ERROR ExtensionFieldsSetsImpl::Deserialize(TLV::TLVReader & reader) +{ + TLV::TLVType container; + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(reader.Next(TagFieldNum())); + ReturnErrorOnFailure(reader.Get(this->fieldNum)); + + if (!this->is_empty()) + { + for (uint8_t i = 0; i < this->fieldNum; i++) + { + ReturnErrorOnFailure(this->EFS[i].Deserialize(reader)); + } + } + + return reader.ExitContainer(container); +} +void ExtensionFieldsSetsImpl::Clear() +{ + if (!this->is_empty()) + { + for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + { + this->EFS[i].Clear(); + } + } + this->fieldNum = 0; +} + +bool ExtensionFieldsSetsImpl::is_empty() const +{ + return (this->fieldNum <= 0); +} + +/// @brief Inserts a field set into the array of extension field sets for a scene entry if the same ID is present in the EFS array, +/// it will overwrite it +/// @param field field set to be inserted +/// @return CHIP_NO_ERROR if insertion worked, CHIP_ERROR_BUFFER_TOO_SMALL if the array is already full +CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) +{ + uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; + for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + { + if (this->EFS[i].ID == field.ID) + { + idPosition = i; + break; + } + + if (this->EFS[i].is_empty() && fisrtEmptyPosition == 0xFF) + { + fisrtEmptyPosition = i; + } + } + + // if found, insert at found position, otherwise at first free possition, otherwise return error + if (idPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + { + ReturnErrorOnFailure(this->EFS[idPosition] = field); + return CHIP_NO_ERROR; + } + else if (fisrtEmptyPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + { + ReturnErrorOnFailure(this->EFS[fisrtEmptyPosition] = field); + this->fieldNum++; + return CHIP_NO_ERROR; + } + else + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } +} + +CHIP_ERROR ExtensionFieldsSetsImpl::getFieldAtPosition(ExtensionFieldsSet & field, uint8_t position) +{ + if (position < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + { + ReturnErrorOnFailure(field = this->EFS[position]); + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR ExtensionFieldsSetsImpl::removeFieldAtPosition(uint8_t position) +{ + if (!this->is_empty()) + { + if (position < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + { + if (!this->EFS[position].is_empty()) + { + this->EFS[position].Clear(); + this->fieldNum--; + } + } + else + { + return CHIP_ERROR_ACCESS_DENIED; + } + } + + return CHIP_NO_ERROR; +} + +} // namespace scenes + +} // namespace chip diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h new file mode 100644 index 00000000000000..58438cfab192b3 --- /dev/null +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h @@ -0,0 +1,160 @@ +/** + * + * Copyright (c) 2023 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace scenes { + +using clusterId = chip::ClusterId; + +struct ExtensionFieldsSet +{ + static constexpr TLV::Tag TagClusterId() { return TLV::ContextTag(1); } + static constexpr TLV::Tag TagEFS() { return TLV::ContextTag(2); } + clusterId ID = kInvalidClusterId; + uint8_t bytesBuffer[CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER] = { 0 }; + uint8_t usedBytes = 0; + + ExtensionFieldsSet() = default; + ExtensionFieldsSet(clusterId cID, uint8_t * data, uint8_t dataSize) : ID(cID), usedBytes(dataSize) + { + if (dataSize <= CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER) + { + memcpy(bytesBuffer, data, usedBytes); + } + } + ~ExtensionFieldsSet() = default; + + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const + { + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); + + ReturnErrorOnFailure(writer.Put(TagClusterId(), static_cast(this->ID))); + ReturnErrorOnFailure(writer.PutBytes(TagEFS(), bytesBuffer, usedBytes)); + + return writer.EndContainer(container); + } + CHIP_ERROR Deserialize(TLV::TLVReader & reader) + { + ByteSpan buffer; + TLV::TLVType container; + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(reader.Next(TagClusterId())); + ReturnErrorOnFailure(reader.Get(this->ID)); + + ReturnErrorOnFailure(reader.Next(TagEFS())); + ReturnErrorOnFailure(reader.Get(buffer)); + if (buffer.size() > CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER) + { + this->usedBytes = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; + } + else + { + this->usedBytes = static_cast(buffer.size()); + } + memcpy(this->bytesBuffer, buffer.data(), this->usedBytes); + // ReturnErrorOnFailure(reader.GetBytes(bytesBuffer, CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER)); + + return reader.ExitContainer(container); + } + + void Clear() + { + this->ID = kInvalidClusterId; + memset(this->bytesBuffer, 0, CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER); + this->usedBytes = 0; + } + + bool is_empty() const { return (this->usedBytes == 0); } + + bool operator==(const ExtensionFieldsSet & other) + { + return (this->ID == other.ID && !memcmp(this->bytesBuffer, other.bytesBuffer, this->usedBytes) && + this->usedBytes == other.usedBytes); + } + + CHIP_ERROR operator=(const ExtensionFieldsSet & other) + { + if (other.usedBytes <= CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER) + { + memcpy(this->bytesBuffer, other.bytesBuffer, other.usedBytes); + } + else + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + this->ID = other.ID; + this->usedBytes = other.usedBytes; + + return CHIP_NO_ERROR; + } +}; + +class ExtensionFieldsSetsImpl : public ExtensionFieldsSets +{ +public: + ExtensionFieldsSetsImpl(); + ~ExtensionFieldsSetsImpl() override{}; + + // overrides + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override; + CHIP_ERROR Deserialize(TLV::TLVReader & reader) override; + void Clear() override; + bool is_empty() const override; + + // implementation + CHIP_ERROR insertField(ExtensionFieldsSet & field); + CHIP_ERROR getFieldAtPosition(ExtensionFieldsSet & field, uint8_t position); + CHIP_ERROR removeFieldAtPosition(uint8_t position); + + bool operator==(const ExtensionFieldsSetsImpl & other) + { + for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + { + if (!(this->EFS[i] == other.EFS[i])) + { + return false; + } + } + return true; + } + + CHIP_ERROR operator=(const ExtensionFieldsSetsImpl & other) + { + for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + { + ReturnErrorOnFailure(this->EFS[i] = other.EFS[i]); + } + fieldNum = other.fieldNum; + + return CHIP_NO_ERROR; + } + +protected: + static constexpr TLV::Tag TagFieldNum() { return TLV::ContextTag(1); } + ExtensionFieldsSet EFS[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES]; + uint8_t fieldNum = 0; +}; +} // namespace scenes +} // namespace chip diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index ddc96f69036c95..3322983848dd0d 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -17,7 +17,7 @@ #pragma once #include -#include +#include #include #include #include @@ -111,7 +111,7 @@ class SceneTable char name[kSceneNameMax] = { 0 }; size_t nameLength = 0; SceneTransitionTime sceneTransitionTime = 0; - ExtensionFieldsSets extentsionFieldsSets; + ExtensionFieldsSetsImpl extentsionFieldsSets; TransitionTime100ms transitionTime100 = 0; CharSpan nameSpan; @@ -120,7 +120,7 @@ class SceneTable { this->SetName(sceneName); } - SceneData(ExtensionFieldsSets fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, + SceneData(ExtensionFieldsSetsImpl fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : sceneTransitionTime(time), transitionTime100(time100ms) @@ -134,6 +134,7 @@ class SceneTable this->SetName(other.nameSpan); extentsionFieldsSets = other.extentsionFieldsSets; } + ~SceneData(){}; CHIP_ERROR Serialize(TLV::TLVWriter & writer) const { @@ -167,8 +168,6 @@ class SceneTable { ReturnErrorOnFailure(reader.Get(this->nameSpan)); this->SetName(this->nameSpan); - - // Putting a null terminator ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime())); } diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index c3c20d0c749dfe..a0502e21e9166d 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -403,6 +403,115 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index return CHIP_NO_ERROR; } +/// @brief Registers handle to get extension fields set for a specific cluster. If the handler is already present in the handler +/// array, it will be overwritten +/// @param ID ID of the cluster used to fill the extension fields set +/// @param get_function pointer to function to call to get the extension fiels set from the cluster +/// @param set_function pointer to function to call send an extension field to the cluster +/// @return CHIP_ERROR_BUFFER_TO_SMALL if couldn't insert the handler, otherwise CHIP_NO_ERROR +CHIP_ERROR DefaultSceneTableImpl::registerHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function) +{ + uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; + for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + { + if (this->handlers[i].getID() == ID) + { + idPosition = i; + break; + } + if (!this->handlers[i].isInitialized() && fisrtEmptyPosition == 0xff) + { + fisrtEmptyPosition = i; + } + } + + // if found, insert at found position, otherwise at first free possition, otherwise return error + if (idPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + { + this->handlers[idPosition].initSceneHandler(ID, get_function, set_function); + return CHIP_NO_ERROR; + } + else if (fisrtEmptyPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + { + this->handlers[fisrtEmptyPosition].initSceneHandler(ID, get_function, set_function); + this->handlerNum++; + return CHIP_NO_ERROR; + } + else + { + return CHIP_ERROR_BUFFER_TOO_SMALL; + } + + return CHIP_ERROR_BUFFER_TOO_SMALL; +} + +CHIP_ERROR DefaultSceneTableImpl::unregisterHandler(uint8_t position) +{ + if (!handlerListEmpty()) + { + if (position < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + { + if (this->handlers[position].isInitialized()) + { + this->handlers[position].clearSceneHandler(); + this->handlerNum--; + } + } + else + { + return CHIP_ERROR_ACCESS_DENIED; + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DefaultSceneTableImpl::EFSValuesFromCluster(ExtensionFieldsSetsImpl & fieldSets) +{ + ExtensionFieldsSet EFS; + if (!this->handlerListEmpty()) + { + for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + { + if (this->handlers[i].isInitialized()) + { + ReturnErrorOnFailure(this->handlers[i].getClusterEFS(EFS)); + ReturnErrorOnFailure(fieldSets.insertField(EFS)); + } + } + } + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DefaultSceneTableImpl::EFSValuesToCluster(ExtensionFieldsSetsImpl & fieldSets) +{ + ExtensionFieldsSet EFS; + if (!this->handlerListEmpty()) + { + for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + { + fieldSets.getFieldAtPosition(EFS, i); + + if (!EFS.is_empty()) + { + if (!this->handlerListEmpty()) + { + for (uint8_t j = 0; j < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; j++) + { + if (EFS.ID == this->handlers[j].getID()) + { + ReturnErrorOnFailure(this->handlers[j].setClusterEFS(EFS)); + } + } + } + } + } + } + + return CHIP_NO_ERROR; +} + CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) { FabricSceneData fabric(fabric_index); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index f191b19d243d08..0513e39dde5ae6 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -25,6 +25,90 @@ namespace chip { namespace scenes { +using clusterId = chip::ClusterId; + +typedef CHIP_ERROR (*clusterFieldsHandle)(ExtensionFieldsSet & fields); + +/// @brief Class to allow extension field sets to be handled by the scene table without any knowledge of the cluster or its +/// implementation +class SceneHandler +{ +public: + SceneHandler(ClusterId Id = kInvalidClusterId, clusterFieldsHandle getClusterEFS = nullptr, + clusterFieldsHandle setClusterEFS = nullptr) + { + if (getClusterEFS != nullptr && setClusterEFS != nullptr && Id != kInvalidClusterId) + { + getEFS = getClusterEFS; + setEFS = setClusterEFS; + cID = Id; + initialized = true; + } + }; + ~SceneHandler(){}; + + void initSceneHandler(ClusterId Id, clusterFieldsHandle getClusterEFS, clusterFieldsHandle setClusterEFS) + { + if (getClusterEFS != nullptr && setClusterEFS != nullptr && Id != kInvalidClusterId) + { + getEFS = getClusterEFS; + setEFS = setClusterEFS; + cID = Id; + initialized = true; + } + } + + void clearSceneHandler() + { + getEFS = nullptr; + setEFS = nullptr; + cID = kInvalidClusterId; + initialized = false; + } + + CHIP_ERROR getClusterEFS(ExtensionFieldsSet & clusterFields) + { + if (this->isInitialized()) + { + ReturnErrorOnFailure(getEFS(clusterFields)); + } + + return CHIP_NO_ERROR; + } + CHIP_ERROR setClusterEFS(ExtensionFieldsSet & clusterFields) + { + if (this->isInitialized()) + { + ReturnErrorOnFailure(setEFS(clusterFields)); + } + + return CHIP_NO_ERROR; + } + + bool isInitialized() const { return this->initialized; } + + ClusterId getID() { return cID; } + + bool operator==(const SceneHandler & other) + { + return (this->getEFS == other.getEFS && this->setEFS == other.setEFS && this->cID == other.cID && + initialized == other.initialized); + } + void operator=(const SceneHandler & other) + { + this->getEFS = other.getEFS; + this->setEFS = other.setEFS; + this->cID = other.cID; + this->initialized = true; + } + +protected: + clusterFieldsHandle getEFS = nullptr; + clusterFieldsHandle setEFS = nullptr; + ClusterId cID = kInvalidClusterId; + bool initialized = false; +}; + /** * @brief Implementation of a storage in nonvolatile storage of the scene table. * @@ -43,22 +127,30 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR Init(PersistentStorageDelegate * storage) override; void Finish() override; - // - // Scene Data - // - - // By id + // Scene access by Id CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) override; CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id, SceneTableEntry & entry) override; CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id) override; - // Iterators - SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; + // SceneHandlers + CHIP_ERROR registerHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function); + CHIP_ERROR unregisterHandler(uint8_t position); + + // Extension field sets operation + CHIP_ERROR EFSValuesFromCluster(ExtensionFieldsSetsImpl & fieldSets); + CHIP_ERROR EFSValuesToCluster(ExtensionFieldsSetsImpl & fieldSets); // Fabrics CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; + // Iterators + SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; + + bool handlerListEmpty() { return (handlerNum == 0); } + bool handlerListFull() { return (handlerNum >= CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES); } + uint8_t getHandlerNum() { return this->handlerNum; } + protected: class SceneEntryIteratorImpl : public SceneEntryIterator { @@ -79,6 +171,8 @@ class DefaultSceneTableImpl : public SceneTable chip::PersistentStorageDelegate * mStorage = nullptr; ObjectPool mSceneEntryIterators; + SceneHandler handlers[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES]; + uint8_t handlerNum = 0; }; // class DefaultSceneTableImpl /** diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index fe55906fe57ef2..606b6d74937d54 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -81,8 +81,9 @@ source_set("ota-requestor-test-srcs") { source_set("scenes-table-test-srcs") { sources = [ - "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSets.cpp", "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSets.h", + "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp", + "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h", "${chip_root}/src/app/clusters/scenes/SceneTable.h", "${chip_root}/src/app/clusters/scenes/SceneTableImpl.cpp", "${chip_root}/src/app/clusters/scenes/SceneTableImpl.h", @@ -93,7 +94,6 @@ source_set("scenes-table-test-srcs") { "${chip_root}/src/app/common:cluster-objects", "${chip_root}/src/lib/core", ] - defines = [ "SCENES_TESTING_CONFIGURATION=1" ] } chip_test_suite("tests") { diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 791c6d4f2e0b2c..055b1514cd69fc 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -21,12 +21,13 @@ #include #include -using FabricIndex = chip::FabricIndex; -using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; -using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; -using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; -using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; -using CharSpan = chip::CharSpan; +using FabricIndex = chip::FabricIndex; +using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; +using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; +using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; +using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; +using CharSpan = chip::CharSpan; +using ExtensionFieldsSet = chip::scenes::ExtensionFieldsSet; namespace { @@ -76,6 +77,82 @@ SceneTableEntry scene10(sceneId1, sceneData10); SceneTableEntry scene11(sceneId5, sceneData11); SceneTableEntry scene12(sceneId8, sceneData12); +// EFS +static const ExtensionFieldsSet onOffEFS1 = ExtensionFieldsSet(0x0006, (uint8_t *) "1", 1); +static const ExtensionFieldsSet onOffEFS2 = ExtensionFieldsSet(0x0006, (uint8_t *) "0", 1); +static const ExtensionFieldsSet levelControlEFS1 = ExtensionFieldsSet(0x0008, (uint8_t *) "511", 3); +static const ExtensionFieldsSet levelControlEFS2 = ExtensionFieldsSet(0x0008, (uint8_t *) "222", 3); +static const ExtensionFieldsSet colorControlEFS1 = ExtensionFieldsSet(0x0303, (uint8_t *) "123456789abcde", 14); +static const ExtensionFieldsSet colorControlEFS2 = ExtensionFieldsSet(0x0303, (uint8_t *) "abcdefghi12345", 14); + +// Simulation of clusters callbacks (sate #1) +CHIP_ERROR test_on_off_from_cluster_callback1(ExtensionFieldsSet & fields) +{ + ReturnErrorOnFailure(fields = onOffEFS1); + return CHIP_NO_ERROR; +} +CHIP_ERROR test_on_off_to_cluster_callback1(ExtensionFieldsSet & fields) +{ + VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_WRITE_FAILED); + return CHIP_NO_ERROR; +} +CHIP_ERROR test_level_control_from_cluster_callback1(ExtensionFieldsSet & fields) +{ + ReturnErrorOnFailure(fields = levelControlEFS1); + return CHIP_NO_ERROR; +} +CHIP_ERROR test_level_control_to_cluster_callback1(ExtensionFieldsSet & fields) +{ + VerifyOrReturnError(fields == levelControlEFS1, CHIP_ERROR_WRITE_FAILED); + return CHIP_NO_ERROR; +} + +CHIP_ERROR test_color_control_from_cluster_callback1(ExtensionFieldsSet & fields) +{ + ReturnErrorOnFailure(fields = colorControlEFS1); + return CHIP_NO_ERROR; +} + +CHIP_ERROR test_color_control_to_cluster_callback1(ExtensionFieldsSet & fields) +{ + VerifyOrReturnError(fields == colorControlEFS1, CHIP_ERROR_WRITE_FAILED); + return CHIP_NO_ERROR; +} + +// Simulation of clusters callbacks (sate #2) +CHIP_ERROR test_on_off_from_cluster_callback2(ExtensionFieldsSet & fields) +{ + ReturnErrorOnFailure(fields = onOffEFS1); + return CHIP_NO_ERROR; +} +CHIP_ERROR test_on_off_to_cluster_callback2(ExtensionFieldsSet & fields) +{ + VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_WRITE_FAILED); + return CHIP_NO_ERROR; +} +CHIP_ERROR test_level_control_from_cluster_callback2(ExtensionFieldsSet & fields) +{ + ReturnErrorOnFailure(fields = levelControlEFS1); + return CHIP_NO_ERROR; +} +CHIP_ERROR test_level_control_to_cluster_callback2(ExtensionFieldsSet & fields) +{ + VerifyOrReturnError(fields == levelControlEFS1, CHIP_ERROR_WRITE_FAILED); + return CHIP_NO_ERROR; +} + +CHIP_ERROR test_color_control_from_cluster_callback2(ExtensionFieldsSet & fields) +{ + ReturnErrorOnFailure(fields = colorControlEFS1); + return CHIP_NO_ERROR; +} + +CHIP_ERROR test_color_control_to_cluster_callback2(ExtensionFieldsSet & fields) +{ + VerifyOrReturnError(fields == colorControlEFS1, CHIP_ERROR_WRITE_FAILED); + return CHIP_NO_ERROR; +} + void ResetSceneTable(SceneTableImpl * sceneTable) { sceneTable->RemoveFabric(kFabric1); @@ -90,6 +167,26 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Reset test ResetSceneTable(sceneTable); + // Test SceneHandlers + NL_TEST_ASSERT( + aSuite, + CHIP_NO_ERROR == + sceneTable->registerHandler(onOffEFS1.ID, &test_on_off_from_cluster_callback1, &test_on_off_to_cluster_callback1)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + sceneTable->registerHandler(levelControlEFS1.ID, &test_level_control_from_cluster_callback1, + &test_level_control_to_cluster_callback1)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + sceneTable->registerHandler(colorControlEFS1.ID, &test_color_control_from_cluster_callback1, + &test_color_control_to_cluster_callback1)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene1.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene2.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene3.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene4.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene5.storageData.extentsionFieldsSets)); + SceneTableEntry scene; // Set test @@ -110,14 +207,24 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); NL_TEST_ASSERT(aSuite, scene == scene3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId4, scene)); NL_TEST_ASSERT(aSuite, scene == scene4); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene5); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId6, scene)); NL_TEST_ASSERT(aSuite, scene == scene6); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId7, scene)); @@ -131,6 +238,27 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); + // Test SceneHandlers overwrite + NL_TEST_ASSERT( + aSuite, + CHIP_NO_ERROR == + sceneTable->registerHandler(onOffEFS2.ID, &test_on_off_from_cluster_callback2, &test_on_off_to_cluster_callback2)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + sceneTable->registerHandler(levelControlEFS2.ID, &test_level_control_from_cluster_callback2, + &test_level_control_to_cluster_callback2)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + sceneTable->registerHandler(colorControlEFS2.ID, &test_color_control_from_cluster_callback2, + &test_color_control_to_cluster_callback2)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene10.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene11.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene12.storageData.extentsionFieldsSets)); + + // Verfies the overwrite hasn't changed the handlers number + NL_TEST_ASSERT(aSuite, sceneTable->getHandlerNum() == 3); + SceneTableEntry scene; // Overwriting the first entry NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene10)); @@ -142,10 +270,15 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) // Scene 10 has the same sceneId as scene 1, Get->sceneId1 should thus return scene 10, etc. NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene10); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene11); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); NL_TEST_ASSERT(aSuite, scene == scene12); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); } void TestIterateScenes(nlTestSuite * aSuite, void * aContext) diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index e951b485e753ef..05976b1d73687c 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1413,6 +1413,20 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_SCENES_MAX_PER_FABRIC (CHIP_CONFIG_SCENES_MAX_NUMBER / 2) #endif +/** + * @brief The maximum number of cluster per scene + */ +#ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES +#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES 7 +#endif + +/** + * @brief The maximum size of a single extension field set for a single cluster + */ +#ifndef CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER +#define CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER 15 +#endif + /** * @} */ From 4d9703da51d6fbe475d97dc25b596166c79e1d80 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 6 Feb 2023 17:47:40 +0000 Subject: [PATCH 13/79] Restyled by whitespace --- src/app/clusters/scenes/ExtensionFieldsSets.h | 2 +- src/app/tests/TestSceneTable.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldsSets.h index eedd3834e97dc3..907d047fddeefb 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.h +++ b/src/app/clusters/scenes/ExtensionFieldsSets.h @@ -35,4 +35,4 @@ class ExtensionFieldsSets virtual bool is_empty() const = 0; }; } // namespace scenes -} // namespace chip \ No newline at end of file +} // namespace chip diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 055b1514cd69fc..fd97d9667bc202 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -486,4 +486,4 @@ int TestSceneTable() return (nlTestRunnerStats(&theSuite)); } -CHIP_REGISTER_TEST_SUITE(TestSceneTable) \ No newline at end of file +CHIP_REGISTER_TEST_SUITE(TestSceneTable) From 503b4efaceea4eac63f999de2c8197f294bbdd83 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 6 Feb 2023 17:47:41 +0000 Subject: [PATCH 14/79] Restyled by clang-format --- src/app/clusters/scenes/SceneTable.h | 14 +++++++------- src/lib/support/DefaultStorageKeyAllocator.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 3322983848dd0d..3a3c07adfbfd3e 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -246,13 +246,13 @@ class SceneTable SceneTable(){}; - virtual ~SceneTable() = default; - - // Not copyable - SceneTable(const SceneTable &) = delete; - SceneTable & operator=(const SceneTable &) = delete; - - virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; + virtual ~SceneTable() = default; + + // Not copyable + SceneTable(const SceneTable &) = delete; + SceneTable & operator=(const SceneTable &) = delete; + + virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; virtual void Finish() = 0; // Data diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index aa78b876547683..f929082861aac9 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } From 36aa63640f7d1825b5dee44cac96ef0e7a5bb8f8 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 8 Feb 2023 14:52:15 -0500 Subject: [PATCH 15/79] Implemented and tested storage by index in the scene table --- .../scenes/ExtensionFieldsSetsImpl.cpp | 2 +- src/app/clusters/scenes/SceneTable.h | 16 +- src/app/clusters/scenes/SceneTableImpl.cpp | 251 ++++++++++-------- src/app/clusters/scenes/SceneTableImpl.h | 11 +- src/app/clusters/scenes/ScenesTestConfig.h | 26 ++ src/app/tests/TestSceneTable.cpp | 124 +++++---- src/lib/core/DataModelTypes.h | 2 + src/lib/support/DefaultStorageKeyAllocator.h | 12 +- 8 files changed, 248 insertions(+), 196 deletions(-) create mode 100644 src/app/clusters/scenes/ScenesTestConfig.h diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index ed3dac591463b3..4051e591b2a072 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -112,7 +112,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) } else { - return CHIP_ERROR_BUFFER_TOO_SMALL; + return CHIP_ERROR_INVALID_LIST_LENGTH; } } diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 3a3c07adfbfd3e..3fa0f0d2867453 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -35,6 +35,7 @@ class SceneTable static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_GROUP_CONCURRENT_ITERATORS; static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; + /// @brief struct used to identify a scene in storage by 3 ids, endpoint, group and scene struct SceneStorageId { @@ -246,19 +247,20 @@ class SceneTable SceneTable(){}; - virtual ~SceneTable() = default; - - // Not copyable - SceneTable(const SceneTable &) = delete; - SceneTable & operator=(const SceneTable &) = delete; - - virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; + virtual ~SceneTable() = default; + + // Not copyable + SceneTable(const SceneTable &) = delete; + SceneTable & operator=(const SceneTable &) = delete; + + virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; virtual void Finish() = 0; // Data virtual CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) = 0; virtual CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) = 0; virtual CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) = 0; + virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) = 0; // Iterators using SceneEntryIterator = CommonIterator; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index a0502e21e9166d..f550279255afbf 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -44,14 +44,13 @@ static constexpr size_t kPersistentBufferMax = 128; */ struct FabricSceneData : public PersistentData { - // static constexpr TLV::Tag TagTableID() { return TLV::ContextTag(1); } static constexpr TLV::Tag TagSceneCount() { return TLV::ContextTag(1); } - static constexpr TLV::Tag TagNext() { return TLV::ContextTag(2); } + static constexpr TLV::Tag TagSceneMap() { return TLV::ContextTag(2); } + static constexpr TLV::Tag TagNext() { return TLV::ContextTag(3); } - chip::FabricIndex fabric_index = kUndefinedFabricIndex; - DefaultSceneTableImpl::SceneStorageId first_scene; - uint16_t scene_count = 0; - FabricIndex next = kUndefinedFabricIndex; + FabricIndex fabric_index = kUndefinedFabricIndex; + uint8_t scene_count = 0; + FabricIndex next = kUndefinedFabricIndex; FabricSceneData() = default; FabricSceneData(FabricIndex fabric) : fabric_index(fabric) {} @@ -65,7 +64,6 @@ struct FabricSceneData : public PersistentData void Clear() override { - first_scene.Clear(); scene_count = 0; next = kUndefinedFabricIndex; } @@ -75,7 +73,6 @@ struct FabricSceneData : public PersistentData TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(first_scene.Serialize(writer)); ReturnErrorOnFailure(writer.Put(TagSceneCount(), static_cast(scene_count))); ReturnErrorOnFailure(writer.Put(TagNext(), static_cast(next))); @@ -90,7 +87,6 @@ struct FabricSceneData : public PersistentData TLV::TLVType container; ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(first_scene.Deserialize(reader)); ReturnErrorOnFailure(reader.Next(TagSceneCount())); ReturnErrorOnFailure(reader.Get(scene_count)); ReturnErrorOnFailure(reader.Next(TagNext())); @@ -216,14 +212,15 @@ struct FabricSceneData : public PersistentData struct SceneTableData : public SceneTableEntry, PersistentData { + static constexpr TLV::Tag TagNext() { return TLV::ContextTag(1); } + FabricIndex fabric_index = kUndefinedFabricIndex; - uint8_t index = 0; - SceneStorageId next; - SceneStorageId prev; - bool first = true; + SceneIndex index = 0; + bool first = true; SceneTableData() : SceneTableEntry() {} SceneTableData(FabricIndex fabric) : fabric_index(fabric) {} + SceneTableData(FabricIndex fabric, SceneIndex idx) : fabric_index(fabric), index(idx) {} SceneTableData(FabricIndex fabric, SceneStorageId storageId) : SceneTableEntry(storageId), fabric_index(fabric) {} SceneTableData(FabricIndex fabric, SceneStorageId storageId, SceneData data) : SceneTableEntry(storageId, data), fabric_index(fabric) @@ -232,16 +229,11 @@ struct SceneTableData : public SceneTableEntry, PersistentData 0) { - // Update previous scene's next - SceneTableData prev(fabric_index, scene.prev); - ReturnErrorOnFailure(prev.Load(mStorage)); - prev.next = scene.next; - ReturnErrorOnFailure(prev.Save(mStorage)); + fabric.scene_count--; + ReturnErrorOnFailure(fabric.Save(mStorage)); } + + return CHIP_NO_ERROR; +} + +/// @brief This function is meant to provide a way to empty the scene table without knowing any specific scene Id. Outisde of this +/// specific use case, RemoveSceneTableEntry should be used. +/// @param fabric_index Fabric in which the scene belongs +/// @param scened_idx Position in the Scene Table +/// @return CHIP_NO_ERROR if removal was successful, errors if failed to remove the scene or to update the fabric after removing it +CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) +{ + FabricSceneData fabric(fabric_index); + SceneTableData scene(fabric_index, scened_idx); + + ReturnErrorOnFailure(scene.Delete(mStorage)); + if (fabric.scene_count > 0) { fabric.scene_count--; + ReturnErrorOnFailure(fabric.Save(mStorage)); } - // Update fabric info - ReturnErrorOnFailure(fabric.Save(mStorage)); - return CHIP_NO_ERROR; } @@ -439,10 +408,10 @@ CHIP_ERROR DefaultSceneTableImpl::registerHandler(ClusterId ID, clusterFieldsHan } else { - return CHIP_ERROR_BUFFER_TOO_SMALL; + return CHIP_ERROR_INVALID_LIST_LENGTH; } - return CHIP_ERROR_BUFFER_TOO_SMALL; + return CHIP_ERROR_INVALID_LIST_LENGTH; } CHIP_ERROR DefaultSceneTableImpl::unregisterHandler(uint8_t position) @@ -520,24 +489,61 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); // Remove scene entries - SceneTableData scene(fabric_index, fabric.first_scene); - size_t scene_count = 0; + SceneTableData scene(fabric_index); + scene.index = 0; - while (scene_count < fabric.scene_count) + while (scene.index < kMaxScenePerFabric) { - if (CHIP_NO_ERROR != scene.Load(mStorage)) - { - break; - } - RemoveSceneTableEntry(fabric_index, scene.storageId); - scene.storageId = scene.next; - scene_count++; + err = RemoveSceneTableEntryAtPosition(fabric_index, scene.index); + VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err, err); + scene.index++; } // Remove fabric return fabric.Delete(mStorage); } +/// @brief Finds the index where to insert current scene by going through the whole table and looking if the scene is already in +/// there and for the first empty index +/// @param storage Storage delegate in use +/// @param fabric Fabric in use +/// @param target_scene Storage Id of scene to store +/// @return CHIP_NO_ERROR if managed to find a suitable storage location, false otherwise +CHIP_ERROR DefaultSceneTableImpl::Find(PersistentStorageDelegate * storage, const FabricIndex & fabric_index, + SceneStorageId target_scene, bool & found, SceneIndex & idx) +{ + CHIP_ERROR err; + SceneTableData scene(fabric_index); + SceneIndex firstFreeIdx = kUndefinedSceneIndex; // storage index if scene not found + + while (scene.index < kMaxScenePerFabric) + { + err = scene.Load(mStorage); + VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); + if (scene.storageId == target_scene) + { + found = true; + idx = scene.index; + return CHIP_NO_ERROR; // return scene at current index if scene found + } + // check if index is free and if first free index wasn't found + if (err == CHIP_ERROR_NOT_FOUND && firstFreeIdx == kUndefinedSceneIndex) + { + firstFreeIdx = scene.index; + } + scene.index++; + } + + if (firstFreeIdx < kMaxScenePerFabric) + { + found = false; + idx = firstFreeIdx; + return CHIP_NO_ERROR; + } + + return CHIP_ERROR_INVALID_LIST_LENGTH; +} + DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntry(FabricIndex fabric_index) { VerifyOrReturnError(IsInitialized(), nullptr); @@ -551,9 +557,8 @@ DefaultSceneTableImpl::SceneEntryIteratorImpl::SceneEntryIteratorImpl(DefaultSce if (CHIP_NO_ERROR == fabric.Load(provider.mStorage)) { - mNextSceneId = fabric.first_scene; - mTotalScene = fabric.scene_count; - mSceneCount = 0; + mTotalScene = fabric.scene_count; + mSceneIndex = 0; } } @@ -564,16 +569,28 @@ size_t DefaultSceneTableImpl::SceneEntryIteratorImpl::Count() bool DefaultSceneTableImpl::SceneEntryIteratorImpl::Next(SceneTableEntry & output) { - VerifyOrReturnError(mSceneCount < mTotalScene, false); + CHIP_ERROR err; + VerifyOrReturnError(mSceneIndex < mTotalScene, false); - SceneTableData scene(mFabric, mNextSceneId); - VerifyOrReturnError(CHIP_NO_ERROR == scene.Load(mProvider.mStorage), false); + SceneTableData scene(mFabric, mSceneIndex); + + // looks for next available scene + while (scene.index < kMaxScenePerFabric) + { + err = scene.Load(mProvider.mStorage); + VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, false); + + scene.index++; + if (err == CHIP_NO_ERROR) + { + mSceneIndex = scene.index; + output.storageId = scene.storageId; + output.storageData = scene.storageData; + return true; + } + } - mSceneCount++; - mNextSceneId = scene.next; - output.storageId = scene.storageId; - output.storageData = scene.storageData; - return true; + return false; } void DefaultSceneTableImpl::SceneEntryIteratorImpl::Release() diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 0513e39dde5ae6..8596fe25601ea3 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -132,6 +132,7 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id, SceneTableEntry & entry) override; CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id) override; + CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) override; // SceneHandlers CHIP_ERROR registerHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function); @@ -163,9 +164,9 @@ class DefaultSceneTableImpl : public SceneTable protected: DefaultSceneTableImpl & mProvider; FabricIndex mFabric = kUndefinedFabricIndex; - SceneStorageId mNextSceneId; - size_t mSceneCount = 0; - size_t mTotalScene = 0; + SceneIndex mNextSceneIdx; + SceneIndex mSceneIndex = 0; + uint8_t mTotalScene = 0; }; bool IsInitialized() { return (mStorage != nullptr); } @@ -173,6 +174,10 @@ class DefaultSceneTableImpl : public SceneTable ObjectPool mSceneEntryIterators; SceneHandler handlers[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES]; uint8_t handlerNum = 0; + +private: + CHIP_ERROR Find(PersistentStorageDelegate * storage, const FabricIndex & fabric, SceneStorageId target_scene, bool & found, + SceneIndex & idx); }; // class DefaultSceneTableImpl /** diff --git a/src/app/clusters/scenes/ScenesTestConfig.h b/src/app/clusters/scenes/ScenesTestConfig.h new file mode 100644 index 00000000000000..74d7eb92021945 --- /dev/null +++ b/src/app/clusters/scenes/ScenesTestConfig.h @@ -0,0 +1,26 @@ +/** + * + * Copyright (c) 2023 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 + * + * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * + * 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. + */ + +#pragma once + +#define ZCL_USING_ON_OFF_CLUSTER_SERVER 1 +#define ZCL_USING_LEVEL_CONTROL_CLUSTER_SERVER 1 +//#define ZCL_USING_MODE_SELECT_CLUSTER_SERVER +#define ZCL_USING_COLOR_CONTROL_CLUSTER_SERVER 1 +//#define ZCL_USING_THERMOSTAT_CLUSTER_SERVER +//#define ZCL_USING_DOOR_LOCK_CLUSTER_SERVER +//#define ZCL_USING_WINDOW_COVERING_CLUSTER_SERVER \ No newline at end of file diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index fd97d9667bc202..484182f8afbc16 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -29,6 +29,10 @@ using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; using CharSpan = chip::CharSpan; using ExtensionFieldsSet = chip::scenes::ExtensionFieldsSet; +#define ON_OFF_CID 0x0006 +#define LV_CTR_CID 0x0008 +#define CO_CTR_CID 0x0300 + namespace { static chip::TestPersistentStorageDelegate testStorage; @@ -78,78 +82,74 @@ SceneTableEntry scene11(sceneId5, sceneData11); SceneTableEntry scene12(sceneId8, sceneData12); // EFS -static const ExtensionFieldsSet onOffEFS1 = ExtensionFieldsSet(0x0006, (uint8_t *) "1", 1); -static const ExtensionFieldsSet onOffEFS2 = ExtensionFieldsSet(0x0006, (uint8_t *) "0", 1); -static const ExtensionFieldsSet levelControlEFS1 = ExtensionFieldsSet(0x0008, (uint8_t *) "511", 3); -static const ExtensionFieldsSet levelControlEFS2 = ExtensionFieldsSet(0x0008, (uint8_t *) "222", 3); -static const ExtensionFieldsSet colorControlEFS1 = ExtensionFieldsSet(0x0303, (uint8_t *) "123456789abcde", 14); -static const ExtensionFieldsSet colorControlEFS2 = ExtensionFieldsSet(0x0303, (uint8_t *) "abcdefghi12345", 14); +static const ExtensionFieldsSet onOffEFS1 = ExtensionFieldsSet(ON_OFF_CID, (uint8_t *) "1", 1); +static const ExtensionFieldsSet onOffEFS2 = ExtensionFieldsSet(ON_OFF_CID, (uint8_t *) "0", 1); +static const ExtensionFieldsSet lvCtrEFS1 = ExtensionFieldsSet(LV_CTR_CID, (uint8_t *) "511", 3); +static const ExtensionFieldsSet lvCtrEFS2 = ExtensionFieldsSet(LV_CTR_CID, (uint8_t *) "222", 3); +static const ExtensionFieldsSet coCtrEFS1 = ExtensionFieldsSet(CO_CTR_CID, (uint8_t *) "123456789abcde", 14); +static const ExtensionFieldsSet coCtrEFS2 = ExtensionFieldsSet(CO_CTR_CID, (uint8_t *) "abcdefghi12345", 14); // Simulation of clusters callbacks (sate #1) -CHIP_ERROR test_on_off_from_cluster_callback1(ExtensionFieldsSet & fields) +CHIP_ERROR oo_from_cluster_cb1(ExtensionFieldsSet & fields) { ReturnErrorOnFailure(fields = onOffEFS1); return CHIP_NO_ERROR; } -CHIP_ERROR test_on_off_to_cluster_callback1(ExtensionFieldsSet & fields) +CHIP_ERROR oo_to_cluster_cb1(ExtensionFieldsSet & fields) { - VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_INVALID_ARGUMENT); return CHIP_NO_ERROR; } -CHIP_ERROR test_level_control_from_cluster_callback1(ExtensionFieldsSet & fields) +CHIP_ERROR lc_from_cluster_cb1(ExtensionFieldsSet & fields) { - ReturnErrorOnFailure(fields = levelControlEFS1); + ReturnErrorOnFailure(fields = lvCtrEFS1); return CHIP_NO_ERROR; } -CHIP_ERROR test_level_control_to_cluster_callback1(ExtensionFieldsSet & fields) +CHIP_ERROR lc_to_cluster_cb1(ExtensionFieldsSet & fields) { - VerifyOrReturnError(fields == levelControlEFS1, CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(fields == lvCtrEFS1, CHIP_ERROR_INVALID_ARGUMENT); return CHIP_NO_ERROR; } - -CHIP_ERROR test_color_control_from_cluster_callback1(ExtensionFieldsSet & fields) +CHIP_ERROR cc_from_cluster_cb1(ExtensionFieldsSet & fields) { - ReturnErrorOnFailure(fields = colorControlEFS1); + ReturnErrorOnFailure(fields = coCtrEFS1); return CHIP_NO_ERROR; } - -CHIP_ERROR test_color_control_to_cluster_callback1(ExtensionFieldsSet & fields) +CHIP_ERROR cc_to_cluster_cb1(ExtensionFieldsSet & fields) { - VerifyOrReturnError(fields == colorControlEFS1, CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(fields == coCtrEFS1, CHIP_ERROR_INVALID_ARGUMENT); return CHIP_NO_ERROR; } // Simulation of clusters callbacks (sate #2) -CHIP_ERROR test_on_off_from_cluster_callback2(ExtensionFieldsSet & fields) +CHIP_ERROR oo_from_cluster_cb2(ExtensionFieldsSet & fields) { ReturnErrorOnFailure(fields = onOffEFS1); return CHIP_NO_ERROR; } -CHIP_ERROR test_on_off_to_cluster_callback2(ExtensionFieldsSet & fields) +CHIP_ERROR oo_to_cluster_cb2(ExtensionFieldsSet & fields) { - VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_INVALID_ARGUMENT); return CHIP_NO_ERROR; } -CHIP_ERROR test_level_control_from_cluster_callback2(ExtensionFieldsSet & fields) +CHIP_ERROR lc_from_cluster_cb2(ExtensionFieldsSet & fields) { - ReturnErrorOnFailure(fields = levelControlEFS1); + ReturnErrorOnFailure(fields = lvCtrEFS2); return CHIP_NO_ERROR; } -CHIP_ERROR test_level_control_to_cluster_callback2(ExtensionFieldsSet & fields) +CHIP_ERROR lc_to_cluster_cb2(ExtensionFieldsSet & fields) { - VerifyOrReturnError(fields == levelControlEFS1, CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(fields == lvCtrEFS2, CHIP_ERROR_INVALID_ARGUMENT); return CHIP_NO_ERROR; } - -CHIP_ERROR test_color_control_from_cluster_callback2(ExtensionFieldsSet & fields) +CHIP_ERROR cc_from_cluster_cb2(ExtensionFieldsSet & fields) { - ReturnErrorOnFailure(fields = colorControlEFS1); + ReturnErrorOnFailure(fields = coCtrEFS2); return CHIP_NO_ERROR; } - -CHIP_ERROR test_color_control_to_cluster_callback2(ExtensionFieldsSet & fields) +CHIP_ERROR cc_to_cluster_cb2(ExtensionFieldsSet & fields) { - VerifyOrReturnError(fields == colorControlEFS1, CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(fields == coCtrEFS2, CHIP_ERROR_INVALID_ARGUMENT); return CHIP_NO_ERROR; } @@ -168,18 +168,9 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) ResetSceneTable(sceneTable); // Test SceneHandlers - NL_TEST_ASSERT( - aSuite, - CHIP_NO_ERROR == - sceneTable->registerHandler(onOffEFS1.ID, &test_on_off_from_cluster_callback1, &test_on_off_to_cluster_callback1)); - NL_TEST_ASSERT(aSuite, - CHIP_NO_ERROR == - sceneTable->registerHandler(levelControlEFS1.ID, &test_level_control_from_cluster_callback1, - &test_level_control_to_cluster_callback1)); - NL_TEST_ASSERT(aSuite, - CHIP_NO_ERROR == - sceneTable->registerHandler(colorControlEFS1.ID, &test_color_control_from_cluster_callback1, - &test_color_control_to_cluster_callback1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(onOffEFS1.ID, &oo_from_cluster_cb1, &oo_to_cluster_cb1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(lvCtrEFS1.ID, &lc_from_cluster_cb1, &lc_to_cluster_cb1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(coCtrEFS2.ID, &cc_from_cluster_cb1, &cc_to_cluster_cb1)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene1.storageData.extentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene2.storageData.extentsionFieldsSets)); @@ -205,6 +196,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Not Found NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId9, scene)); + // Get test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); @@ -239,18 +231,9 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable); // Test SceneHandlers overwrite - NL_TEST_ASSERT( - aSuite, - CHIP_NO_ERROR == - sceneTable->registerHandler(onOffEFS2.ID, &test_on_off_from_cluster_callback2, &test_on_off_to_cluster_callback2)); - NL_TEST_ASSERT(aSuite, - CHIP_NO_ERROR == - sceneTable->registerHandler(levelControlEFS2.ID, &test_level_control_from_cluster_callback2, - &test_level_control_to_cluster_callback2)); - NL_TEST_ASSERT(aSuite, - CHIP_NO_ERROR == - sceneTable->registerHandler(colorControlEFS2.ID, &test_color_control_from_cluster_callback2, - &test_color_control_to_cluster_callback2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(onOffEFS2.ID, &oo_from_cluster_cb2, &oo_to_cluster_cb2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(lvCtrEFS2.ID, &lc_from_cluster_cb2, &lc_to_cluster_cb2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(coCtrEFS2.ID, &cc_from_cluster_cb2, &cc_to_cluster_cb2)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene10.storageData.extentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene11.storageData.extentsionFieldsSets)); @@ -292,7 +275,6 @@ void TestIterateScenes(nlTestSuite * aSuite, void * aContext) if (iterator) { NL_TEST_ASSERT(aSuite, iterator->Count() == 8); - NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); @@ -329,7 +311,20 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); - iterator->Release(); + + // Adde scene in middle, a spot should have been freed + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene9)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 8); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId9, scene)); + NL_TEST_ASSERT(aSuite, scene == scene9); + + // Remove the recently added scene 9 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene9.storageId)); + iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator->Count() == 7); + NL_TEST_ASSERT(aSuite, iterator->Next(scene)); + NL_TEST_ASSERT(aSuite, scene == scene10); // Remove first NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.storageId)); @@ -381,6 +376,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); + iterator->Release(); } void TestFabricScenes(nlTestSuite * aSuite, void * aContext) @@ -393,10 +389,12 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) SceneTableEntry scene; + // Fabric 1 inserts NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene3)); + // Fabric 2 inserts NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene1)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene2)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene3)); @@ -422,7 +420,7 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); - // Confirm Fabric 2 still there + // Verify Fabric 2 still there NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); @@ -432,7 +430,7 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) // Remove Fabric 2 NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric2)); - // Verify Fabric 1 removed + // Verify Fabric 2 removed NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveFabric(kFabric2)); NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); @@ -470,9 +468,9 @@ int TestTeardown(void * inContext) int TestSceneTable() { static nlTest sTests[] = { - NL_TEST_DEF("TestFabricScenes", TestFabricScenes), NL_TEST_DEF("TestStoreScenes", TestStoreScenes), - NL_TEST_DEF("TestOverwriteScenes", TestOverwriteScenes), NL_TEST_DEF("TestIterateScenes", TestIterateScenes), - NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), NL_TEST_SENTINEL() + NL_TEST_DEF("TestStoreScenes", TestStoreScenes), NL_TEST_DEF("TestOverwriteScenes", TestOverwriteScenes), + NL_TEST_DEF("TestIterateScenes", TestIterateScenes), NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), + NL_TEST_DEF("TestFabricScenes", TestFabricScenes), NL_TEST_SENTINEL() }; nlTestSuite theSuite = { diff --git a/src/lib/core/DataModelTypes.h b/src/lib/core/DataModelTypes.h index 5bfbec2f3b6131..967deec0198bfe 100644 --- a/src/lib/core/DataModelTypes.h +++ b/src/lib/core/DataModelTypes.h @@ -40,6 +40,7 @@ typedef uint32_t EventId; typedef uint64_t EventNumber; typedef uint64_t FabricId; typedef uint8_t FabricIndex; +typedef uint8_t SceneIndex; typedef uint32_t FieldId; typedef uint16_t ListIndex; typedef uint16_t LocalizedStringIdentifier; @@ -63,6 +64,7 @@ constexpr ListIndex kInvalidListIndex = 0xFFFF; // List index is a uint16 thus constexpr KeysetId kInvalidKeysetId = 0xFFFF; constexpr SceneGroupID kGlobalGroupSceneId = CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID; +constexpr SceneIndex kUndefinedSceneIndex = 0xff; constexpr SceneId kUndefinedSceneId = CHIP_CONFIG_SCENES_TABLE_NULL_INDEX; constexpr SceneId kUnusedEndpointId = CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index f929082861aac9..689ac6fefba88d 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } @@ -198,12 +198,14 @@ class DefaultStorageKeyAllocator } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } // Scene Storage - static StorageKeyName SceneFabricList() { return StorageKeyName::FromConst("g/sfl"); } + static StorageKeyName SceneFabricList() + { + return StorageKeyName::FromConst("g/gfl"); + } // shares key with group fabric list to minimize flash usage static StorageKeyName FabricScenesKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } - static StorageKeyName FabricSceneKey(chip::FabricIndex fabric, chip::EndpointId endpoint, chip::GroupId group, - chip::SceneId scene) + static StorageKeyName FabricSceneKey(chip::FabricIndex fabric, uint8_t id) { - return StorageKeyName::Formatted("f/%x/s/e%xg%xs%x", fabric, endpoint, group, scene); + return StorageKeyName::Formatted("f/%x/s%x", fabric, id); } }; From 95dde658114a741d04daaa7972e73567e6e34555 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Thu, 9 Feb 2023 10:46:11 -0500 Subject: [PATCH 16/79] Reduced the number of loads necessary when accessing scenes stored in nvm by loading an array of storage IDs when loading the fabric scene data --- src/app/clusters/scenes/ExtensionFieldsSets.h | 3 + .../scenes/ExtensionFieldsSetsImpl.cpp | 14 +- .../clusters/scenes/ExtensionFieldsSetsImpl.h | 23 +- src/app/clusters/scenes/SceneTable.h | 7 +- src/app/clusters/scenes/SceneTableImpl.cpp | 316 ++++++++---------- src/app/clusters/scenes/SceneTableImpl.h | 4 - 6 files changed, 170 insertions(+), 197 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldsSets.h index 907d047fddeefb..c76f73de242e9f 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.h +++ b/src/app/clusters/scenes/ExtensionFieldsSets.h @@ -23,6 +23,9 @@ namespace chip { namespace scenes { +static constexpr uint8_t kMaxClusterPerScenes = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; +static constexpr uint8_t kMaxFieldsPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; + class ExtensionFieldsSets { public: diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index 4051e591b2a072..28fcdc8a06143d 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -29,7 +29,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Serialize(TLV::TLVWriter & writer) const ReturnErrorOnFailure(writer.Put(TagFieldNum(), static_cast(this->fieldNum))); if (!this->is_empty()) { - for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { if (!this->EFS[i].is_empty()) { @@ -64,7 +64,7 @@ void ExtensionFieldsSetsImpl::Clear() { if (!this->is_empty()) { - for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { this->EFS[i].Clear(); } @@ -84,7 +84,7 @@ bool ExtensionFieldsSetsImpl::is_empty() const CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) { uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; - for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { if (this->EFS[i].ID == field.ID) { @@ -99,12 +99,12 @@ CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) } // if found, insert at found position, otherwise at first free possition, otherwise return error - if (idPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + if (idPosition < kMaxClusterPerScenes) { ReturnErrorOnFailure(this->EFS[idPosition] = field); return CHIP_NO_ERROR; } - else if (fisrtEmptyPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + else if (fisrtEmptyPosition < kMaxClusterPerScenes) { ReturnErrorOnFailure(this->EFS[fisrtEmptyPosition] = field); this->fieldNum++; @@ -118,7 +118,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) CHIP_ERROR ExtensionFieldsSetsImpl::getFieldAtPosition(ExtensionFieldsSet & field, uint8_t position) { - if (position < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + if (position < kMaxClusterPerScenes) { ReturnErrorOnFailure(field = this->EFS[position]); } @@ -130,7 +130,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::removeFieldAtPosition(uint8_t position) { if (!this->is_empty()) { - if (position < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + if (position < kMaxClusterPerScenes) { if (!this->EFS[position].is_empty()) { diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h index 58438cfab192b3..f6a4137dd6f025 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h @@ -29,14 +29,14 @@ struct ExtensionFieldsSet { static constexpr TLV::Tag TagClusterId() { return TLV::ContextTag(1); } static constexpr TLV::Tag TagEFS() { return TLV::ContextTag(2); } - clusterId ID = kInvalidClusterId; - uint8_t bytesBuffer[CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER] = { 0 }; - uint8_t usedBytes = 0; + clusterId ID = kInvalidClusterId; + uint8_t bytesBuffer[kMaxFieldsPerCluster] = { 0 }; + uint8_t usedBytes = 0; ExtensionFieldsSet() = default; ExtensionFieldsSet(clusterId cID, uint8_t * data, uint8_t dataSize) : ID(cID), usedBytes(dataSize) { - if (dataSize <= CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER) + if (dataSize <= kMaxFieldsPerCluster) { memcpy(bytesBuffer, data, usedBytes); } @@ -65,16 +65,15 @@ struct ExtensionFieldsSet ReturnErrorOnFailure(reader.Next(TagEFS())); ReturnErrorOnFailure(reader.Get(buffer)); - if (buffer.size() > CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER) + if (buffer.size() > kMaxFieldsPerCluster) { - this->usedBytes = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; + this->usedBytes = kMaxFieldsPerCluster; } else { this->usedBytes = static_cast(buffer.size()); } memcpy(this->bytesBuffer, buffer.data(), this->usedBytes); - // ReturnErrorOnFailure(reader.GetBytes(bytesBuffer, CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER)); return reader.ExitContainer(container); } @@ -82,7 +81,7 @@ struct ExtensionFieldsSet void Clear() { this->ID = kInvalidClusterId; - memset(this->bytesBuffer, 0, CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER); + memset(this->bytesBuffer, 0, kMaxFieldsPerCluster); this->usedBytes = 0; } @@ -96,7 +95,7 @@ struct ExtensionFieldsSet CHIP_ERROR operator=(const ExtensionFieldsSet & other) { - if (other.usedBytes <= CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER) + if (other.usedBytes <= kMaxFieldsPerCluster) { memcpy(this->bytesBuffer, other.bytesBuffer, other.usedBytes); } @@ -130,7 +129,7 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets bool operator==(const ExtensionFieldsSetsImpl & other) { - for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { if (!(this->EFS[i] == other.EFS[i])) { @@ -142,7 +141,7 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets CHIP_ERROR operator=(const ExtensionFieldsSetsImpl & other) { - for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { ReturnErrorOnFailure(this->EFS[i] = other.EFS[i]); } @@ -153,7 +152,7 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets protected: static constexpr TLV::Tag TagFieldNum() { return TLV::ContextTag(1); } - ExtensionFieldsSet EFS[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES]; + ExtensionFieldsSet EFS[kMaxClusterPerScenes]; uint8_t fieldNum = 0; }; } // namespace scenes diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 3fa0f0d2867453..b1b57df8d4774c 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -29,12 +29,13 @@ namespace scenes { typedef uint16_t SceneTransitionTime; typedef uint8_t TransitionTime100ms; +static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; + class SceneTable { public: - static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_GROUP_CONCURRENT_ITERATORS; - static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; - static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; + static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_GROUP_CONCURRENT_ITERATORS; + static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; /// @brief struct used to identify a scene in storage by 3 ids, endpoint, group and scene struct SceneStorageId diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index f550279255afbf..49e23daf3eb804 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -37,6 +37,55 @@ struct FabricHavingSceneList : public CommonPersistentData::FabricList static constexpr size_t kPersistentBufferMax = 128; +struct SceneTableData : public SceneTableEntry, PersistentData +{ + FabricIndex fabric_index = kUndefinedFabricIndex; + SceneIndex index = 0; + bool first = true; + + SceneTableData() : SceneTableEntry() {} + SceneTableData(FabricIndex fabric) : fabric_index(fabric) {} + SceneTableData(FabricIndex fabric, SceneIndex idx) : fabric_index(fabric), index(idx) {} + SceneTableData(FabricIndex fabric, SceneStorageId storageId) : SceneTableEntry(storageId), fabric_index(fabric) {} + SceneTableData(FabricIndex fabric, SceneStorageId storageId, SceneData data) : + SceneTableEntry(storageId, data), fabric_index(fabric) + {} + + CHIP_ERROR UpdateKey(StorageKeyName & key) override + { + VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX); + key = DefaultStorageKeyAllocator::FabricSceneKey(fabric_index, index); + return CHIP_NO_ERROR; + } + + void Clear() override { storageData.Clear(); } + + CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override + { + TLV::TLVType container; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); + + ReturnErrorOnFailure(storageId.Serialize(writer)); + ReturnErrorOnFailure(storageData.Serialize(writer)); + + return writer.EndContainer(container); + } + + CHIP_ERROR Deserialize(TLV::TLVReader & reader) override + { + ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); + VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); + + TLV::TLVType container; + ReturnErrorOnFailure(reader.EnterContainer(container)); + + ReturnErrorOnFailure(storageId.Deserialize(reader)); + ReturnErrorOnFailure(storageData.Deserialize(reader)); + + return reader.ExitContainer(container); + } +}; + /** * @brief Linked list of all scenes in a fabric, stored in persistent memory * @@ -50,7 +99,8 @@ struct FabricSceneData : public PersistentData FabricIndex fabric_index = kUndefinedFabricIndex; uint8_t scene_count = 0; - FabricIndex next = kUndefinedFabricIndex; + SceneStorageId scene_map[kMaxScenePerFabric]; + FabricIndex next = kUndefinedFabricIndex; FabricSceneData() = default; FabricSceneData(FabricIndex fabric) : fabric_index(fabric) {} @@ -65,7 +115,11 @@ struct FabricSceneData : public PersistentData void Clear() override { scene_count = 0; - next = kUndefinedFabricIndex; + for (uint8_t i = 0; i < kMaxScenePerFabric; i++) + { + scene_map[i].Clear(); + } + next = kUndefinedFabricIndex; } CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override @@ -74,6 +128,10 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); ReturnErrorOnFailure(writer.Put(TagSceneCount(), static_cast(scene_count))); + for (uint8_t i = 0; i < kMaxScenePerFabric; i++) + { + ReturnErrorOnFailure(scene_map[i].Serialize(writer)); + } ReturnErrorOnFailure(writer.Put(TagNext(), static_cast(next))); return writer.EndContainer(container); @@ -89,6 +147,10 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(reader.Next(TagSceneCount())); ReturnErrorOnFailure(reader.Get(scene_count)); + for (uint8_t i = 0; i < kMaxScenePerFabric; i++) + { + ReturnErrorOnFailure(scene_map[i].Deserialize(reader)); + } ReturnErrorOnFailure(reader.Next(TagNext())); ReturnErrorOnFailure(reader.Get(next)); @@ -174,29 +236,39 @@ struct FabricSceneData : public PersistentData // Fabric not in the list return CHIP_ERROR_NOT_FOUND; } - - // Check the fabric is registered in the fabrics' linked list - CHIP_ERROR Validate(PersistentStorageDelegate * storage) const + /// @brief Finds the index where to insert current scene by going through the whole table and looking if the scene is already in + /// there and for the first empty index + /// @param storage Storage delegate in use + /// @param fabric Fabric in use + /// @param target_scene Storage Id of scene to store + /// @return CHIP_NO_ERROR if managed to find a suitable storage location, false otherwise + CHIP_ERROR Find(SceneStorageId target_scene, SceneIndex & idx) { - FabricHavingSceneList fabric_list; - ReturnErrorOnFailure(fabric_list.Load(storage)); - - // Existing fabric list, search for existing entry - FabricSceneData fabric(fabric_list.first_entry); + SceneIndex firstFreeIdx = kUndefinedSceneIndex; // storage index if scene not found + uint8_t index = 0; - for (size_t i = 0; i < fabric_list.entry_count; i++) + while (index < kMaxScenePerFabric) { - ReturnErrorOnFailure(fabric.Load(storage)); - if (fabric.fabric_index == this->fabric_index) + if (scene_map[index] == target_scene) { - return CHIP_NO_ERROR; + idx = index; + return CHIP_NO_ERROR; // return scene at current index if scene found } - fabric.fabric_index = fabric.next; + else if (scene_map[index].sceneEndpointId == kInvalidEndpointId && firstFreeIdx == kUndefinedSceneIndex) + { + firstFreeIdx = index; + } + index++; } - // Fabric not in the list - return CHIP_ERROR_NOT_FOUND; - } + if (firstFreeIdx < kMaxScenePerFabric) + { + idx = firstFreeIdx; + return CHIP_ERROR_NOT_FOUND; + } + + return CHIP_ERROR_BUFFER_TOO_SMALL; + } CHIP_ERROR Save(PersistentStorageDelegate * storage) override { ReturnErrorOnFailure(Register(storage)); @@ -208,56 +280,47 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(Unregister(storage)); return PersistentData::Delete(storage); } -}; - -struct SceneTableData : public SceneTableEntry, PersistentData -{ - static constexpr TLV::Tag TagNext() { return TLV::ContextTag(1); } - - FabricIndex fabric_index = kUndefinedFabricIndex; - SceneIndex index = 0; - bool first = true; - - SceneTableData() : SceneTableEntry() {} - SceneTableData(FabricIndex fabric) : fabric_index(fabric) {} - SceneTableData(FabricIndex fabric, SceneIndex idx) : fabric_index(fabric), index(idx) {} - SceneTableData(FabricIndex fabric, SceneStorageId storageId) : SceneTableEntry(storageId), fabric_index(fabric) {} - SceneTableData(FabricIndex fabric, SceneStorageId storageId, SceneData data) : - SceneTableEntry(storageId, data), fabric_index(fabric) - {} - - CHIP_ERROR UpdateKey(StorageKeyName & key) override + CHIP_ERROR SaveScene(PersistentStorageDelegate * storage, const SceneTableEntry & entry) { - VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX); - key = DefaultStorageKeyAllocator::FabricSceneKey(fabric_index, index); - return CHIP_NO_ERROR; - } + CHIP_ERROR err; + SceneTableData scene(fabric_index, entry.storageId, entry.storageData); + // Look for empty storage space - void Clear() override { storageData.Clear(); } + err = this->Find(entry.storageId, scene.index); - CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override - { - TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); + if (CHIP_NO_ERROR == err) + { - ReturnErrorOnFailure(storageId.Serialize(writer)); - ReturnErrorOnFailure(storageData.Serialize(writer)); + return scene.Save(storage); + } + else if (CHIP_ERROR_NOT_FOUND == err) // If not found, scene.index should be the first free index + { + scene_count++; + scene_map[scene.index] = scene.storageId; + ReturnErrorOnFailure(this->Save(storage)); - return writer.EndContainer(container); + return scene.Save(storage); + } + + return CHIP_ERROR_INVALID_LIST_LENGTH; } - CHIP_ERROR Deserialize(TLV::TLVReader & reader) override + CHIP_ERROR RemoveScene(PersistentStorageDelegate * storage, const SceneStorageId & scene_id) { - ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); - VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); + SceneTableData scene(fabric_index, scene_id); + // Look for empty storage space - TLV::TLVType container; - ReturnErrorOnFailure(reader.EnterContainer(container)); + VerifyOrReturnError(this->Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); + ReturnErrorOnFailure(scene.Delete(storage)); - ReturnErrorOnFailure(storageId.Deserialize(reader)); - ReturnErrorOnFailure(storageData.Deserialize(reader)); + if (scene_count > 0) + { + scene_count--; + scene_map[scene.index].Clear(); + ReturnErrorOnFailure(this->Save(storage)); + } - return reader.ExitContainer(container); + return CHIP_NO_ERROR; } }; @@ -282,48 +345,22 @@ CHIP_ERROR DefaultSceneTableImpl::SetSceneTableEntry(FabricIndex fabric_index, c VerifyOrReturnError(IsInitialized(), CHIP_ERROR_INTERNAL); FabricSceneData fabric(fabric_index); - SceneTableData scene(fabric_index); - bool foundIndex = false; - - scene.index = 0; // Load fabric data (defaults to zero) CHIP_ERROR err = fabric.Load(mStorage); VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); - scene.storageId = entry.storageId; - scene.storageData = entry.storageData; - - // Look for empty storage space - if (CHIP_NO_ERROR == Find(mStorage, fabric_index, entry.storageId, foundIndex, scene.index)) - { - if (foundIndex) - { - // Existing scene - return scene.Save(mStorage); - } - else if (scene.index < kMaxScenePerFabric) - { - fabric.scene_count++; - ReturnErrorOnFailure(fabric.Save(mStorage)); - - return scene.Save(mStorage); - } - } - - return CHIP_ERROR_INVALID_LIST_LENGTH; + return fabric.SaveScene(mStorage, entry); } CHIP_ERROR DefaultSceneTableImpl::GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) { FabricSceneData fabric(fabric_index); SceneTableData scene(fabric_index); - bool foundIndex = false; ReturnErrorOnFailure(fabric.Load(mStorage)); - VerifyOrReturnError(Find(mStorage, fabric_index, scene_id, foundIndex, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); - VerifyOrReturnError(foundIndex, CHIP_ERROR_NOT_FOUND); + VerifyOrReturnError(fabric.Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); - scene.Load(mStorage); + ReturnErrorOnFailure(scene.Load(mStorage)); entry.storageId = scene.storageId; entry.storageData = scene.storageData; @@ -332,23 +369,10 @@ CHIP_ERROR DefaultSceneTableImpl::GetSceneTableEntry(FabricIndex fabric_index, S CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) { FabricSceneData fabric(fabric_index); - SceneTableData scene(fabric_index); - bool foundIndex = false; ReturnErrorOnFailure(fabric.Load(mStorage)); - VerifyOrReturnError(Find(mStorage, fabric_index, scene_id, foundIndex, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); - VerifyOrReturnError(foundIndex, CHIP_ERROR_NOT_FOUND); - - ReturnErrorOnFailure(scene.Delete(mStorage)); - - if (fabric.scene_count > 0) - { - fabric.scene_count--; - ReturnErrorOnFailure(fabric.Save(mStorage)); - } - - return CHIP_NO_ERROR; + return fabric.RemoveScene(mStorage, scene_id); } /// @brief This function is meant to provide a way to empty the scene table without knowing any specific scene Id. Outisde of this @@ -464,14 +488,11 @@ CHIP_ERROR DefaultSceneTableImpl::EFSValuesToCluster(ExtensionFieldsSetsImpl & f if (!EFS.is_empty()) { - if (!this->handlerListEmpty()) + for (uint8_t j = 0; j < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; j++) { - for (uint8_t j = 0; j < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; j++) + if (EFS.ID == this->handlers[j].getID()) { - if (EFS.ID == this->handlers[j].getID()) - { - ReturnErrorOnFailure(this->handlers[j].setClusterEFS(EFS)); - } + ReturnErrorOnFailure(this->handlers[j].setClusterEFS(EFS)); } } } @@ -484,66 +505,21 @@ CHIP_ERROR DefaultSceneTableImpl::EFSValuesToCluster(ExtensionFieldsSetsImpl & f CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) { FabricSceneData fabric(fabric_index); - + SceneIndex idx = 0; CHIP_ERROR err = fabric.Load(mStorage); VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); - // Remove scene entries - SceneTableData scene(fabric_index); - scene.index = 0; - - while (scene.index < kMaxScenePerFabric) + while (idx < kMaxScenePerFabric) { - err = RemoveSceneTableEntryAtPosition(fabric_index, scene.index); + err = RemoveSceneTableEntryAtPosition(fabric_index, idx); VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err, err); - scene.index++; + idx++; } // Remove fabric return fabric.Delete(mStorage); } -/// @brief Finds the index where to insert current scene by going through the whole table and looking if the scene is already in -/// there and for the first empty index -/// @param storage Storage delegate in use -/// @param fabric Fabric in use -/// @param target_scene Storage Id of scene to store -/// @return CHIP_NO_ERROR if managed to find a suitable storage location, false otherwise -CHIP_ERROR DefaultSceneTableImpl::Find(PersistentStorageDelegate * storage, const FabricIndex & fabric_index, - SceneStorageId target_scene, bool & found, SceneIndex & idx) -{ - CHIP_ERROR err; - SceneTableData scene(fabric_index); - SceneIndex firstFreeIdx = kUndefinedSceneIndex; // storage index if scene not found - - while (scene.index < kMaxScenePerFabric) - { - err = scene.Load(mStorage); - VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); - if (scene.storageId == target_scene) - { - found = true; - idx = scene.index; - return CHIP_NO_ERROR; // return scene at current index if scene found - } - // check if index is free and if first free index wasn't found - if (err == CHIP_ERROR_NOT_FOUND && firstFreeIdx == kUndefinedSceneIndex) - { - firstFreeIdx = scene.index; - } - scene.index++; - } - - if (firstFreeIdx < kMaxScenePerFabric) - { - found = false; - idx = firstFreeIdx; - return CHIP_NO_ERROR; - } - - return CHIP_ERROR_INVALID_LIST_LENGTH; -} - DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntry(FabricIndex fabric_index) { VerifyOrReturnError(IsInitialized(), nullptr); @@ -554,12 +530,9 @@ DefaultSceneTableImpl::SceneEntryIteratorImpl::SceneEntryIteratorImpl(DefaultSce mProvider(provider), mFabric(fabric_index) { FabricSceneData fabric(fabric_index); - if (CHIP_NO_ERROR == fabric.Load(provider.mStorage)) - { - - mTotalScene = fabric.scene_count; - mSceneIndex = 0; - } + ReturnOnFailure(fabric.Load(provider.mStorage)); + mTotalScene = fabric.scene_count; + mSceneIndex = 0; } size_t DefaultSceneTableImpl::SceneEntryIteratorImpl::Count() @@ -569,25 +542,26 @@ size_t DefaultSceneTableImpl::SceneEntryIteratorImpl::Count() bool DefaultSceneTableImpl::SceneEntryIteratorImpl::Next(SceneTableEntry & output) { - CHIP_ERROR err; - VerifyOrReturnError(mSceneIndex < mTotalScene, false); + FabricSceneData fabric(mFabric); + SceneTableData scene(mFabric); - SceneTableData scene(mFabric, mSceneIndex); + VerifyOrReturnError(fabric.Load(mProvider.mStorage) == CHIP_NO_ERROR, false); // looks for next available scene - while (scene.index < kMaxScenePerFabric) + while (mSceneIndex < kMaxScenePerFabric) { - err = scene.Load(mProvider.mStorage); - VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, false); - - scene.index++; - if (err == CHIP_NO_ERROR) + if (fabric.scene_map[mSceneIndex].sceneEndpointId != kInvalidEndpointId) { - mSceneIndex = scene.index; + scene.index = mSceneIndex; + VerifyOrReturnError(scene.Load(mProvider.mStorage) == CHIP_NO_ERROR, false); output.storageId = scene.storageId; output.storageData = scene.storageData; + mSceneIndex++; + return true; } + + mSceneIndex++; } return false; diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 8596fe25601ea3..cfe1e55b64936f 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -174,10 +174,6 @@ class DefaultSceneTableImpl : public SceneTable ObjectPool mSceneEntryIterators; SceneHandler handlers[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES]; uint8_t handlerNum = 0; - -private: - CHIP_ERROR Find(PersistentStorageDelegate * storage, const FabricIndex & fabric, SceneStorageId target_scene, bool & found, - SceneIndex & idx); }; // class DefaultSceneTableImpl /** From 6d8e8f474374000715b54d81d9d0a16901c9e8e4 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Thu, 9 Feb 2023 11:02:36 -0500 Subject: [PATCH 17/79] Removed unused file --- src/app/clusters/scenes/ScenesTestConfig.h | 26 ---------------------- 1 file changed, 26 deletions(-) delete mode 100644 src/app/clusters/scenes/ScenesTestConfig.h diff --git a/src/app/clusters/scenes/ScenesTestConfig.h b/src/app/clusters/scenes/ScenesTestConfig.h deleted file mode 100644 index 74d7eb92021945..00000000000000 --- a/src/app/clusters/scenes/ScenesTestConfig.h +++ /dev/null @@ -1,26 +0,0 @@ -/** - * - * Copyright (c) 2023 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 - * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ - * - * 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. - */ - -#pragma once - -#define ZCL_USING_ON_OFF_CLUSTER_SERVER 1 -#define ZCL_USING_LEVEL_CONTROL_CLUSTER_SERVER 1 -//#define ZCL_USING_MODE_SELECT_CLUSTER_SERVER -#define ZCL_USING_COLOR_CONTROL_CLUSTER_SERVER 1 -//#define ZCL_USING_THERMOSTAT_CLUSTER_SERVER -//#define ZCL_USING_DOOR_LOCK_CLUSTER_SERVER -//#define ZCL_USING_WINDOW_COVERING_CLUSTER_SERVER \ No newline at end of file From 5622c800fc727aae947f9795b73455c01d6e817d Mon Sep 17 00:00:00 2001 From: Junior Martinez Date: Thu, 9 Feb 2023 16:26:47 -0500 Subject: [PATCH 18/79] styling --- scripts/examples/gn_efr32_example.sh | 7 +++---- src/app/clusters/scenes/SceneTable.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/scripts/examples/gn_efr32_example.sh b/scripts/examples/gn_efr32_example.sh index 5e5a9bdef2e32e..49ff6ce7cc6787 100755 --- a/scripts/examples/gn_efr32_example.sh +++ b/scripts/examples/gn_efr32_example.sh @@ -201,10 +201,9 @@ else if [ "$1" =~ *"use_rs9116=true"* ] || [ "$1" =~ *"use_SiWx917=true"* ] || [ "$1" =~ *"use_wf200=true"* ]; then USE_WIFI=true fi - - optArgs+=$1" " - shift - ;; + optArgs+=$1" " + shift + ;; esac done diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index b1b57df8d4774c..e2960de8f5d006 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -251,7 +251,7 @@ class SceneTable virtual ~SceneTable() = default; // Not copyable - SceneTable(const SceneTable &) = delete; + SceneTable(const SceneTable &) = delete; SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; From acfe9c6e2bbc15777027fc12546454b33da77370 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Fri, 10 Feb 2023 14:35:19 -0500 Subject: [PATCH 19/79] refactored members names to mMember to avoid shadowing errors --- .../scenes/ExtensionFieldsSetsImpl.cpp | 36 ++--- .../clusters/scenes/ExtensionFieldsSetsImpl.h | 52 +++---- src/app/clusters/scenes/SceneTable.h | 130 +++++++++--------- src/app/clusters/scenes/SceneTableImpl.cpp | 30 ++-- 4 files changed, 124 insertions(+), 124 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index 28fcdc8a06143d..c7ac0e8b1eacbf 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -26,14 +26,14 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TagFieldNum(), static_cast(this->fieldNum))); + ReturnErrorOnFailure(writer.Put(TagFieldNum(), static_cast(this->mFieldNum))); if (!this->is_empty()) { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - if (!this->EFS[i].is_empty()) + if (!this->mEFS[i].is_empty()) { - LogErrorOnFailure(this->EFS[i].Serialize(writer)); + LogErrorOnFailure(this->mEFS[i].Serialize(writer)); } } } @@ -48,13 +48,13 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Deserialize(TLV::TLVReader & reader) ReturnErrorOnFailure(reader.EnterContainer(container)); ReturnErrorOnFailure(reader.Next(TagFieldNum())); - ReturnErrorOnFailure(reader.Get(this->fieldNum)); + ReturnErrorOnFailure(reader.Get(this->mFieldNum)); if (!this->is_empty()) { - for (uint8_t i = 0; i < this->fieldNum; i++) + for (uint8_t i = 0; i < this->mFieldNum; i++) { - ReturnErrorOnFailure(this->EFS[i].Deserialize(reader)); + ReturnErrorOnFailure(this->mEFS[i].Deserialize(reader)); } } @@ -66,15 +66,15 @@ void ExtensionFieldsSetsImpl::Clear() { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - this->EFS[i].Clear(); + this->mEFS[i].Clear(); } } - this->fieldNum = 0; + this->mFieldNum = 0; } bool ExtensionFieldsSetsImpl::is_empty() const { - return (this->fieldNum <= 0); + return (this->mFieldNum <= 0); } /// @brief Inserts a field set into the array of extension field sets for a scene entry if the same ID is present in the EFS array, @@ -86,13 +86,13 @@ CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - if (this->EFS[i].ID == field.ID) + if (this->mEFS[i].mID == field.mID) { idPosition = i; break; } - if (this->EFS[i].is_empty() && fisrtEmptyPosition == 0xFF) + if (this->mEFS[i].is_empty() && fisrtEmptyPosition == 0xFF) { fisrtEmptyPosition = i; } @@ -101,13 +101,13 @@ CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) // if found, insert at found position, otherwise at first free possition, otherwise return error if (idPosition < kMaxClusterPerScenes) { - ReturnErrorOnFailure(this->EFS[idPosition] = field); + ReturnErrorOnFailure(this->mEFS[idPosition] = field); return CHIP_NO_ERROR; } else if (fisrtEmptyPosition < kMaxClusterPerScenes) { - ReturnErrorOnFailure(this->EFS[fisrtEmptyPosition] = field); - this->fieldNum++; + ReturnErrorOnFailure(this->mEFS[fisrtEmptyPosition] = field); + this->mFieldNum++; return CHIP_NO_ERROR; } else @@ -120,7 +120,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::getFieldAtPosition(ExtensionFieldsSet & fiel { if (position < kMaxClusterPerScenes) { - ReturnErrorOnFailure(field = this->EFS[position]); + ReturnErrorOnFailure(field = this->mEFS[position]); } return CHIP_NO_ERROR; @@ -132,10 +132,10 @@ CHIP_ERROR ExtensionFieldsSetsImpl::removeFieldAtPosition(uint8_t position) { if (position < kMaxClusterPerScenes) { - if (!this->EFS[position].is_empty()) + if (!this->mEFS[position].is_empty()) { - this->EFS[position].Clear(); - this->fieldNum--; + this->mEFS[position].Clear(); + this->mFieldNum--; } } else diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h index f6a4137dd6f025..5249c735cc8d90 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h @@ -29,16 +29,16 @@ struct ExtensionFieldsSet { static constexpr TLV::Tag TagClusterId() { return TLV::ContextTag(1); } static constexpr TLV::Tag TagEFS() { return TLV::ContextTag(2); } - clusterId ID = kInvalidClusterId; - uint8_t bytesBuffer[kMaxFieldsPerCluster] = { 0 }; - uint8_t usedBytes = 0; + clusterId mID = kInvalidClusterId; + uint8_t mBytesBuffer[kMaxFieldsPerCluster] = { 0 }; + uint8_t mUsedBytes = 0; ExtensionFieldsSet() = default; - ExtensionFieldsSet(clusterId cID, uint8_t * data, uint8_t dataSize) : ID(cID), usedBytes(dataSize) + ExtensionFieldsSet(clusterId cmID, uint8_t * data, uint8_t dataSize) : mID(cmID), mUsedBytes(dataSize) { if (dataSize <= kMaxFieldsPerCluster) { - memcpy(bytesBuffer, data, usedBytes); + memcpy(mBytesBuffer, data, mUsedBytes); } } ~ExtensionFieldsSet() = default; @@ -48,8 +48,8 @@ struct ExtensionFieldsSet TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TagClusterId(), static_cast(this->ID))); - ReturnErrorOnFailure(writer.PutBytes(TagEFS(), bytesBuffer, usedBytes)); + ReturnErrorOnFailure(writer.Put(TagClusterId(), static_cast(this->mID))); + ReturnErrorOnFailure(writer.PutBytes(TagEFS(), mBytesBuffer, mUsedBytes)); return writer.EndContainer(container); } @@ -61,50 +61,50 @@ struct ExtensionFieldsSet ReturnErrorOnFailure(reader.EnterContainer(container)); ReturnErrorOnFailure(reader.Next(TagClusterId())); - ReturnErrorOnFailure(reader.Get(this->ID)); + ReturnErrorOnFailure(reader.Get(this->mID)); ReturnErrorOnFailure(reader.Next(TagEFS())); ReturnErrorOnFailure(reader.Get(buffer)); if (buffer.size() > kMaxFieldsPerCluster) { - this->usedBytes = kMaxFieldsPerCluster; + this->mUsedBytes = kMaxFieldsPerCluster; } else { - this->usedBytes = static_cast(buffer.size()); + this->mUsedBytes = static_cast(buffer.size()); } - memcpy(this->bytesBuffer, buffer.data(), this->usedBytes); + memcpy(this->mBytesBuffer, buffer.data(), this->mUsedBytes); return reader.ExitContainer(container); } void Clear() { - this->ID = kInvalidClusterId; - memset(this->bytesBuffer, 0, kMaxFieldsPerCluster); - this->usedBytes = 0; + this->mID = kInvalidClusterId; + memset(this->mBytesBuffer, 0, kMaxFieldsPerCluster); + this->mUsedBytes = 0; } - bool is_empty() const { return (this->usedBytes == 0); } + bool is_empty() const { return (this->mUsedBytes == 0); } bool operator==(const ExtensionFieldsSet & other) { - return (this->ID == other.ID && !memcmp(this->bytesBuffer, other.bytesBuffer, this->usedBytes) && - this->usedBytes == other.usedBytes); + return (this->mID == other.mID && !memcmp(this->mBytesBuffer, other.mBytesBuffer, this->mUsedBytes) && + this->mUsedBytes == other.mUsedBytes); } CHIP_ERROR operator=(const ExtensionFieldsSet & other) { - if (other.usedBytes <= kMaxFieldsPerCluster) + if (other.mUsedBytes <= kMaxFieldsPerCluster) { - memcpy(this->bytesBuffer, other.bytesBuffer, other.usedBytes); + memcpy(this->mBytesBuffer, other.mBytesBuffer, other.mUsedBytes); } else { return CHIP_ERROR_BUFFER_TOO_SMALL; } - this->ID = other.ID; - this->usedBytes = other.usedBytes; + this->mID = other.mID; + this->mUsedBytes = other.mUsedBytes; return CHIP_NO_ERROR; } @@ -131,7 +131,7 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - if (!(this->EFS[i] == other.EFS[i])) + if (!(this->mEFS[i] == other.mEFS[i])) { return false; } @@ -143,17 +143,17 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - ReturnErrorOnFailure(this->EFS[i] = other.EFS[i]); + ReturnErrorOnFailure(this->mEFS[i] = other.mEFS[i]); } - fieldNum = other.fieldNum; + mFieldNum = other.mFieldNum; return CHIP_NO_ERROR; } protected: static constexpr TLV::Tag TagFieldNum() { return TLV::ContextTag(1); } - ExtensionFieldsSet EFS[kMaxClusterPerScenes]; - uint8_t fieldNum = 0; + ExtensionFieldsSet mEFS[kMaxClusterPerScenes]; + uint8_t mFieldNum = 0; }; } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index e2960de8f5d006..431082e75904eb 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -45,26 +45,26 @@ class SceneTable static constexpr TLV::Tag TagFirstSceneID() { return TLV::ContextTag(3); } // Identifies endpoint to which this scene applies to - EndpointId sceneEndpointId = kInvalidEndpointId; + EndpointId mSceneEndpointId = kInvalidEndpointId; // Identifies group within the scope of the given fabric - SceneGroupID sceneGroupId = kGlobalGroupSceneId; - SceneId sceneId = kUndefinedSceneId; + SceneGroupID mSceneGroupId = kGlobalGroupSceneId; + SceneId mSceneId = kUndefinedSceneId; SceneStorageId() = default; SceneStorageId(EndpointId endpoint, SceneId id, SceneGroupID groupId = kGlobalGroupSceneId) : - sceneEndpointId(endpoint), sceneGroupId(groupId), sceneId(id) + mSceneEndpointId(endpoint), mSceneGroupId(groupId), mSceneId(id) {} SceneStorageId(const SceneStorageId & storageId) : - sceneEndpointId(storageId.sceneEndpointId), sceneGroupId(storageId.sceneGroupId), sceneId(storageId.sceneId) + mSceneEndpointId(storageId.mSceneEndpointId), mSceneGroupId(storageId.mSceneGroupId), mSceneId(storageId.mSceneId) {} CHIP_ERROR Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TagFirstSceneEndpointID(), static_cast(this->sceneEndpointId))); - ReturnErrorOnFailure(writer.Put(TagFirstSceneGroupID(), static_cast(this->sceneGroupId))); - ReturnErrorOnFailure(writer.Put(TagFirstSceneID(), static_cast(this->sceneId))); + ReturnErrorOnFailure(writer.Put(TagFirstSceneEndpointID(), static_cast(this->mSceneEndpointId))); + ReturnErrorOnFailure(writer.Put(TagFirstSceneGroupID(), static_cast(this->mSceneGroupId))); + ReturnErrorOnFailure(writer.Put(TagFirstSceneID(), static_cast(this->mSceneId))); return writer.EndContainer(container); } @@ -75,31 +75,31 @@ class SceneTable ReturnErrorOnFailure(reader.EnterContainer(container)); ReturnErrorOnFailure(reader.Next(TagFirstSceneEndpointID())); - ReturnErrorOnFailure(reader.Get(this->sceneEndpointId)); + ReturnErrorOnFailure(reader.Get(this->mSceneEndpointId)); ReturnErrorOnFailure(reader.Next(TagFirstSceneGroupID())); - ReturnErrorOnFailure(reader.Get(this->sceneGroupId)); + ReturnErrorOnFailure(reader.Get(this->mSceneGroupId)); ReturnErrorOnFailure(reader.Next(TagFirstSceneID())); - ReturnErrorOnFailure(reader.Get(this->sceneId)); + ReturnErrorOnFailure(reader.Get(this->mSceneId)); return reader.ExitContainer(container); } void Clear() { - sceneEndpointId = kInvalidEndpointId; - sceneGroupId = kGlobalGroupSceneId; - sceneId = kUndefinedSceneId; + mSceneEndpointId = kInvalidEndpointId; + mSceneGroupId = kGlobalGroupSceneId; + mSceneId = kUndefinedSceneId; } bool operator==(const SceneStorageId & other) { - return (this->sceneEndpointId == other.sceneEndpointId && this->sceneGroupId == other.sceneGroupId && - this->sceneId == other.sceneId); + return (this->mSceneEndpointId == other.mSceneEndpointId && this->mSceneGroupId == other.mSceneGroupId && + this->mSceneId == other.mSceneId); } void operator=(const SceneStorageId & other) { - this->sceneEndpointId = other.sceneEndpointId; - this->sceneGroupId = other.sceneGroupId; - this->sceneId = other.sceneId; + this->mSceneEndpointId = other.mSceneEndpointId; + this->mSceneGroupId = other.mSceneGroupId; + this->mSceneId = other.mSceneId; } }; @@ -110,31 +110,31 @@ class SceneTable static constexpr TLV::Tag TagSceneTransitionTime() { return TLV::ContextTag(2); } static constexpr TLV::Tag TagSceneTransitionTime100() { return TLV::ContextTag(3); } - char name[kSceneNameMax] = { 0 }; - size_t nameLength = 0; - SceneTransitionTime sceneTransitionTime = 0; - ExtensionFieldsSetsImpl extentsionFieldsSets; - TransitionTime100ms transitionTime100 = 0; - CharSpan nameSpan; + char mName[kSceneNameMax] = { 0 }; + size_t mNameLength = 0; + SceneTransitionTime mSceneTransitionTime = 0; + ExtensionFieldsSetsImpl mExtentsionFieldsSets; + TransitionTime100ms mTransitionTime100 = 0; + CharSpan mNameSpan; SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : - sceneTransitionTime(time), transitionTime100(time100ms) + mSceneTransitionTime(time), mTransitionTime100(time100ms) { this->SetName(sceneName); } SceneData(ExtensionFieldsSetsImpl fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : - sceneTransitionTime(time), - transitionTime100(time100ms) + mSceneTransitionTime(time), + mTransitionTime100(time100ms) { this->SetName(sceneName); - extentsionFieldsSets = fields; + mExtentsionFieldsSets = fields; } SceneData(const SceneData & other) : - sceneTransitionTime(other.sceneTransitionTime), transitionTime100(other.transitionTime100) + mSceneTransitionTime(other.mSceneTransitionTime), mTransitionTime100(other.mTransitionTime100) { - this->SetName(other.nameSpan); - extentsionFieldsSets = other.extentsionFieldsSets; + this->SetName(other.mNameSpan); + mExtentsionFieldsSets = other.mExtentsionFieldsSets; } ~SceneData(){}; @@ -144,14 +144,14 @@ class SceneTable ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); // A 0 size means the name wasn't used so it won't get stored - if (!this->nameSpan.empty()) + if (!this->mNameSpan.empty()) { - ReturnErrorOnFailure(writer.PutString(TagSceneName(), this->nameSpan)); + ReturnErrorOnFailure(writer.PutString(TagSceneName(), this->mNameSpan)); } - ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime(), static_cast(this->sceneTransitionTime))); - ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime100(), static_cast(this->transitionTime100))); - ReturnErrorOnFailure(this->extentsionFieldsSets.Serialize(writer)); + ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime(), static_cast(this->mSceneTransitionTime))); + ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime100(), static_cast(this->mTransitionTime100))); + ReturnErrorOnFailure(this->mExtentsionFieldsSets.Serialize(writer)); return writer.EndContainer(container); } @@ -168,15 +168,15 @@ class SceneTable // If there was no error, a name is expected from the storage, if there was an unexpectec TLV element, if (currTag == TagSceneName()) { - ReturnErrorOnFailure(reader.Get(this->nameSpan)); - this->SetName(this->nameSpan); + ReturnErrorOnFailure(reader.Get(this->mNameSpan)); + this->SetName(this->mNameSpan); ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime())); } - ReturnErrorOnFailure(reader.Get(this->sceneTransitionTime)); + ReturnErrorOnFailure(reader.Get(this->mSceneTransitionTime)); ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime100())); - ReturnErrorOnFailure(reader.Get(this->transitionTime100)); - ReturnErrorOnFailure(this->extentsionFieldsSets.Deserialize(reader)); + ReturnErrorOnFailure(reader.Get(this->mTransitionTime100)); + ReturnErrorOnFailure(this->mExtentsionFieldsSets.Deserialize(reader)); return reader.ExitContainer(container); } @@ -185,38 +185,38 @@ class SceneTable { if (nullptr == sceneName.data()) { - name[0] = 0; - nameLength = 0; + mName[0] = 0; + mNameLength = 0; } else { - Platform::CopyString(name, sceneName); - nameLength = sceneName.size(); + Platform::CopyString(mName, sceneName); + mNameLength = sceneName.size(); } - nameSpan = CharSpan(name, nameLength); + mNameSpan = CharSpan(mName, mNameLength); } void Clear() { this->SetName(CharSpan()); - sceneTransitionTime = 0; - transitionTime100 = 0; - extentsionFieldsSets.Clear(); + mSceneTransitionTime = 0; + mTransitionTime100 = 0; + mExtentsionFieldsSets.Clear(); } bool operator==(const SceneData & other) { - return (this->nameSpan.data_equal(other.nameSpan) && (this->sceneTransitionTime == other.sceneTransitionTime) && - (this->transitionTime100 == other.transitionTime100) && - (this->extentsionFieldsSets == other.extentsionFieldsSets)); + return (this->mNameSpan.data_equal(other.mNameSpan) && (this->mSceneTransitionTime == other.mSceneTransitionTime) && + (this->mTransitionTime100 == other.mTransitionTime100) && + (this->mExtentsionFieldsSets == other.mExtentsionFieldsSets)); } void operator=(const SceneData & other) { - this->SetName(other.nameSpan); - this->extentsionFieldsSets = other.extentsionFieldsSets; - this->sceneTransitionTime = other.sceneTransitionTime; - this->transitionTime100 = other.transitionTime100; + this->SetName(other.mNameSpan); + this->mExtentsionFieldsSets = other.mExtentsionFieldsSets; + this->mSceneTransitionTime = other.mSceneTransitionTime; + this->mTransitionTime100 = other.mTransitionTime100; } }; @@ -225,24 +225,24 @@ class SceneTable { // ID - SceneStorageId storageId; + SceneStorageId mStorageId; // DATA - SceneData storageData; + SceneData mStorageData; SceneTableEntry() = default; - SceneTableEntry(SceneStorageId id) : storageId(id) {} - SceneTableEntry(const SceneStorageId id, const SceneData data) : storageId(id), storageData(data) {} + SceneTableEntry(SceneStorageId id) : mStorageId(id) {} + SceneTableEntry(const SceneStorageId id, const SceneData data) : mStorageId(id), mStorageData(data) {} bool operator==(const SceneTableEntry & other) { - return (this->storageId == other.storageId && this->storageData == other.storageData); + return (this->mStorageId == other.mStorageId && this->mStorageData == other.mStorageData); } void operator=(const SceneTableEntry & other) { - this->storageId = other.storageId; - this->storageData = other.storageData; + this->mStorageId = other.mStorageId; + this->mStorageData = other.mStorageData; } }; @@ -251,7 +251,7 @@ class SceneTable virtual ~SceneTable() = default; // Not copyable - SceneTable(const SceneTable &) = delete; + SceneTable(const SceneTable &) = delete; SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 49e23daf3eb804..ef98d93d48f87a 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -58,15 +58,15 @@ struct SceneTableData : public SceneTableEntry, PersistentData idx = index; return CHIP_NO_ERROR; // return scene at current index if scene found } - else if (scene_map[index].sceneEndpointId == kInvalidEndpointId && firstFreeIdx == kUndefinedSceneIndex) + else if (scene_map[index].mSceneEndpointId == kInvalidEndpointId && firstFreeIdx == kUndefinedSceneIndex) { firstFreeIdx = index; } @@ -283,10 +283,10 @@ struct FabricSceneData : public PersistentData CHIP_ERROR SaveScene(PersistentStorageDelegate * storage, const SceneTableEntry & entry) { CHIP_ERROR err; - SceneTableData scene(fabric_index, entry.storageId, entry.storageData); + SceneTableData scene(fabric_index, entry.mStorageId, entry.mStorageData); // Look for empty storage space - err = this->Find(entry.storageId, scene.index); + err = this->Find(entry.mStorageId, scene.index); if (CHIP_NO_ERROR == err) { @@ -296,7 +296,7 @@ struct FabricSceneData : public PersistentData else if (CHIP_ERROR_NOT_FOUND == err) // If not found, scene.index should be the first free index { scene_count++; - scene_map[scene.index] = scene.storageId; + scene_map[scene.index] = scene.mStorageId; ReturnErrorOnFailure(this->Save(storage)); return scene.Save(storage); @@ -361,8 +361,8 @@ CHIP_ERROR DefaultSceneTableImpl::GetSceneTableEntry(FabricIndex fabric_index, S VerifyOrReturnError(fabric.Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); ReturnErrorOnFailure(scene.Load(mStorage)); - entry.storageId = scene.storageId; - entry.storageData = scene.storageData; + entry.mStorageId = scene.mStorageId; + entry.mStorageData = scene.mStorageData; return CHIP_NO_ERROR; } @@ -490,7 +490,7 @@ CHIP_ERROR DefaultSceneTableImpl::EFSValuesToCluster(ExtensionFieldsSetsImpl & f { for (uint8_t j = 0; j < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; j++) { - if (EFS.ID == this->handlers[j].getID()) + if (EFS.mID == this->handlers[j].getID()) { ReturnErrorOnFailure(this->handlers[j].setClusterEFS(EFS)); } @@ -550,12 +550,12 @@ bool DefaultSceneTableImpl::SceneEntryIteratorImpl::Next(SceneTableEntry & outpu // looks for next available scene while (mSceneIndex < kMaxScenePerFabric) { - if (fabric.scene_map[mSceneIndex].sceneEndpointId != kInvalidEndpointId) + if (fabric.scene_map[mSceneIndex].mSceneEndpointId != kInvalidEndpointId) { scene.index = mSceneIndex; VerifyOrReturnError(scene.Load(mProvider.mStorage) == CHIP_NO_ERROR, false); - output.storageId = scene.storageId; - output.storageData = scene.storageData; + output.mStorageId = scene.mStorageId; + output.mStorageData = scene.mStorageData; mSceneIndex++; return true; From a72504eb5d5729b93df9597ff186ae13a613d6fc Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Fri, 10 Feb 2023 14:49:30 -0500 Subject: [PATCH 20/79] Adding refactor to test file as well --- src/app/tests/TestSceneTable.cpp | 64 ++++++++++++++++---------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 484182f8afbc16..284072201f8fe3 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -168,15 +168,15 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) ResetSceneTable(sceneTable); // Test SceneHandlers - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(onOffEFS1.ID, &oo_from_cluster_cb1, &oo_to_cluster_cb1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(lvCtrEFS1.ID, &lc_from_cluster_cb1, &lc_to_cluster_cb1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(coCtrEFS2.ID, &cc_from_cluster_cb1, &cc_to_cluster_cb1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(onOffEFS1.mID, &oo_from_cluster_cb1, &oo_to_cluster_cb1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(lvCtrEFS1.mID, &lc_from_cluster_cb1, &lc_to_cluster_cb1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(coCtrEFS2.mID, &cc_from_cluster_cb1, &cc_to_cluster_cb1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene1.storageData.extentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene2.storageData.extentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene3.storageData.extentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene4.storageData.extentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene5.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene1.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene2.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene3.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene4.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene5.mStorageData.mExtentsionFieldsSets)); SceneTableEntry scene; @@ -199,23 +199,23 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Get test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); NL_TEST_ASSERT(aSuite, scene == scene2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); NL_TEST_ASSERT(aSuite, scene == scene3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId4, scene)); NL_TEST_ASSERT(aSuite, scene == scene4); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene5); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId6, scene)); NL_TEST_ASSERT(aSuite, scene == scene6); @@ -231,13 +231,13 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable); // Test SceneHandlers overwrite - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(onOffEFS2.ID, &oo_from_cluster_cb2, &oo_to_cluster_cb2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(lvCtrEFS2.ID, &lc_from_cluster_cb2, &lc_to_cluster_cb2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(coCtrEFS2.ID, &cc_from_cluster_cb2, &cc_to_cluster_cb2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(onOffEFS2.mID, &oo_from_cluster_cb2, &oo_to_cluster_cb2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(lvCtrEFS2.mID, &lc_from_cluster_cb2, &lc_to_cluster_cb2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(coCtrEFS2.mID, &cc_from_cluster_cb2, &cc_to_cluster_cb2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene10.storageData.extentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene11.storageData.extentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene12.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene10.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene11.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene12.mStorageData.mExtentsionFieldsSets)); // Verfies the overwrite hasn't changed the handlers number NL_TEST_ASSERT(aSuite, sceneTable->getHandlerNum() == 3); @@ -253,15 +253,15 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) // Scene 10 has the same sceneId as scene 1, Get->sceneId1 should thus return scene 10, etc. NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene10); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene11); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); NL_TEST_ASSERT(aSuite, scene == scene12); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.storageData.extentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); } void TestIterateScenes(nlTestSuite * aSuite, void * aContext) @@ -306,7 +306,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) SceneTableEntry scene; // Remove middle - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene5.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene5.mStorageId)); auto * iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); @@ -320,21 +320,21 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, scene == scene9); // Remove the recently added scene 9 - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene9.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene9.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); // Remove first - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 6); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene2); // Remove Next - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene3.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene3.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 5); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); @@ -342,37 +342,37 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene4); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene2.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene2.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 4); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene4); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene4.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene4.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 3); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene6); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene6.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene6.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 2); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene7); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene7.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene7.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 1); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene12); // Remove last - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); NL_TEST_ASSERT(aSuite, iterator->Next(scene) == false); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.storageId)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); From 4c5e78eecdfbfe4e8d3bcb09eff5062f0b5cbdf7 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Mon, 13 Feb 2023 10:23:33 -0500 Subject: [PATCH 21/79] Restyled .sh file --- scripts/examples/gn_efr32_example.sh | 2 +- src/lib/core/SceneId.h | 66 ---------------------------- 2 files changed, 1 insertion(+), 67 deletions(-) delete mode 100644 src/lib/core/SceneId.h diff --git a/scripts/examples/gn_efr32_example.sh b/scripts/examples/gn_efr32_example.sh index 49ff6ce7cc6787..59cf1a05700498 100755 --- a/scripts/examples/gn_efr32_example.sh +++ b/scripts/examples/gn_efr32_example.sh @@ -151,7 +151,7 @@ else elif [ "$2" = "SiWx917" ]; then optArgs+="use_SiWx917=true " elif [ "$2" = "wf200" ]; then - optArgs+="use_wf200=true" + optArgs+="use_wf200=true " else echo "Wifi usage: --wifi rs9116|SiWx917|wf200" exit 1 diff --git a/src/lib/core/SceneId.h b/src/lib/core/SceneId.h deleted file mode 100644 index 235c5d961817c7..00000000000000 --- a/src/lib/core/SceneId.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * - * Copyright (c) 2022 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. - */ - -#pragma once - -#include -#include - -/** - * @brief Indicates the absence of a Scene table entry. - */ -#define SCENE_TABLE_NULL_INDEX 0xFF -/** - * @brief Value used when setting or getting the endpoint in a Scene table - * entry. It indicates that the entry is not in use. - */ -#define SCENE_TABLE_UNUSED_ENDPOINT_ID 0x00 -/** - * @brief Maximum length of Scene names, not including the length byte. - */ -#define ZCL_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH 16 -/** - * @brief The group identifier for the global scene. - */ -#define ZCL_SCENES_GLOBAL_SCENE_GROUP_ID 0x0000 -/** - * @brief The scene identifier for the global scene. - */ -#define ZCL_SCENES_GLOBAL_SCENE_SCENE_ID 0x00 - -/** - * @brief The maximum number of scenes according to spec - */ -#define SCENE_MAX_NUMBER 16 - -/** - * @brief The maximum number of scenes allowed on a single fabric - */ -#define SCENE_MAX_PER_FABRIC (SCENE_MAX_NUMBER / 2) - -namespace chip { - -typedef GroupId SceneGroupID; -typedef uint8_t SceneId; -typedef uint16_t SceneTransitionTime; -typedef uint8_t TransitionTime100ms; - -constexpr SceneGroupID kGlobalGroupSceneId = ZCL_SCENES_GLOBAL_SCENE_GROUP_ID; -constexpr SceneId kUndefinedSceneId = SCENE_TABLE_NULL_INDEX; -constexpr SceneId kUnusedEndpointId = SCENE_TABLE_UNUSED_ENDPOINT_ID; - -} // namespace chip From 040875c1b1db25b9f0a8f81e13eff9d7f47269ea Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Mon, 13 Feb 2023 15:36:30 -0500 Subject: [PATCH 22/79] Fixed urldefense in links --- src/app/clusters/scenes/ExtensionFieldsSets.h | 2 +- src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp | 2 +- src/app/clusters/scenes/ExtensionFieldsSetsImpl.h | 2 +- src/app/clusters/scenes/SceneTable.h | 2 +- src/app/clusters/scenes/SceneTableImpl.cpp | 2 +- src/app/clusters/scenes/SceneTableImpl.h | 2 +- src/lib/support/TestSceneTable.h | 4 ++-- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldsSets.h index c76f73de242e9f..3e6dc908ec3cea 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.h +++ b/src/app/clusters/scenes/ExtensionFieldsSets.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * 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, diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index c7ac0e8b1eacbf..d5fb997a9b478a 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * 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, diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h index 5249c735cc8d90..07fc3f888fad86 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * 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, diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 431082e75904eb..77ea7d7a9a765f 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * 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, diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index ef98d93d48f87a..a58c7507e07b86 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * 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, diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index cfe1e55b64936f..222dd1da266492 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * 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, diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h index fe67352c4fe068..9c4626a4244d49 100644 --- a/src/lib/support/TestSceneTable.h +++ b/src/lib/support/TestSceneTable.h @@ -1,13 +1,13 @@ /* * - * Copyright (c) 2022 Project CHIP Authors + * Copyright (c) 2023 Project CHIP Authors * All rights reserved. * * 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 * - * https://urldefense.com/v3/__http://www.apache.org/licenses/LICENSE-2.0__;!!N30Cs7Jr!UgbMbEQ59BIK-1Xslc7QXYm0lQBh92qA3ElecRe1CF_9YhXxbwPOZa6j4plru7B7kCJ7bKQgHxgQrket3-Dnk268sIdA7Qb8$ + * 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, From a1156b810eb07403317e7dbc4fa7fc1331dc7f93 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 13 Feb 2023 20:47:51 +0000 Subject: [PATCH 23/79] Restyled by clang-format --- src/app/clusters/scenes/SceneTable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 77ea7d7a9a765f..1c3cbf3ccdbebb 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -251,7 +251,7 @@ class SceneTable virtual ~SceneTable() = default; // Not copyable - SceneTable(const SceneTable &) = delete; + SceneTable(const SceneTable &) = delete; SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; From 23bfd5c5c045e2b5bd941c5adc60992ea5a7a119 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 13 Feb 2023 20:47:54 +0000 Subject: [PATCH 24/79] Restyled by shfmt --- scripts/examples/gn_efr32_example.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/examples/gn_efr32_example.sh b/scripts/examples/gn_efr32_example.sh index 59cf1a05700498..0ac2bc789b1f26 100755 --- a/scripts/examples/gn_efr32_example.sh +++ b/scripts/examples/gn_efr32_example.sh @@ -201,9 +201,9 @@ else if [ "$1" =~ *"use_rs9116=true"* ] || [ "$1" =~ *"use_SiWx917=true"* ] || [ "$1" =~ *"use_wf200=true"* ]; then USE_WIFI=true fi - optArgs+=$1" " - shift - ;; + optArgs+=$1" " + shift + ;; esac done From 1cb2526d60a561cb36488b7d3d4f00d88b0bd489 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 13 Feb 2023 20:53:52 +0000 Subject: [PATCH 25/79] Restyled by clang-format --- src/lib/support/DefaultStorageKeyAllocator.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index 689ac6fefba88d..aa059a9630b110 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } From f90f2626bda5b1ac51b9ae5a27088fe375ea77fc Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Tue, 14 Feb 2023 13:51:21 -0500 Subject: [PATCH 26/79] Refactor for CI --- .../scenes/ExtensionFieldsSetsImpl.cpp | 11 ++- src/app/clusters/scenes/SceneTableImpl.cpp | 16 ++-- src/app/clusters/scenes/SceneTableImpl.h | 18 ++--- src/lib/support/TestSceneTable.h | 76 ++++++++++++++----- 4 files changed, 78 insertions(+), 43 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index d5fb997a9b478a..830c1b5955e4d0 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -83,6 +83,7 @@ bool ExtensionFieldsSetsImpl::is_empty() const /// @return CHIP_NO_ERROR if insertion worked, CHIP_ERROR_BUFFER_TOO_SMALL if the array is already full CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) { + CHIP_ERROR err = CHIP_ERROR_INVALID_LIST_LENGTH; uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { @@ -102,18 +103,16 @@ CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) if (idPosition < kMaxClusterPerScenes) { ReturnErrorOnFailure(this->mEFS[idPosition] = field); - return CHIP_NO_ERROR; + err = CHIP_NO_ERROR; } else if (fisrtEmptyPosition < kMaxClusterPerScenes) { ReturnErrorOnFailure(this->mEFS[fisrtEmptyPosition] = field); this->mFieldNum++; - return CHIP_NO_ERROR; - } - else - { - return CHIP_ERROR_INVALID_LIST_LENGTH; + err = CHIP_NO_ERROR; } + + return err; } CHIP_ERROR ExtensionFieldsSetsImpl::getFieldAtPosition(ExtensionFieldsSet & field, uint8_t position) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index a58c7507e07b86..f1117aa79b6afc 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -254,7 +254,7 @@ struct FabricSceneData : public PersistentData idx = index; return CHIP_NO_ERROR; // return scene at current index if scene found } - else if (scene_map[index].mSceneEndpointId == kInvalidEndpointId && firstFreeIdx == kUndefinedSceneIndex) + if (scene_map[index].mSceneEndpointId == kInvalidEndpointId && firstFreeIdx == kUndefinedSceneIndex) { firstFreeIdx = index; } @@ -293,7 +293,8 @@ struct FabricSceneData : public PersistentData return scene.Save(storage); } - else if (CHIP_ERROR_NOT_FOUND == err) // If not found, scene.index should be the first free index + + if (CHIP_ERROR_NOT_FOUND == err) // If not found, scene.index should be the first free index { scene_count++; scene_map[scene.index] = scene.mStorageId; @@ -404,6 +405,7 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fa /// @return CHIP_ERROR_BUFFER_TO_SMALL if couldn't insert the handler, otherwise CHIP_NO_ERROR CHIP_ERROR DefaultSceneTableImpl::registerHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function) { + CHIP_ERROR err = CHIP_ERROR_INVALID_LIST_LENGTH; uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) { @@ -422,20 +424,16 @@ CHIP_ERROR DefaultSceneTableImpl::registerHandler(ClusterId ID, clusterFieldsHan if (idPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) { this->handlers[idPosition].initSceneHandler(ID, get_function, set_function); - return CHIP_NO_ERROR; + err = CHIP_NO_ERROR; } else if (fisrtEmptyPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) { this->handlers[fisrtEmptyPosition].initSceneHandler(ID, get_function, set_function); this->handlerNum++; - return CHIP_NO_ERROR; - } - else - { - return CHIP_ERROR_INVALID_LIST_LENGTH; + err = CHIP_NO_ERROR; } - return CHIP_ERROR_INVALID_LIST_LENGTH; + return err; } CHIP_ERROR DefaultSceneTableImpl::unregisterHandler(uint8_t position) diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 222dd1da266492..7b630ff29e8359 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -34,25 +34,25 @@ typedef CHIP_ERROR (*clusterFieldsHandle)(ExtensionFieldsSet & fields); class SceneHandler { public: - SceneHandler(ClusterId Id = kInvalidClusterId, clusterFieldsHandle getClusterEFS = nullptr, - clusterFieldsHandle setClusterEFS = nullptr) + SceneHandler(ClusterId Id = kInvalidClusterId, clusterFieldsHandle getEFSHandle = nullptr, + clusterFieldsHandle setEFSHandle = nullptr) { - if (getClusterEFS != nullptr && setClusterEFS != nullptr && Id != kInvalidClusterId) + if (getEFSHandle != nullptr && setEFSHandle != nullptr && Id != kInvalidClusterId) { - getEFS = getClusterEFS; - setEFS = setClusterEFS; + getEFS = getEFSHandle; + setEFS = setEFSHandle; cID = Id; initialized = true; } }; ~SceneHandler(){}; - void initSceneHandler(ClusterId Id, clusterFieldsHandle getClusterEFS, clusterFieldsHandle setClusterEFS) + void initSceneHandler(ClusterId Id, clusterFieldsHandle getEFSHandle, clusterFieldsHandle setEFSHandle) { - if (getClusterEFS != nullptr && setClusterEFS != nullptr && Id != kInvalidClusterId) + if (getEFSHandle != nullptr && setEFSHandle != nullptr && Id != kInvalidClusterId) { - getEFS = getClusterEFS; - setEFS = setClusterEFS; + getEFS = getEFSHandle; + setEFS = setEFSHandle; cID = Id; initialized = true; } diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h index 9c4626a4244d49..cf1a06c144e692 100644 --- a/src/lib/support/TestSceneTable.h +++ b/src/lib/support/TestSceneTable.h @@ -24,11 +24,36 @@ namespace chip { namespace SceneTesting { -using FabricIndex = chip::FabricIndex; -using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; -using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; -using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; -using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; +using FabricIndex = chip::FabricIndex; +using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; +using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; +using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; +using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; +using ExtensionFieldsSet = chip::scenes::ExtensionFieldsSet; + +static const ExtensionFieldsSet onOffEFS1 = ExtensionFieldsSet(0x0006, (uint8_t *) "1", 1); +static const ExtensionFieldsSet levelControlEFS1 = ExtensionFieldsSet(0x0008, (uint8_t *) "511", 3); + +static CHIP_ERROR test_on_off_from_cluster_callback(ExtensionFieldsSet & fields) +{ + ReturnErrorOnFailure(fields = onOffEFS1); + return CHIP_NO_ERROR; +} +static CHIP_ERROR test_on_off_to_cluster_callback(ExtensionFieldsSet & fields) +{ + VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_WRITE_FAILED); + return CHIP_NO_ERROR; +} +static CHIP_ERROR test_level_control_from_cluster_callback(ExtensionFieldsSet & fields) +{ + ReturnErrorOnFailure(fields = levelControlEFS1); + return CHIP_NO_ERROR; +} +static CHIP_ERROR test_level_control_to_cluster_callback(ExtensionFieldsSet & fields) +{ + VerifyOrReturnError(fields == levelControlEFS1, CHIP_ERROR_WRITE_FAILED); + return CHIP_NO_ERROR; +} CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry) { @@ -36,9 +61,9 @@ CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry temp; LogErrorOnFailure(provider->SetSceneTableEntry(fabric_index, entry)); - LogErrorOnFailure(provider->GetSceneTableEntry(fabric_index, entry.storageId, temp)); - VerifyOrReturnError(temp.storageId == entry.storageId, CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(temp.storageData == entry.storageData, CHIP_ERROR_WRITE_FAILED); + LogErrorOnFailure(provider->GetSceneTableEntry(fabric_index, entry.mStorageId, temp)); + VerifyOrReturnError(temp.mStorageId == entry.mStorageId, CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(temp.mStorageData == entry.mStorageData, CHIP_ERROR_WRITE_FAILED); return err; } @@ -55,13 +80,13 @@ CHIP_ERROR scene_iterator_test(SceneTableImpl * provider, FabricIndex fabric_ind VerifyOrReturnError(iterator->Count() == 3, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.storageId == entry1.storageId, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(temp.mStorageId == entry1.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.storageId == entry2.storageId, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(temp.mStorageId == entry2.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.storageId == entry3.storageId, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(temp.mStorageId == entry3.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); // Iterator should return false here VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); @@ -78,21 +103,21 @@ CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index CHIP_ERROR err = CHIP_NO_ERROR; SceneTableEntry temp; - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry2.storageId)); + LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry2.mStorageId)); auto * iterator = provider->IterateSceneEntry(fabric_index); VerifyOrReturnError(iterator->Count() == 2, CHIP_ERROR_INVALID_ARGUMENT); iterator->Next(temp); - VerifyOrReturnError(temp.storageId == entry1.storageId, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(temp.mStorageId == entry1.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); iterator->Release(); - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry1.storageId)); + LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry1.mStorageId)); iterator = provider->IterateSceneEntry(fabric_index); VerifyOrReturnError(iterator->Count() == 1, CHIP_ERROR_INVALID_ARGUMENT); iterator->Next(temp); - VerifyOrReturnError(temp.storageId == entry3.storageId, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(temp.mStorageId == entry3.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry3.storageId)); + LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry3.mStorageId)); iterator = provider->IterateSceneEntry(fabric_index); VerifyOrReturnError(iterator->Count() == 0, CHIP_ERROR_INVALID_ARGUMENT); @@ -112,17 +137,30 @@ CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) static const SceneStorageId sceneId3(1, 0xCC, 0x102); // Scene data - static const SceneData sceneData1("Scene #1"); - static const SceneData sceneData2("Scene #2", 2, 5); - static const SceneData sceneData3("Scene #3", 25); + static const SceneData sceneData1(CharSpan("Scene #1", sizeof("Scene #1"))); + static const SceneData sceneData2(CharSpan("Scene #2", sizeof("Scene #2")), 2, 5); + static const SceneData sceneData3(CharSpan(), 25); + // Scenes SceneTableEntry scene1(sceneId1, sceneData1); SceneTableEntry scene2(sceneId2, sceneData2); SceneTableEntry scene3(sceneId3, sceneData3); + err = provider->registerHandler(onOffEFS1.mID, &test_on_off_from_cluster_callback, &test_on_off_to_cluster_callback); + LogErrorOnFailure(err); + err = provider->registerHandler(levelControlEFS1.mID, &test_level_control_from_cluster_callback, + &test_level_control_to_cluster_callback); + LogErrorOnFailure(err); + err = provider->EFSValuesFromCluster(scene1.mStorageData.mExtentsionFieldsSets); + LogErrorOnFailure(err); + // Tests err = scene_store_test(provider, fabric_index, scene1); LogErrorOnFailure(err); + + err = provider->EFSValuesToCluster(scene1.mStorageData.mExtentsionFieldsSets); + LogErrorOnFailure(err); + err = scene_store_test(provider, fabric_index, scene2); LogErrorOnFailure(err); err = scene_store_test(provider, fabric_index, scene3); From 0af6b610cfd646d13a258cdb91ad9f5bb8c73783 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Thu, 16 Feb 2023 13:42:54 -0500 Subject: [PATCH 27/79] Fix test causing SegFault in fake_x64 test --- src/app/clusters/scenes/SceneTable.h | 2 +- src/app/tests/TestSceneTable.cpp | 12 ++++++++++++ src/lib/core/CHIPConfig.h | 11 +++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 1c3cbf3ccdbebb..df2008c37e9361 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -34,7 +34,7 @@ static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; class SceneTable { public: - static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_GROUP_CONCURRENT_ITERATORS; + static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; /// @brief struct used to identify a scene in storage by 3 ids, endpoint, group and scene diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 284072201f8fe3..2ca7e5c4be4839 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -272,6 +272,8 @@ void TestIterateScenes(nlTestSuite * aSuite, void * aContext) SceneTableEntry scene; auto * iterator = sceneTable->IterateSceneEntry(kFabric1); + NL_TEST_ASSERT(aSuite, iterator != nullptr); + if (iterator) { NL_TEST_ASSERT(aSuite, iterator->Count() == 8); @@ -311,6 +313,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); + iterator->Release(); // Adde scene in middle, a spot should have been freed NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene9)); @@ -318,6 +321,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, iterator->Count() == 8); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId9, scene)); NL_TEST_ASSERT(aSuite, scene == scene9); + iterator->Release(); // Remove the recently added scene 9 NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene9.mStorageId)); @@ -325,6 +329,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); + iterator->Release(); // Remove first NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.mStorageId)); @@ -332,6 +337,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, iterator->Count() == 6); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene2); + iterator->Release(); // Remove Next NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene3.mStorageId)); @@ -341,36 +347,42 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, scene == scene2); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene4); + iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene2.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 4); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene4); + iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene4.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 3); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene6); + iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene6.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 2); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene7); + iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene7.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 1); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene12); + iterator->Release(); // Remove last NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); NL_TEST_ASSERT(aSuite, iterator->Next(scene) == false); + iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 05976b1d73687c..6bbb1208c49b47 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1427,6 +1427,17 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER 15 #endif +/** + * @def CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS + * + * @brief Defines the number of simultaneous Scenes iterators that can be allocated + * + * Number of iterator instances that can be allocated at any one time + */ +#ifndef CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS +#define CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS 2 +#endif + /** * @} */ From a69a3577fb87dd267a8cd1578ff882140ccc81af Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Fri, 17 Feb 2023 14:34:31 -0500 Subject: [PATCH 28/79] Applied fixes for coding style and array management --- src/app/clusters/scenes/ExtensionFieldsSets.h | 3 +- .../scenes/ExtensionFieldsSetsImpl.cpp | 80 +++++++++---------- .../clusters/scenes/ExtensionFieldsSetsImpl.h | 20 ++--- src/app/clusters/scenes/SceneTable.h | 48 +++++------ src/app/clusters/scenes/SceneTableImpl.cpp | 50 ++++++------ src/app/clusters/scenes/SceneTableImpl.h | 26 +++--- src/app/tests/TestSceneTable.cpp | 46 +++++------ src/lib/support/TestSceneTable.h | 4 +- 8 files changed, 136 insertions(+), 141 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldsSets.h index 3e6dc908ec3cea..3c86a79f08dad3 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.h +++ b/src/app/clusters/scenes/ExtensionFieldsSets.h @@ -23,6 +23,7 @@ namespace chip { namespace scenes { +static constexpr uint8_t kInvalidPosition = 0xff; static constexpr uint8_t kMaxClusterPerScenes = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; static constexpr uint8_t kMaxFieldsPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; @@ -35,7 +36,7 @@ class ExtensionFieldsSets virtual CHIP_ERROR Serialize(TLV::TLVWriter & writer) const = 0; virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; virtual void Clear() = 0; - virtual bool is_empty() const = 0; + virtual bool IsEmpty() const = 0; }; } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index 830c1b5955e4d0..77c97516cce2ff 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -27,13 +27,13 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Serialize(TLV::TLVWriter & writer) const TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); ReturnErrorOnFailure(writer.Put(TagFieldNum(), static_cast(this->mFieldNum))); - if (!this->is_empty()) + if (!this->IsEmpty()) { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - if (!this->mEFS[i].is_empty()) + if (!this->mEFS[i].IsEmpty()) { - LogErrorOnFailure(this->mEFS[i].Serialize(writer)); + ReturnErrorOnFailure(this->mEFS[i].Serialize(writer)); } } } @@ -50,7 +50,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Deserialize(TLV::TLVReader & reader) ReturnErrorOnFailure(reader.Next(TagFieldNum())); ReturnErrorOnFailure(reader.Get(this->mFieldNum)); - if (!this->is_empty()) + if (!this->IsEmpty()) { for (uint8_t i = 0; i < this->mFieldNum; i++) { @@ -60,9 +60,10 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Deserialize(TLV::TLVReader & reader) return reader.ExitContainer(container); } + void ExtensionFieldsSetsImpl::Clear() { - if (!this->is_empty()) + if (!this->IsEmpty()) { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { @@ -72,42 +73,43 @@ void ExtensionFieldsSetsImpl::Clear() this->mFieldNum = 0; } -bool ExtensionFieldsSetsImpl::is_empty() const +bool ExtensionFieldsSetsImpl::IsEmpty() const { - return (this->mFieldNum <= 0); + return (this->mFieldNum == 0); } -/// @brief Inserts a field set into the array of extension field sets for a scene entry if the same ID is present in the EFS array, -/// it will overwrite it -/// @param field field set to be inserted -/// @return CHIP_NO_ERROR if insertion worked, CHIP_ERROR_BUFFER_TOO_SMALL if the array is already full -CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) +/// @brief Inserts a field Set set into the array of extension field Set sets for a scene entry. +/// If the same ID is present in the EFS array, it will overwrite it. +/// @param fieldSet field set to be inserted +/// @return CHIP_NO_ERROR if insertion worked, CHIP_ERROR_NO_MEMORY if the array is already full +CHIP_ERROR ExtensionFieldsSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet) { - CHIP_ERROR err = CHIP_ERROR_INVALID_LIST_LENGTH; - uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; + CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; + uint8_t idPosition = kInvalidPosition; + uint8_t firstEmptyPosition = kInvalidPosition; for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - if (this->mEFS[i].mID == field.mID) + if (this->mEFS[i].mID == fieldSet.mID) { idPosition = i; break; } - if (this->mEFS[i].is_empty() && fisrtEmptyPosition == 0xFF) + if (this->mEFS[i].IsEmpty() && firstEmptyPosition == 0xFF) { - fisrtEmptyPosition = i; + firstEmptyPosition = i; } } - // if found, insert at found position, otherwise at first free possition, otherwise return error + // if found, replace at found position, otherwise at insert first free position, otherwise return error if (idPosition < kMaxClusterPerScenes) { - ReturnErrorOnFailure(this->mEFS[idPosition] = field); + ReturnErrorOnFailure(this->mEFS[idPosition] = fieldSet); err = CHIP_NO_ERROR; } - else if (fisrtEmptyPosition < kMaxClusterPerScenes) + else if (firstEmptyPosition < kMaxClusterPerScenes) { - ReturnErrorOnFailure(this->mEFS[fisrtEmptyPosition] = field); + ReturnErrorOnFailure(this->mEFS[firstEmptyPosition] = fieldSet); this->mFieldNum++; err = CHIP_NO_ERROR; } @@ -115,33 +117,31 @@ CHIP_ERROR ExtensionFieldsSetsImpl::insertField(ExtensionFieldsSet & field) return err; } -CHIP_ERROR ExtensionFieldsSetsImpl::getFieldAtPosition(ExtensionFieldsSet & field, uint8_t position) +CHIP_ERROR ExtensionFieldsSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & fieldSet, uint8_t position) { - if (position < kMaxClusterPerScenes) + if (position < this->mFieldNum) { - ReturnErrorOnFailure(field = this->mEFS[position]); + ReturnErrorOnFailure(fieldSet = this->mEFS[position]); } return CHIP_NO_ERROR; } -CHIP_ERROR ExtensionFieldsSetsImpl::removeFieldAtPosition(uint8_t position) +CHIP_ERROR ExtensionFieldsSetsImpl::RemoveFieldAtPosition(uint8_t position) { - if (!this->is_empty()) - { - if (position < kMaxClusterPerScenes) - { - if (!this->mEFS[position].is_empty()) - { - this->mEFS[position].Clear(); - this->mFieldNum--; - } - } - else - { - return CHIP_ERROR_ACCESS_DENIED; - } - } + + VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnValue(!this->IsEmpty() && !this->mEFS[position].IsEmpty(), CHIP_NO_ERROR); + + uint8_t next = position + 1; + uint8_t moveNum = kMaxClusterPerScenes - next; + + // Compress array after removal + memmove(&this->mEFS[position], &this->mEFS[next], sizeof(ExtensionFieldsSet) * moveNum); + + this->mFieldNum--; + // Clear last occupied position + this->mEFS[mFieldNum].Clear(); // return CHIP_NO_ERROR; } diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h index 07fc3f888fad86..f1fa88daa6544f 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h @@ -65,14 +65,8 @@ struct ExtensionFieldsSet ReturnErrorOnFailure(reader.Next(TagEFS())); ReturnErrorOnFailure(reader.Get(buffer)); - if (buffer.size() > kMaxFieldsPerCluster) - { - this->mUsedBytes = kMaxFieldsPerCluster; - } - else - { - this->mUsedBytes = static_cast(buffer.size()); - } + VerifyOrReturnError(buffer.size() <= kMaxFieldsPerCluster, CHIP_ERROR_BUFFER_TOO_SMALL); + this->mUsedBytes = static_cast(buffer.size()); memcpy(this->mBytesBuffer, buffer.data(), this->mUsedBytes); return reader.ExitContainer(container); @@ -85,7 +79,7 @@ struct ExtensionFieldsSet this->mUsedBytes = 0; } - bool is_empty() const { return (this->mUsedBytes == 0); } + bool IsEmpty() const { return (this->mUsedBytes == 0); } bool operator==(const ExtensionFieldsSet & other) { @@ -120,12 +114,12 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override; CHIP_ERROR Deserialize(TLV::TLVReader & reader) override; void Clear() override; - bool is_empty() const override; + bool IsEmpty() const override; // implementation - CHIP_ERROR insertField(ExtensionFieldsSet & field); - CHIP_ERROR getFieldAtPosition(ExtensionFieldsSet & field, uint8_t position); - CHIP_ERROR removeFieldAtPosition(uint8_t position); + CHIP_ERROR InsertFieldSet(ExtensionFieldsSet & field); + CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldsSet & field, uint8_t position); + CHIP_ERROR RemoveFieldAtPosition(uint8_t position); bool operator==(const ExtensionFieldsSetsImpl & other) { diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index df2008c37e9361..866de234c16762 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -30,13 +30,12 @@ typedef uint16_t SceneTransitionTime; typedef uint8_t TransitionTime100ms; static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; +static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; +static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; class SceneTable { public: - static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; - static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; - /// @brief struct used to identify a scene in storage by 3 ids, endpoint, group and scene struct SceneStorageId { @@ -44,7 +43,7 @@ class SceneTable static constexpr TLV::Tag TagFirstSceneGroupID() { return TLV::ContextTag(2); } static constexpr TLV::Tag TagFirstSceneID() { return TLV::ContextTag(3); } - // Identifies endpoint to which this scene applies to + // Identifies endpoint to which this scene applies EndpointId mSceneEndpointId = kInvalidEndpointId; // Identifies group within the scope of the given fabric SceneGroupID mSceneGroupId = kGlobalGroupSceneId; @@ -113,28 +112,28 @@ class SceneTable char mName[kSceneNameMax] = { 0 }; size_t mNameLength = 0; SceneTransitionTime mSceneTransitionTime = 0; - ExtensionFieldsSetsImpl mExtentsionFieldsSets; - TransitionTime100ms mTransitionTime100 = 0; + ExtensionFieldsSetsImpl mExtensionFieldsSets; + TransitionTime100ms mTransitionTime100ms = 0; CharSpan mNameSpan; SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : - mSceneTransitionTime(time), mTransitionTime100(time100ms) + mSceneTransitionTime(time), mTransitionTime100ms(time100ms) { this->SetName(sceneName); } SceneData(ExtensionFieldsSetsImpl fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : mSceneTransitionTime(time), - mTransitionTime100(time100ms) + mTransitionTime100ms(time100ms) { this->SetName(sceneName); - mExtentsionFieldsSets = fields; + mExtensionFieldsSets = fields; } SceneData(const SceneData & other) : - mSceneTransitionTime(other.mSceneTransitionTime), mTransitionTime100(other.mTransitionTime100) + mSceneTransitionTime(other.mSceneTransitionTime), mTransitionTime100ms(other.mTransitionTime100ms) { this->SetName(other.mNameSpan); - mExtentsionFieldsSets = other.mExtentsionFieldsSets; + mExtensionFieldsSets = other.mExtensionFieldsSets; } ~SceneData(){}; @@ -150,8 +149,8 @@ class SceneTable } ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime(), static_cast(this->mSceneTransitionTime))); - ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime100(), static_cast(this->mTransitionTime100))); - ReturnErrorOnFailure(this->mExtentsionFieldsSets.Serialize(writer)); + ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime100(), static_cast(this->mTransitionTime100ms))); + ReturnErrorOnFailure(this->mExtensionFieldsSets.Serialize(writer)); return writer.EndContainer(container); } @@ -175,8 +174,8 @@ class SceneTable ReturnErrorOnFailure(reader.Get(this->mSceneTransitionTime)); ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime100())); - ReturnErrorOnFailure(reader.Get(this->mTransitionTime100)); - ReturnErrorOnFailure(this->mExtentsionFieldsSets.Deserialize(reader)); + ReturnErrorOnFailure(reader.Get(this->mTransitionTime100ms)); + ReturnErrorOnFailure(this->mExtensionFieldsSets.Deserialize(reader)); return reader.ExitContainer(container); } @@ -190,8 +189,9 @@ class SceneTable } else { - Platform::CopyString(mName, sceneName); - mNameLength = sceneName.size(); + size_t maxChars = std::min(sceneName.size(), kSceneNameMax); + memcpy(mName, sceneName.data(), maxChars); + mNameLength = maxChars; } mNameSpan = CharSpan(mName, mNameLength); } @@ -200,23 +200,23 @@ class SceneTable { this->SetName(CharSpan()); mSceneTransitionTime = 0; - mTransitionTime100 = 0; - mExtentsionFieldsSets.Clear(); + mTransitionTime100ms = 0; + mExtensionFieldsSets.Clear(); } bool operator==(const SceneData & other) { return (this->mNameSpan.data_equal(other.mNameSpan) && (this->mSceneTransitionTime == other.mSceneTransitionTime) && - (this->mTransitionTime100 == other.mTransitionTime100) && - (this->mExtentsionFieldsSets == other.mExtentsionFieldsSets)); + (this->mTransitionTime100ms == other.mTransitionTime100ms) && + (this->mExtensionFieldsSets == other.mExtensionFieldsSets)); } void operator=(const SceneData & other) { this->SetName(other.mNameSpan); - this->mExtentsionFieldsSets = other.mExtentsionFieldsSets; - this->mSceneTransitionTime = other.mSceneTransitionTime; - this->mTransitionTime100 = other.mTransitionTime100; + this->mExtensionFieldsSets = other.mExtensionFieldsSets; + this->mSceneTransitionTime = other.mSceneTransitionTime; + this->mTransitionTime100ms = other.mTransitionTime100ms; } }; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index f1117aa79b6afc..b0ce8de1fb8282 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -237,11 +237,11 @@ struct FabricSceneData : public PersistentData return CHIP_ERROR_NOT_FOUND; } /// @brief Finds the index where to insert current scene by going through the whole table and looking if the scene is already in - /// there and for the first empty index - /// @param storage Storage delegate in use - /// @param fabric Fabric in use + /// there. If the target is not in the table, sets idx to the first empty space /// @param target_scene Storage Id of scene to store - /// @return CHIP_NO_ERROR if managed to find a suitable storage location, false otherwise + /// @param idx Index where target or space is found + /// @return CHIP_NO_ERROR if managed to find the target scene, CHIP_ERROR_NOT_FOUND if not found and space left + /// CHIP_ERROR_NO_MEMORY if target was not found and table is full CHIP_ERROR Find(SceneStorageId target_scene, SceneIndex & idx) { SceneIndex firstFreeIdx = kUndefinedSceneIndex; // storage index if scene not found @@ -267,7 +267,7 @@ struct FabricSceneData : public PersistentData return CHIP_ERROR_NOT_FOUND; } - return CHIP_ERROR_BUFFER_TOO_SMALL; + return CHIP_ERROR_NO_MEMORY; } CHIP_ERROR Save(PersistentStorageDelegate * storage) override { @@ -402,19 +402,19 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fa /// @param ID ID of the cluster used to fill the extension fields set /// @param get_function pointer to function to call to get the extension fiels set from the cluster /// @param set_function pointer to function to call send an extension field to the cluster -/// @return CHIP_ERROR_BUFFER_TO_SMALL if couldn't insert the handler, otherwise CHIP_NO_ERROR -CHIP_ERROR DefaultSceneTableImpl::registerHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function) +/// @return CHIP_ERROR_NO_MEMORY if couldn't insert the handler, otherwise CHIP_NO_ERROR +CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function) { - CHIP_ERROR err = CHIP_ERROR_INVALID_LIST_LENGTH; + CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) { - if (this->handlers[i].getID() == ID) + if (this->handlers[i].GetID() == ID) { idPosition = i; break; } - if (!this->handlers[i].isInitialized() && fisrtEmptyPosition == 0xff) + if (!this->handlers[i].IsInitialized() && fisrtEmptyPosition == 0xff) { fisrtEmptyPosition = i; } @@ -423,12 +423,12 @@ CHIP_ERROR DefaultSceneTableImpl::registerHandler(ClusterId ID, clusterFieldsHan // if found, insert at found position, otherwise at first free possition, otherwise return error if (idPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) { - this->handlers[idPosition].initSceneHandler(ID, get_function, set_function); + this->handlers[idPosition].InitSceneHandler(ID, get_function, set_function); err = CHIP_NO_ERROR; } else if (fisrtEmptyPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) { - this->handlers[fisrtEmptyPosition].initSceneHandler(ID, get_function, set_function); + this->handlers[fisrtEmptyPosition].InitSceneHandler(ID, get_function, set_function); this->handlerNum++; err = CHIP_NO_ERROR; } @@ -436,15 +436,15 @@ CHIP_ERROR DefaultSceneTableImpl::registerHandler(ClusterId ID, clusterFieldsHan return err; } -CHIP_ERROR DefaultSceneTableImpl::unregisterHandler(uint8_t position) +CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) { - if (!handlerListEmpty()) + if (!HandlerListEmpty()) { if (position < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) { - if (this->handlers[position].isInitialized()) + if (this->handlers[position].IsInitialized()) { - this->handlers[position].clearSceneHandler(); + this->handlers[position].ClearSceneHandler(); this->handlerNum--; } } @@ -460,14 +460,14 @@ CHIP_ERROR DefaultSceneTableImpl::unregisterHandler(uint8_t position) CHIP_ERROR DefaultSceneTableImpl::EFSValuesFromCluster(ExtensionFieldsSetsImpl & fieldSets) { ExtensionFieldsSet EFS; - if (!this->handlerListEmpty()) + if (!this->HandlerListEmpty()) { for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) { - if (this->handlers[i].isInitialized()) + if (this->handlers[i].IsInitialized()) { - ReturnErrorOnFailure(this->handlers[i].getClusterEFS(EFS)); - ReturnErrorOnFailure(fieldSets.insertField(EFS)); + ReturnErrorOnFailure(this->handlers[i].GetClusterEFS(EFS)); + ReturnErrorOnFailure(fieldSets.InsertFieldSet(EFS)); } } } @@ -478,19 +478,19 @@ CHIP_ERROR DefaultSceneTableImpl::EFSValuesFromCluster(ExtensionFieldsSetsImpl & CHIP_ERROR DefaultSceneTableImpl::EFSValuesToCluster(ExtensionFieldsSetsImpl & fieldSets) { ExtensionFieldsSet EFS; - if (!this->handlerListEmpty()) + if (!this->HandlerListEmpty()) { for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) { - fieldSets.getFieldAtPosition(EFS, i); + fieldSets.GetFieldSetAtPosition(EFS, i); - if (!EFS.is_empty()) + if (!EFS.IsEmpty()) { for (uint8_t j = 0; j < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; j++) { - if (EFS.mID == this->handlers[j].getID()) + if (EFS.mID == this->handlers[j].GetID()) { - ReturnErrorOnFailure(this->handlers[j].setClusterEFS(EFS)); + ReturnErrorOnFailure(this->handlers[j].SetClusterEFS(EFS)); } } } diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 7b630ff29e8359..c3fb2e043b948a 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -47,7 +47,7 @@ class SceneHandler }; ~SceneHandler(){}; - void initSceneHandler(ClusterId Id, clusterFieldsHandle getEFSHandle, clusterFieldsHandle setEFSHandle) + void InitSceneHandler(ClusterId Id, clusterFieldsHandle getEFSHandle, clusterFieldsHandle setEFSHandle) { if (getEFSHandle != nullptr && setEFSHandle != nullptr && Id != kInvalidClusterId) { @@ -58,7 +58,7 @@ class SceneHandler } } - void clearSceneHandler() + void ClearSceneHandler() { getEFS = nullptr; setEFS = nullptr; @@ -66,18 +66,18 @@ class SceneHandler initialized = false; } - CHIP_ERROR getClusterEFS(ExtensionFieldsSet & clusterFields) + CHIP_ERROR GetClusterEFS(ExtensionFieldsSet & clusterFields) { - if (this->isInitialized()) + if (this->IsInitialized()) { ReturnErrorOnFailure(getEFS(clusterFields)); } return CHIP_NO_ERROR; } - CHIP_ERROR setClusterEFS(ExtensionFieldsSet & clusterFields) + CHIP_ERROR SetClusterEFS(ExtensionFieldsSet & clusterFields) { - if (this->isInitialized()) + if (this->IsInitialized()) { ReturnErrorOnFailure(setEFS(clusterFields)); } @@ -85,9 +85,9 @@ class SceneHandler return CHIP_NO_ERROR; } - bool isInitialized() const { return this->initialized; } + bool IsInitialized() const { return this->initialized; } - ClusterId getID() { return cID; } + ClusterId GetID() { return cID; } bool operator==(const SceneHandler & other) { @@ -135,8 +135,8 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) override; // SceneHandlers - CHIP_ERROR registerHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function); - CHIP_ERROR unregisterHandler(uint8_t position); + CHIP_ERROR RegisterHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function); + CHIP_ERROR UnregisterHandler(uint8_t position); // Extension field sets operation CHIP_ERROR EFSValuesFromCluster(ExtensionFieldsSetsImpl & fieldSets); @@ -148,9 +148,9 @@ class DefaultSceneTableImpl : public SceneTable // Iterators SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; - bool handlerListEmpty() { return (handlerNum == 0); } - bool handlerListFull() { return (handlerNum >= CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES); } - uint8_t getHandlerNum() { return this->handlerNum; } + bool HandlerListEmpty() { return (handlerNum == 0); } + bool HandlerListFull() { return (handlerNum >= CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES); } + uint8_t GetHandlerNum() { return this->handlerNum; } protected: class SceneEntryIteratorImpl : public SceneEntryIterator diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 2ca7e5c4be4839..bf7d2b64bda9d1 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -168,15 +168,15 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) ResetSceneTable(sceneTable); // Test SceneHandlers - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(onOffEFS1.mID, &oo_from_cluster_cb1, &oo_to_cluster_cb1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(lvCtrEFS1.mID, &lc_from_cluster_cb1, &lc_to_cluster_cb1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(coCtrEFS2.mID, &cc_from_cluster_cb1, &cc_to_cluster_cb1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(onOffEFS1.mID, &oo_from_cluster_cb1, &oo_to_cluster_cb1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(lvCtrEFS1.mID, &lc_from_cluster_cb1, &lc_to_cluster_cb1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(coCtrEFS2.mID, &cc_from_cluster_cb1, &cc_to_cluster_cb1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene1.mStorageData.mExtentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene2.mStorageData.mExtentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene3.mStorageData.mExtentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene4.mStorageData.mExtentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene5.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene1.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene2.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene3.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene4.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene5.mStorageData.mExtensionFieldsSets)); SceneTableEntry scene; @@ -199,23 +199,23 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Get test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); NL_TEST_ASSERT(aSuite, scene == scene2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); NL_TEST_ASSERT(aSuite, scene == scene3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId4, scene)); NL_TEST_ASSERT(aSuite, scene == scene4); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene5); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId6, scene)); NL_TEST_ASSERT(aSuite, scene == scene6); @@ -231,16 +231,16 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable); // Test SceneHandlers overwrite - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(onOffEFS2.mID, &oo_from_cluster_cb2, &oo_to_cluster_cb2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(lvCtrEFS2.mID, &lc_from_cluster_cb2, &lc_to_cluster_cb2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->registerHandler(coCtrEFS2.mID, &cc_from_cluster_cb2, &cc_to_cluster_cb2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(onOffEFS2.mID, &oo_from_cluster_cb2, &oo_to_cluster_cb2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(lvCtrEFS2.mID, &lc_from_cluster_cb2, &lc_to_cluster_cb2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(coCtrEFS2.mID, &cc_from_cluster_cb2, &cc_to_cluster_cb2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene10.mStorageData.mExtentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene11.mStorageData.mExtentsionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene12.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene10.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene11.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene12.mStorageData.mExtensionFieldsSets)); // Verfies the overwrite hasn't changed the handlers number - NL_TEST_ASSERT(aSuite, sceneTable->getHandlerNum() == 3); + NL_TEST_ASSERT(aSuite, sceneTable->GetHandlerNum() == 3); SceneTableEntry scene; // Overwriting the first entry @@ -253,15 +253,15 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) // Scene 10 has the same sceneId as scene 1, Get->sceneId1 should thus return scene 10, etc. NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene10); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene11); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); NL_TEST_ASSERT(aSuite, scene == scene12); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtentsionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); } void TestIterateScenes(nlTestSuite * aSuite, void * aContext) diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h index cf1a06c144e692..420d675e9a9044 100644 --- a/src/lib/support/TestSceneTable.h +++ b/src/lib/support/TestSceneTable.h @@ -151,14 +151,14 @@ CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) err = provider->registerHandler(levelControlEFS1.mID, &test_level_control_from_cluster_callback, &test_level_control_to_cluster_callback); LogErrorOnFailure(err); - err = provider->EFSValuesFromCluster(scene1.mStorageData.mExtentsionFieldsSets); + err = provider->EFSValuesFromCluster(scene1.mStorageData.mExtensionFieldsSets); LogErrorOnFailure(err); // Tests err = scene_store_test(provider, fabric_index, scene1); LogErrorOnFailure(err); - err = provider->EFSValuesToCluster(scene1.mStorageData.mExtentsionFieldsSets); + err = provider->EFSValuesToCluster(scene1.mStorageData.mExtensionFieldsSets); LogErrorOnFailure(err); err = scene_store_test(provider, fabric_index, scene2); From a5161f199f5197498e344d3fe49d744333c0da2f Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Tue, 21 Feb 2023 21:35:51 -0500 Subject: [PATCH 29/79] Refactor TLV tags to use enums, re-implemented scene handler and tests --- src/app/clusters/scenes/ExtensionFieldsSets.h | 1 + .../scenes/ExtensionFieldsSetsImpl.cpp | 33 +- .../clusters/scenes/ExtensionFieldsSetsImpl.h | 61 +- src/app/clusters/scenes/SceneTable.h | 141 +++-- src/app/clusters/scenes/SceneTableImpl.cpp | 125 ++-- src/app/clusters/scenes/SceneTableImpl.h | 186 +++--- src/app/tests/TestSceneTable.cpp | 539 ++++++++++++++---- src/lib/core/CHIPConfig.h | 4 +- src/lib/support/TestSceneTable.h | 404 +++++++++++-- 9 files changed, 1117 insertions(+), 377 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldsSets.h index 3c86a79f08dad3..e2853fa6e09fbd 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSets.h +++ b/src/app/clusters/scenes/ExtensionFieldsSets.h @@ -37,6 +37,7 @@ class ExtensionFieldsSets virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; virtual void Clear() = 0; virtual bool IsEmpty() const = 0; + virtual uint8_t GetFieldNum() const = 0; }; } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index 77c97516cce2ff..27038353dcec80 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -25,11 +25,11 @@ ExtensionFieldsSetsImpl::ExtensionFieldsSetsImpl() : ExtensionFieldsSets() {} CHIP_ERROR ExtensionFieldsSetsImpl::Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TagFieldNum(), static_cast(this->mFieldNum))); + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(kTagEFSArrayContainer), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagEFSFieldNum), static_cast(this->mFieldNum))); if (!this->IsEmpty()) { - for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < this->mFieldNum; i++) { if (!this->mEFS[i].IsEmpty()) { @@ -44,10 +44,10 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Serialize(TLV::TLVWriter & writer) const CHIP_ERROR ExtensionFieldsSetsImpl::Deserialize(TLV::TLVReader & reader) { TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagEFSArrayContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TagFieldNum())); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFSFieldNum))); ReturnErrorOnFailure(reader.Get(this->mFieldNum)); if (!this->IsEmpty()) @@ -73,11 +73,6 @@ void ExtensionFieldsSetsImpl::Clear() this->mFieldNum = 0; } -bool ExtensionFieldsSetsImpl::IsEmpty() const -{ - return (this->mFieldNum == 0); -} - /// @brief Inserts a field Set set into the array of extension field Set sets for a scene entry. /// If the same ID is present in the EFS array, it will overwrite it. /// @param fieldSet field set to be inserted @@ -87,6 +82,9 @@ CHIP_ERROR ExtensionFieldsSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; uint8_t idPosition = kInvalidPosition; uint8_t firstEmptyPosition = kInvalidPosition; + + VerifyOrReturnError(fieldSet.mID != kInvalidClusterId, CHIP_ERROR_INVALID_ARGUMENT); + for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { if (this->mEFS[i].mID == fieldSet.mID) @@ -104,12 +102,12 @@ CHIP_ERROR ExtensionFieldsSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet // if found, replace at found position, otherwise at insert first free position, otherwise return error if (idPosition < kMaxClusterPerScenes) { - ReturnErrorOnFailure(this->mEFS[idPosition] = fieldSet); - err = CHIP_NO_ERROR; + this->mEFS[idPosition] = fieldSet; + err = CHIP_NO_ERROR; } else if (firstEmptyPosition < kMaxClusterPerScenes) { - ReturnErrorOnFailure(this->mEFS[firstEmptyPosition] = fieldSet); + this->mEFS[firstEmptyPosition] = fieldSet; this->mFieldNum++; err = CHIP_NO_ERROR; } @@ -119,23 +117,22 @@ CHIP_ERROR ExtensionFieldsSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet CHIP_ERROR ExtensionFieldsSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & fieldSet, uint8_t position) { - if (position < this->mFieldNum) - { - ReturnErrorOnFailure(fieldSet = this->mEFS[position]); - } + VerifyOrReturnError(position < this->mFieldNum, CHIP_ERROR_BUFFER_TOO_SMALL); + + fieldSet = this->mEFS[position]; return CHIP_NO_ERROR; } CHIP_ERROR ExtensionFieldsSetsImpl::RemoveFieldAtPosition(uint8_t position) { - VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnValue(!this->IsEmpty() && !this->mEFS[position].IsEmpty(), CHIP_NO_ERROR); uint8_t next = position + 1; uint8_t moveNum = kMaxClusterPerScenes - next; + // TODO: Implement general array management methods // Compress array after removal memmove(&this->mEFS[position], &this->mEFS[next], sizeof(ExtensionFieldsSet) * moveNum); diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h index f1fa88daa6544f..a8b24623145dee 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h @@ -23,47 +23,64 @@ namespace chip { namespace scenes { +enum EFSTLVTag +{ + kTagEFSArrayContainer = 1, + kTagEFSFieldNum = 1, + kTagEFSContainer, + kTagEFSClusterID, + kTagEFS, +}; + using clusterId = chip::ClusterId; struct ExtensionFieldsSet { - static constexpr TLV::Tag TagClusterId() { return TLV::ContextTag(1); } - static constexpr TLV::Tag TagEFS() { return TLV::ContextTag(2); } clusterId mID = kInvalidClusterId; uint8_t mBytesBuffer[kMaxFieldsPerCluster] = { 0 }; uint8_t mUsedBytes = 0; ExtensionFieldsSet() = default; - ExtensionFieldsSet(clusterId cmID, uint8_t * data, uint8_t dataSize) : mID(cmID), mUsedBytes(dataSize) + ExtensionFieldsSet(clusterId cmID, const uint8_t * data, uint8_t dataSize) : mID(cmID), mUsedBytes(dataSize) { if (dataSize <= kMaxFieldsPerCluster) { memcpy(mBytesBuffer, data, mUsedBytes); } } + + ExtensionFieldsSet(clusterId cmID, ByteSpan bytes) : mID(cmID), mUsedBytes(static_cast(bytes.size())) + { + if (bytes.size() <= kMaxFieldsPerCluster) + { + memcpy(mBytesBuffer, bytes.data(), bytes.size()); + } + } + ~ExtensionFieldsSet() = default; CHIP_ERROR Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(kTagEFSContainer), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TagClusterId(), static_cast(this->mID))); - ReturnErrorOnFailure(writer.PutBytes(TagEFS(), mBytesBuffer, mUsedBytes)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagEFSClusterID), static_cast(this->mID))); + ReturnErrorOnFailure(writer.PutBytes(TLV::ContextTag(kTagEFS), mBytesBuffer, mUsedBytes)); return writer.EndContainer(container); } + CHIP_ERROR Deserialize(TLV::TLVReader & reader) { ByteSpan buffer; TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagEFSContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TagClusterId())); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFSClusterID))); ReturnErrorOnFailure(reader.Get(this->mID)); - ReturnErrorOnFailure(reader.Next(TagEFS())); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFS))); ReturnErrorOnFailure(reader.Get(buffer)); VerifyOrReturnError(buffer.size() <= kMaxFieldsPerCluster, CHIP_ERROR_BUFFER_TOO_SMALL); this->mUsedBytes = static_cast(buffer.size()); @@ -86,22 +103,6 @@ struct ExtensionFieldsSet return (this->mID == other.mID && !memcmp(this->mBytesBuffer, other.mBytesBuffer, this->mUsedBytes) && this->mUsedBytes == other.mUsedBytes); } - - CHIP_ERROR operator=(const ExtensionFieldsSet & other) - { - if (other.mUsedBytes <= kMaxFieldsPerCluster) - { - memcpy(this->mBytesBuffer, other.mBytesBuffer, other.mUsedBytes); - } - else - { - return CHIP_ERROR_BUFFER_TOO_SMALL; - } - this->mID = other.mID; - this->mUsedBytes = other.mUsedBytes; - - return CHIP_NO_ERROR; - } }; class ExtensionFieldsSetsImpl : public ExtensionFieldsSets @@ -114,7 +115,8 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override; CHIP_ERROR Deserialize(TLV::TLVReader & reader) override; void Clear() override; - bool IsEmpty() const override; + bool IsEmpty() const override { return (this->mFieldNum == 0); } + uint8_t GetFieldNum() const override { return this->mFieldNum; }; // implementation CHIP_ERROR InsertFieldSet(ExtensionFieldsSet & field); @@ -133,19 +135,18 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets return true; } - CHIP_ERROR operator=(const ExtensionFieldsSetsImpl & other) + ExtensionFieldsSetsImpl & operator=(const ExtensionFieldsSetsImpl & other) { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - ReturnErrorOnFailure(this->mEFS[i] = other.mEFS[i]); + this->mEFS[i] = other.mEFS[i]; } mFieldNum = other.mFieldNum; - return CHIP_NO_ERROR; + return *this; } protected: - static constexpr TLV::Tag TagFieldNum() { return TLV::ContextTag(1); } ExtensionFieldsSet mEFS[kMaxClusterPerScenes]; uint8_t mFieldNum = 0; }; diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 866de234c16762..a1b5bf55e93a38 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -26,58 +26,114 @@ namespace chip { namespace scenes { +enum SceneTLVTag +{ + kTagSceneStorageIDContainer = 1, + kTagSceneEndpointID, + kTagSceneGroupID, + kTagSceneID, + kTagSceneDataContainer, + kTagSceneName, + kTagSceneDTransitionTime, + kTagSceneDTransitionTime100, +}; + +typedef uint32_t TransitionTimeMs; typedef uint16_t SceneTransitionTime; typedef uint8_t TransitionTime100ms; +static constexpr uint8_t kEFSBufferSize = 128; static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; +static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; +/// @brief Abstract class allowing different Endpoints interactions with the ExtensionFieldSets added to and retrieved from the +/// scene Table +class SceneHandler +{ +public: + SceneHandler(){}; + virtual ~SceneHandler() = default; + + virtual bool SupportsCluster(EndpointId endpoint, ClusterId cluster) = 0; + + /// @brief From command AddScene, allows handler to filter through clusters in command to serialize only the supported ones. + /// @param endpoint Endpoint ID + /// @param cluster Cluster ID to fetch from command + /// @param serialysedBytes Buffer for ExtensionFieldSet in command + /// @param extensionFieldSet ExtensionFieldSets provided by the AddScene Command + /// @return + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialysedBytes, + app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) = 0; + + /// @brief From command SaveScene, retrieves ExtensionField from nvm + /// @param endpoint + /// @param cluster + /// @param serialysedBytes + /// @return + virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialysedBytes) = 0; + + /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a command object + /// @param endpoint Endpoint ID + /// @param cluster Cluster ID to set in command + /// @param serialysedBytes ExtensionFieldSet stored in NVM + /// @param extensionFieldSet ExtensionFieldSet in command format + /// @return + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialysedBytes, + app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; + + /// @brief From stored scene (e.g RecallScene), applies EFS values to cluster at transition time + /// @param endpoint Endpoint ID + /// @param cluster Cluster ID + /// @param serialysedBytes ExtensionFieldSet stored in NVM + /// @param timeMs Transition time in ms to apply the scene + /// @return + virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialysedBytes, TransitionTimeMs timeMs) = 0; +}; + class SceneTable { public: /// @brief struct used to identify a scene in storage by 3 ids, endpoint, group and scene struct SceneStorageId { - static constexpr TLV::Tag TagFirstSceneEndpointID() { return TLV::ContextTag(1); } - static constexpr TLV::Tag TagFirstSceneGroupID() { return TLV::ContextTag(2); } - static constexpr TLV::Tag TagFirstSceneID() { return TLV::ContextTag(3); } - // Identifies endpoint to which this scene applies - EndpointId mSceneEndpointId = kInvalidEndpointId; + EndpointId mEndpointId = kInvalidEndpointId; // Identifies group within the scope of the given fabric - SceneGroupID mSceneGroupId = kGlobalGroupSceneId; - SceneId mSceneId = kUndefinedSceneId; + SceneGroupID mGroupId = kGlobalGroupSceneId; + SceneId mSceneId = kUndefinedSceneId; SceneStorageId() = default; SceneStorageId(EndpointId endpoint, SceneId id, SceneGroupID groupId = kGlobalGroupSceneId) : - mSceneEndpointId(endpoint), mSceneGroupId(groupId), mSceneId(id) + mEndpointId(endpoint), mGroupId(groupId), mSceneId(id) {} SceneStorageId(const SceneStorageId & storageId) : - mSceneEndpointId(storageId.mSceneEndpointId), mSceneGroupId(storageId.mSceneGroupId), mSceneId(storageId.mSceneId) + mEndpointId(storageId.mEndpointId), mGroupId(storageId.mGroupId), mSceneId(storageId.mSceneId) {} CHIP_ERROR Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure( + writer.StartContainer(TLV::ContextTag(kTagSceneStorageIDContainer), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TagFirstSceneEndpointID(), static_cast(this->mSceneEndpointId))); - ReturnErrorOnFailure(writer.Put(TagFirstSceneGroupID(), static_cast(this->mSceneGroupId))); - ReturnErrorOnFailure(writer.Put(TagFirstSceneID(), static_cast(this->mSceneId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneEndpointID), static_cast(this->mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(this->mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(this->mSceneId))); return writer.EndContainer(container); } CHIP_ERROR Deserialize(TLV::TLVReader & reader) { TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagSceneStorageIDContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TagFirstSceneEndpointID())); - ReturnErrorOnFailure(reader.Get(this->mSceneEndpointId)); - ReturnErrorOnFailure(reader.Next(TagFirstSceneGroupID())); - ReturnErrorOnFailure(reader.Get(this->mSceneGroupId)); - ReturnErrorOnFailure(reader.Next(TagFirstSceneID())); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); + ReturnErrorOnFailure(reader.Get(this->mEndpointId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); + ReturnErrorOnFailure(reader.Get(this->mGroupId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); ReturnErrorOnFailure(reader.Get(this->mSceneId)); return reader.ExitContainer(container); @@ -85,30 +141,25 @@ class SceneTable void Clear() { - mSceneEndpointId = kInvalidEndpointId; - mSceneGroupId = kGlobalGroupSceneId; - mSceneId = kUndefinedSceneId; + mEndpointId = kInvalidEndpointId; + mGroupId = kGlobalGroupSceneId; + mSceneId = kUndefinedSceneId; } bool operator==(const SceneStorageId & other) { - return (this->mSceneEndpointId == other.mSceneEndpointId && this->mSceneGroupId == other.mSceneGroupId && - this->mSceneId == other.mSceneId); + return (this->mEndpointId == other.mEndpointId && this->mGroupId == other.mGroupId && this->mSceneId == other.mSceneId); } void operator=(const SceneStorageId & other) { - this->mSceneEndpointId = other.mSceneEndpointId; - this->mSceneGroupId = other.mSceneGroupId; - this->mSceneId = other.mSceneId; + this->mEndpointId = other.mEndpointId; + this->mGroupId = other.mGroupId; + this->mSceneId = other.mSceneId; } }; /// @brief struct used to store data held in a scene struct SceneData { - static constexpr TLV::Tag TagSceneName() { return TLV::ContextTag(1); } - static constexpr TLV::Tag TagSceneTransitionTime() { return TLV::ContextTag(2); } - static constexpr TLV::Tag TagSceneTransitionTime100() { return TLV::ContextTag(3); } - char mName[kSceneNameMax] = { 0 }; size_t mNameLength = 0; SceneTransitionTime mSceneTransitionTime = 0; @@ -140,16 +191,19 @@ class SceneTable CHIP_ERROR Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(1), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure( + writer.StartContainer(TLV::ContextTag(kTagSceneDataContainer), TLV::kTLVType_Structure, container)); // A 0 size means the name wasn't used so it won't get stored if (!this->mNameSpan.empty()) { - ReturnErrorOnFailure(writer.PutString(TagSceneName(), this->mNameSpan)); + ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(kTagSceneName), this->mNameSpan)); } - ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime(), static_cast(this->mSceneTransitionTime))); - ReturnErrorOnFailure(writer.Put(TagSceneTransitionTime100(), static_cast(this->mTransitionTime100ms))); + ReturnErrorOnFailure( + writer.Put(TLV::ContextTag(kTagSceneDTransitionTime), static_cast(this->mSceneTransitionTime))); + ReturnErrorOnFailure( + writer.Put(TLV::ContextTag(kTagSceneDTransitionTime100), static_cast(this->mTransitionTime100ms))); ReturnErrorOnFailure(this->mExtensionFieldsSets.Serialize(writer)); return writer.EndContainer(container); @@ -157,23 +211,24 @@ class SceneTable CHIP_ERROR Deserialize(TLV::TLVReader & reader) { TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(1))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagSceneDataContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); ReturnErrorOnFailure(reader.Next()); TLV::Tag currTag = reader.GetTag(); - VerifyOrReturnError(TagSceneName() == currTag || TagSceneTransitionTime() == currTag, CHIP_ERROR_WRONG_TLV_TYPE); + VerifyOrReturnError(TLV::ContextTag(kTagSceneName) == currTag || TLV::ContextTag(kTagSceneDTransitionTime) == currTag, + CHIP_ERROR_WRONG_TLV_TYPE); // If there was no error, a name is expected from the storage, if there was an unexpectec TLV element, - if (currTag == TagSceneName()) + if (currTag == TLV::ContextTag(kTagSceneName)) { ReturnErrorOnFailure(reader.Get(this->mNameSpan)); this->SetName(this->mNameSpan); - ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime())); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime))); } ReturnErrorOnFailure(reader.Get(this->mSceneTransitionTime)); - ReturnErrorOnFailure(reader.Next(TagSceneTransitionTime100())); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime100))); ReturnErrorOnFailure(reader.Get(this->mTransitionTime100ms)); ReturnErrorOnFailure(this->mExtensionFieldsSets.Deserialize(reader)); @@ -251,7 +306,7 @@ class SceneTable virtual ~SceneTable() = default; // Not copyable - SceneTable(const SceneTable &) = delete; + SceneTable(const SceneTable &) = delete; SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; @@ -271,6 +326,10 @@ class SceneTable // Fabrics virtual CHIP_ERROR RemoveFabric(FabricIndex fabric_index) = 0; + // Handlers + SceneHandler * mHandlers[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES] = { nullptr }; + uint8_t handlerNum = 0; + protected: const uint8_t mMaxScenePerFabric = kMaxScenePerFabric; }; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index b0ce8de1fb8282..cfb3f0306ac82e 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -22,6 +22,12 @@ namespace chip { namespace scenes { +enum SceneImplTLVTag +{ + kTagSceneCount = 1, + kTagNext, +}; + using SceneTableEntry = DefaultSceneTableImpl::SceneTableEntry; using SceneStorageId = DefaultSceneTableImpl::SceneStorageId; using SceneData = DefaultSceneTableImpl::SceneData; @@ -35,7 +41,7 @@ struct FabricHavingSceneList : public CommonPersistentData::FabricList } }; -static constexpr size_t kPersistentBufferMax = 128; +static constexpr size_t kPersistentBufferMax = 256; struct SceneTableData : public SceneTableEntry, PersistentData { @@ -93,10 +99,6 @@ struct SceneTableData : public SceneTableEntry, PersistentData { - static constexpr TLV::Tag TagSceneCount() { return TLV::ContextTag(1); } - static constexpr TLV::Tag TagSceneMap() { return TLV::ContextTag(2); } - static constexpr TLV::Tag TagNext() { return TLV::ContextTag(3); } - FabricIndex fabric_index = kUndefinedFabricIndex; uint8_t scene_count = 0; SceneStorageId scene_map[kMaxScenePerFabric]; @@ -127,12 +129,12 @@ struct FabricSceneData : public PersistentData TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TagSceneCount(), static_cast(scene_count))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneCount), static_cast(scene_count))); for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { ReturnErrorOnFailure(scene_map[i].Serialize(writer)); } - ReturnErrorOnFailure(writer.Put(TagNext(), static_cast(next))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNext), static_cast(next))); return writer.EndContainer(container); } @@ -145,13 +147,13 @@ struct FabricSceneData : public PersistentData TLV::TLVType container; ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TagSceneCount())); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneCount))); ReturnErrorOnFailure(reader.Get(scene_count)); for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { ReturnErrorOnFailure(scene_map[i].Deserialize(reader)); } - ReturnErrorOnFailure(reader.Next(TagNext())); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNext))); ReturnErrorOnFailure(reader.Get(next)); return reader.ExitContainer(container); @@ -254,7 +256,7 @@ struct FabricSceneData : public PersistentData idx = index; return CHIP_NO_ERROR; // return scene at current index if scene found } - if (scene_map[index].mSceneEndpointId == kInvalidEndpointId && firstFreeIdx == kUndefinedSceneIndex) + if (scene_map[index].mEndpointId == kInvalidEndpointId && firstFreeIdx == kUndefinedSceneIndex) { firstFreeIdx = index; } @@ -280,6 +282,7 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(Unregister(storage)); return PersistentData::Delete(storage); } + CHIP_ERROR SaveScene(PersistentStorageDelegate * storage, const SceneTableEntry & entry) { CHIP_ERROR err; @@ -397,38 +400,37 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fa return CHIP_NO_ERROR; } -/// @brief Registers handle to get extension fields set for a specific cluster. If the handler is already present in the handler -/// array, it will be overwritten -/// @param ID ID of the cluster used to fill the extension fields set -/// @param get_function pointer to function to call to get the extension fiels set from the cluster -/// @param set_function pointer to function to call send an extension field to the cluster -/// @return CHIP_ERROR_NO_MEMORY if couldn't insert the handler, otherwise CHIP_NO_ERROR -CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function) +/// @brief Register a handler in the handler list +/// @param handler Cluster specific handler for extension field sets interaction +/// @return CHIP_NO_ERROR if handler was registered, CHIP_ERROR_NO_MEMORY if the handler list is full +CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) { - CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; - uint8_t idPosition = 0xff, fisrtEmptyPosition = 0xff; - for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; + uint8_t idPosition = kInvalidPosition; + uint8_t fisrtEmptyPosition = kInvalidPosition; + + for (uint8_t i = 0; i < kMaxSceneHandlers; i++) { - if (this->handlers[i].GetID() == ID) + if (this->mHandlers[i] == handler) { idPosition = i; break; } - if (!this->handlers[i].IsInitialized() && fisrtEmptyPosition == 0xff) + if (this->mHandlers[i] == nullptr && fisrtEmptyPosition == kInvalidPosition) { fisrtEmptyPosition = i; } } // if found, insert at found position, otherwise at first free possition, otherwise return error - if (idPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + if (idPosition < kMaxSceneHandlers) { - this->handlers[idPosition].InitSceneHandler(ID, get_function, set_function); - err = CHIP_NO_ERROR; + this->mHandlers[idPosition] = handler; + err = CHIP_NO_ERROR; } - else if (fisrtEmptyPosition < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) + else if (fisrtEmptyPosition < kMaxSceneHandlers) { - this->handlers[fisrtEmptyPosition].InitSceneHandler(ID, get_function, set_function); + this->mHandlers[fisrtEmptyPosition] = handler; this->handlerNum++; err = CHIP_NO_ERROR; } @@ -438,36 +440,37 @@ CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(ClusterId ID, clusterFieldsHan CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) { - if (!HandlerListEmpty()) - { - if (position < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES) - { - if (this->handlers[position].IsInitialized()) - { - this->handlers[position].ClearSceneHandler(); - this->handlerNum--; - } - } - else - { - return CHIP_ERROR_ACCESS_DENIED; - } - } + VerifyOrReturnError(position < kMaxSceneHandlers, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnValue(!this->HandlerListEmpty() && !(this->mHandlers[position] == nullptr), CHIP_NO_ERROR); + + uint8_t next = position + 1; + uint8_t moveNum = kMaxSceneHandlers - next; + + // TODO: Implement general array management methods + // Compress array after removal + memmove(&this->mHandlers[position], &this->mHandlers[next], sizeof(SceneHandler *) * moveNum); + + this->handlerNum--; + // Clear last occupied position + this->mHandlers[handlerNum] = nullptr; return CHIP_NO_ERROR; } -CHIP_ERROR DefaultSceneTableImpl::EFSValuesFromCluster(ExtensionFieldsSetsImpl & fieldSets) +CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene, clusterId cluster) { ExtensionFieldsSet EFS; + MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldsPerCluster); if (!this->HandlerListEmpty()) { - for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + for (uint8_t i = 0; i < this->handlerNum; i++) { - if (this->handlers[i].IsInitialized()) + if (this->mHandlers[i] != nullptr) { - ReturnErrorOnFailure(this->handlers[i].GetClusterEFS(EFS)); - ReturnErrorOnFailure(fieldSets.InsertFieldSet(EFS)); + EFS.mID = cluster; + ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, cluster, EFSSpan)); + EFS.mUsedBytes = (uint8_t) EFSSpan.size(); + ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldsSets.InsertFieldSet(EFS)); } } } @@ -475,23 +478,33 @@ CHIP_ERROR DefaultSceneTableImpl::EFSValuesFromCluster(ExtensionFieldsSetsImpl & return CHIP_NO_ERROR; } -CHIP_ERROR DefaultSceneTableImpl::EFSValuesToCluster(ExtensionFieldsSetsImpl & fieldSets) +CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) { + FabricSceneData fabric(fabric_index); + SceneTableData scene(fabric_index); ExtensionFieldsSet EFS; + TransitionTimeMs time; + clusterId cluster; + + ReturnErrorOnFailure(fabric.Load(mStorage)); + VerifyOrReturnError(fabric.Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); + ReturnErrorOnFailure(scene.Load(mStorage)); + if (!this->HandlerListEmpty()) { - for (uint8_t i = 0; i < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; i++) + for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldsSets.GetFieldNum(); i++) { - fieldSets.GetFieldSetAtPosition(EFS, i); + scene.mStorageData.mExtensionFieldsSets.GetFieldSetAtPosition(EFS, i); + cluster = EFS.mID; + time = scene.mStorageData.mSceneTransitionTime * 1000 + + (scene.mStorageData.mTransitionTime100ms ? scene.mStorageData.mTransitionTime100ms * 10 : 0); + ByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, EFS.mUsedBytes); if (!EFS.IsEmpty()) { - for (uint8_t j = 0; j < CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; j++) + for (uint8_t j = 0; j < this->handlerNum; j++) { - if (EFS.mID == this->handlers[j].GetID()) - { - ReturnErrorOnFailure(this->handlers[j].SetClusterEFS(EFS)); - } + ReturnErrorOnFailure(this->mHandlers[j]->ApplyScene(scene.mStorageId.mEndpointId, cluster, EFSSpan, time)); } } } @@ -548,7 +561,7 @@ bool DefaultSceneTableImpl::SceneEntryIteratorImpl::Next(SceneTableEntry & outpu // looks for next available scene while (mSceneIndex < kMaxScenePerFabric) { - if (fabric.scene_map[mSceneIndex].mSceneEndpointId != kInvalidEndpointId) + if (fabric.scene_map[mSceneIndex].mEndpointId != kInvalidEndpointId) { scene.index = mSceneIndex; VerifyOrReturnError(scene.Load(mProvider.mStorage) == CHIP_NO_ERROR, false); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index c3fb2e043b948a..aac47870632db4 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -27,86 +27,135 @@ namespace scenes { using clusterId = chip::ClusterId; -typedef CHIP_ERROR (*clusterFieldsHandle)(ExtensionFieldsSet & fields); - -/// @brief Class to allow extension field sets to be handled by the scene table without any knowledge of the cluster or its -/// implementation -class SceneHandler +/// @brief Default implementation of handler, handle EFS from add scene and view scene commands for any cluster +/// The implementation of SerializeSave and ApplyScene were omitted and must be implemented in a way that +/// is compatible with the SerializeAdd output in order to function with the Default Scene Handler. +/// It is worth noting that this implementation is very memory consuming. In the current worst case, +/// (Color control cluster), the Extension Field Set's value pair list TLV occupies 99 bytes of memory +class DefaultSceneHandlerImpl : public scenes::SceneHandler { public: - SceneHandler(ClusterId Id = kInvalidClusterId, clusterFieldsHandle getEFSHandle = nullptr, - clusterFieldsHandle setEFSHandle = nullptr) + static constexpr uint8_t kMaxValueSize = 4; + static constexpr uint8_t kMaxAvPair = 15; + + DefaultSceneHandlerImpl() = default; + ~DefaultSceneHandlerImpl() override{}; + + /// @brief Function to serialize data from an add scene command, assume the incoming extensionFieldSet is initialized + /// @param endpoint Target Endpoint + /// @param cluster Cluster in the Extension field set, filled by the function + /// @param serialyzedBytes Mutable Byte span to hold EFS data from command + /// @param extensionFieldSet Extension field set from commmand, pre initialized + /// @return CHIP_NO_ERROR if success, specific CHIP_ERROR otherwise + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialyzedBytes, + app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) override { - if (getEFSHandle != nullptr && setEFSHandle != nullptr && Id != kInvalidClusterId) - { - getEFS = getEFSHandle; - setEFS = setEFSHandle; - cID = Id; - initialized = true; - } - }; - ~SceneHandler(){}; + app::DataModel::List attributeValueList; + app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; + TLV::TLVWriter writer; + TLV::TLVType outer; - void InitSceneHandler(ClusterId Id, clusterFieldsHandle getEFSHandle, clusterFieldsHandle setEFSHandle) - { - if (getEFSHandle != nullptr && setEFSHandle != nullptr && Id != kInvalidClusterId) - { - getEFS = getEFSHandle; - setEFS = setEFSHandle; - cID = Id; - initialized = true; - } - } + uint8_t pairCount = 0; + uint8_t valueBytes = 0; - void ClearSceneHandler() - { - getEFS = nullptr; - setEFS = nullptr; - cID = kInvalidClusterId; - initialized = false; - } + VerifyOrReturnError(SupportsCluster(endpoint, extensionFieldSet.clusterID), CHIP_ERROR_INVALID_ARGUMENT); - CHIP_ERROR GetClusterEFS(ExtensionFieldsSet & clusterFields) - { - if (this->IsInitialized()) + cluster = extensionFieldSet.clusterID; + + auto pair_iterator = extensionFieldSet.attributeValueList.begin(); + while (pair_iterator.Next() && pairCount < kMaxAvPair) { - ReturnErrorOnFailure(getEFS(clusterFields)); + aVPair = pair_iterator.GetValue(); + mAVPairs[pairCount].attributeID = aVPair.attributeID; + auto value_iterator = aVPair.attributeValue.begin(); + + valueBytes = 0; + while (value_iterator.Next() && valueBytes < kMaxValueSize) + { + mValueBuffer[pairCount][valueBytes] = value_iterator.GetValue(); + valueBytes++; + } + // Check we could go through all bytes of the value + VerifyOrReturnError(value_iterator.Next() == false, CHIP_ERROR_BUFFER_TOO_SMALL); + mAVPairs[pairCount].attributeValue = mValueBuffer[pairCount]; + mAVPairs[pairCount].attributeValue.reduce_size(valueBytes); + pairCount++; } + // Check we could go through all pairs in incomming command + VerifyOrReturnError(pair_iterator.Next() == false, CHIP_ERROR_BUFFER_TOO_SMALL); + + attributeValueList = mAVPairs; + attributeValueList.reduce_size(pairCount); + + writer.Init(serialyzedBytes); + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(app::DataModel::Encode( + writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + attributeValueList)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + return CHIP_NO_ERROR; } - CHIP_ERROR SetClusterEFS(ExtensionFieldsSet & clusterFields) + + /// @brief Simulates taking data from nvm and loading it in a command object if the cluster is supported by the endpoint + /// @param endpoint target endpoint + /// @param cluster target cluster + /// @param serialyzedBytes data to deserialize into EFS + /// @return CHIP_NO_ERROR if Extension Field Set was successfully populated, specific CHIP_ERROR otherwise + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialyzedBytes, + app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) override { - if (this->IsInitialized()) - { - ReturnErrorOnFailure(setEFS(clusterFields)); - } + app::DataModel::DecodableList attributeValueList; + app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType decodePair; - return CHIP_NO_ERROR; - } + TLV::TLVReader reader; + TLV::TLVType outer; + uint8_t pairCount = 0; + uint8_t valueBytes = 0; - bool IsInitialized() const { return this->initialized; } + VerifyOrReturnError(SupportsCluster(endpoint, cluster), CHIP_ERROR_INVALID_ARGUMENT); - ClusterId GetID() { return cID; } + extensionFieldSet.clusterID = cluster; + reader.Init(serialyzedBytes); + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.EnterContainer(outer)); + ReturnErrorOnFailure(reader.Next()); + attributeValueList.Decode(reader); - bool operator==(const SceneHandler & other) - { - return (this->getEFS == other.getEFS && this->setEFS == other.setEFS && this->cID == other.cID && - initialized == other.initialized); - } - void operator=(const SceneHandler & other) - { - this->getEFS = other.getEFS; - this->setEFS = other.setEFS; - this->cID = other.cID; - this->initialized = true; + auto pair_iterator = attributeValueList.begin(); + while (pair_iterator.Next() && pairCount < kMaxAvPair) + { + decodePair = pair_iterator.GetValue(); + mAVPairs[pairCount].attributeID = decodePair.attributeID; + auto value_iterator = decodePair.attributeValue.begin(); + valueBytes = 0; + + while (value_iterator.Next() && valueBytes < kMaxValueSize) + { + mValueBuffer[pairCount][valueBytes] = value_iterator.GetValue(); + valueBytes++; + } + // Check we could go through all bytes of the value + VerifyOrReturnError(value_iterator.Next() == false, CHIP_ERROR_BUFFER_TOO_SMALL); + mAVPairs[pairCount].attributeValue = mValueBuffer[pairCount]; + mAVPairs[pairCount].attributeValue.reduce_size(valueBytes); + pairCount++; + }; + + // Check we could go through all pairs stored in memory + VerifyOrReturnError(pair_iterator.Next() == false, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(reader.ExitContainer(outer)); + + extensionFieldSet.attributeValueList = mAVPairs; + extensionFieldSet.attributeValueList.reduce_size(pairCount); + + return CHIP_NO_ERROR; } -protected: - clusterFieldsHandle getEFS = nullptr; - clusterFieldsHandle setEFS = nullptr; - ClusterId cID = kInvalidClusterId; - bool initialized = false; +private: + app::Clusters::Scenes::Structs::AttributeValuePair::Type mAVPairs[kMaxAvPair]; + uint8_t mValueBuffer[kMaxAvPair][kMaxValueSize]; }; /** @@ -129,18 +178,17 @@ class DefaultSceneTableImpl : public SceneTable // Scene access by Id CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) override; - CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id, - SceneTableEntry & entry) override; - CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, DefaultSceneTableImpl::SceneStorageId scene_id) override; + CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) override; + CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) override; CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) override; // SceneHandlers - CHIP_ERROR RegisterHandler(ClusterId ID, clusterFieldsHandle get_function, clusterFieldsHandle set_function); + CHIP_ERROR RegisterHandler(SceneHandler * handler); CHIP_ERROR UnregisterHandler(uint8_t position); // Extension field sets operation - CHIP_ERROR EFSValuesFromCluster(ExtensionFieldsSetsImpl & fieldSets); - CHIP_ERROR EFSValuesToCluster(ExtensionFieldsSetsImpl & fieldSets); + CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene, clusterId cluster); + CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id); // Fabrics CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; @@ -172,8 +220,6 @@ class DefaultSceneTableImpl : public SceneTable chip::PersistentStorageDelegate * mStorage = nullptr; ObjectPool mSceneEntryIterators; - SceneHandler handlers[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES]; - uint8_t handlerNum = 0; }; // class DefaultSceneTableImpl /** diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index bf7d2b64bda9d1..f09059cca056da 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -17,41 +17,59 @@ */ #include +#include +#include #include #include #include -using FabricIndex = chip::FabricIndex; -using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; -using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; -using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; -using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; -using CharSpan = chip::CharSpan; -using ExtensionFieldsSet = chip::scenes::ExtensionFieldsSet; +using namespace chip; +using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; +using SceneTableImpl = scenes::DefaultSceneTableImpl; +using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; +using SceneData = scenes::DefaultSceneTableImpl::SceneData; +using ExtensionFieldsSet = scenes::ExtensionFieldsSet; +using TransitionTimeMs = scenes::TransitionTimeMs; #define ON_OFF_CID 0x0006 #define LV_CTR_CID 0x0008 -#define CO_CTR_CID 0x0300 +#define CC_CTR_CID 0x0300 +#define TEST_ENDPOINT1 0x0001 +#define TEST_ENDPOINT2 0x0099 + +// ON OFF ATTRIBUTE IDs +#define ON_OFF_ID 0x0000 + +// LEVEL CONTROL ATTRIBUTE IDs +#define CURRENT_LVL_ID 0x0000 +#define CURRENT_FRQ_ID 0x0004 + +// COLOR CONTROL ATTRIBUTE IDs +#define CURRENT_SAT_ID 0x0001 +#define CURRENT_X_ID 0x0003 +#define CURRENT_Y_ID 0x0004 +#define COLOR_TEMP_MIR_ID 00007 +#define EN_CURRENT_HUE_ID 0x4000 +#define C_LOOP_ACTIVE_ID 0x4002 +#define C_LOOP_DIR_ID 0x4003 +#define C_LOOP_TIME_ID 0x4004 namespace { -static chip::TestPersistentStorageDelegate testStorage; -static SceneTableImpl sSceneTable; - // Test fabrics, adding more requires to modify the "ResetSceneTable" function constexpr chip::FabricIndex kFabric1 = 1; constexpr chip::FabricIndex kFabric2 = 7; // Scene storage ID -static const SceneStorageId sceneId1(1, 0xAA, 0x101); -static const SceneStorageId sceneId2(1, 0xBB, 0x00); -static const SceneStorageId sceneId3(1, 0xCC, 0x102); -static const SceneStorageId sceneId4(1, 0xBE, 0x00); -static const SceneStorageId sceneId5(1, 0x45, 0x103); -static const SceneStorageId sceneId6(1, 0x65, 0x00); -static const SceneStorageId sceneId7(1, 0x77, 0x101); -static const SceneStorageId sceneId8(1, 0xEE, 0x101); -static const SceneStorageId sceneId9(1, 0xAB, 0x101); +static const SceneStorageId sceneId1(TEST_ENDPOINT1, 0xAA, 0x101); +static const SceneStorageId sceneId2(TEST_ENDPOINT1, 0xBB, 0x00); +static const SceneStorageId sceneId3(TEST_ENDPOINT2, 0xCC, 0x102); +static const SceneStorageId sceneId4(TEST_ENDPOINT2, 0xBE, 0x00); +static const SceneStorageId sceneId5(TEST_ENDPOINT1, 0x45, 0x103); +static const SceneStorageId sceneId6(TEST_ENDPOINT1, 0x65, 0x00); +static const SceneStorageId sceneId7(TEST_ENDPOINT1, 0x77, 0x101); +static const SceneStorageId sceneId8(TEST_ENDPOINT2, 0xEE, 0x101); +static const SceneStorageId sceneId9(TEST_ENDPOINT2, 0xAB, 0x101); // Scene data static const SceneData sceneData1(CharSpan("Scene #1", sizeof("Scene #1"))); @@ -81,77 +99,163 @@ SceneTableEntry scene10(sceneId1, sceneData10); SceneTableEntry scene11(sceneId5, sceneData11); SceneTableEntry scene12(sceneId8, sceneData12); -// EFS -static const ExtensionFieldsSet onOffEFS1 = ExtensionFieldsSet(ON_OFF_CID, (uint8_t *) "1", 1); -static const ExtensionFieldsSet onOffEFS2 = ExtensionFieldsSet(ON_OFF_CID, (uint8_t *) "0", 1); -static const ExtensionFieldsSet lvCtrEFS1 = ExtensionFieldsSet(LV_CTR_CID, (uint8_t *) "511", 3); -static const ExtensionFieldsSet lvCtrEFS2 = ExtensionFieldsSet(LV_CTR_CID, (uint8_t *) "222", 3); -static const ExtensionFieldsSet coCtrEFS1 = ExtensionFieldsSet(CO_CTR_CID, (uint8_t *) "123456789abcde", 14); -static const ExtensionFieldsSet coCtrEFS2 = ExtensionFieldsSet(CO_CTR_CID, (uint8_t *) "abcdefghi12345", 14); +// Clusters EFS data +static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type OOextensionFieldSet; +static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type LCextensionFieldSet; +static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type CCextensionFieldSet; -// Simulation of clusters callbacks (sate #1) -CHIP_ERROR oo_from_cluster_cb1(ExtensionFieldsSet & fields) -{ - ReturnErrorOnFailure(fields = onOffEFS1); - return CHIP_NO_ERROR; -} -CHIP_ERROR oo_to_cluster_cb1(ExtensionFieldsSet & fields) -{ - VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} -CHIP_ERROR lc_from_cluster_cb1(ExtensionFieldsSet & fields) -{ - ReturnErrorOnFailure(fields = lvCtrEFS1); - return CHIP_NO_ERROR; -} -CHIP_ERROR lc_to_cluster_cb1(ExtensionFieldsSet & fields) -{ - VerifyOrReturnError(fields == lvCtrEFS1, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} -CHIP_ERROR cc_from_cluster_cb1(ExtensionFieldsSet & fields) -{ - ReturnErrorOnFailure(fields = coCtrEFS1); - return CHIP_NO_ERROR; -} -CHIP_ERROR cc_to_cluster_cb1(ExtensionFieldsSet & fields) -{ - VerifyOrReturnError(fields == coCtrEFS1, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} +static app::Clusters::Scenes::Structs::AttributeValuePair::Type OOPairs[1]; +static app::Clusters::Scenes::Structs::AttributeValuePair::Type LCPairs[2]; +static app::Clusters::Scenes::Structs::AttributeValuePair::Type CCPairs[8]; -// Simulation of clusters callbacks (sate #2) -CHIP_ERROR oo_from_cluster_cb2(ExtensionFieldsSet & fields) -{ - ReturnErrorOnFailure(fields = onOffEFS1); - return CHIP_NO_ERROR; -} -CHIP_ERROR oo_to_cluster_cb2(ExtensionFieldsSet & fields) -{ - VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} -CHIP_ERROR lc_from_cluster_cb2(ExtensionFieldsSet & fields) -{ - ReturnErrorOnFailure(fields = lvCtrEFS2); - return CHIP_NO_ERROR; -} -CHIP_ERROR lc_to_cluster_cb2(ExtensionFieldsSet & fields) -{ - VerifyOrReturnError(fields == lvCtrEFS2, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} -CHIP_ERROR cc_from_cluster_cb2(ExtensionFieldsSet & fields) -{ - ReturnErrorOnFailure(fields = coCtrEFS2); - return CHIP_NO_ERROR; -} -CHIP_ERROR cc_to_cluster_cb2(ExtensionFieldsSet & fields) +static uint8_t OO_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; +static uint8_t LC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; +static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; + +/// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control +class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { - VerifyOrReturnError(fields == coCtrEFS2, CHIP_ERROR_INVALID_ARGUMENT); - return CHIP_NO_ERROR; -} +public: + static constexpr uint8_t kMaxValueSize = 4; + static constexpr uint8_t kMaxAvPair = 15; + + TestSceneHandler() = default; + ~TestSceneHandler() override {} + + // Default function only checks if endpoint and clusters are valid + bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override + { + bool ret = false; + if (endpoint == TEST_ENDPOINT1) + { + if (cluster == ON_OFF_CID || cluster == LV_CTR_CID) + { + ret = true; + } + } + + if (endpoint == TEST_ENDPOINT2) + { + if (cluster == ON_OFF_CID || cluster == CC_CTR_CID) + { + ret = true; + } + } + + return ret; + } + + /// @brief Simulates save from cluster, data is already in an EFS struct but this isn't mandatory + /// @param endpoint target endpoint + /// @param cluster target cluster + /// @param serialyzedBytes data to serialize into EFS + /// @return success if successfully serialized the data, CHIP_ERROR_INVALID_ARGUMENT if endpoint or cluster not supported + CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialyzedBytes) override + { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + + if (endpoint == TEST_ENDPOINT1) + { + switch (cluster) + { + case ON_OFF_CID: + err = CHIP_NO_ERROR; + memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + serialyzedBytes.reduce_size(15); // Used memory for OnOff TLV + break; + case LV_CTR_CID: + err = CHIP_NO_ERROR; + memcpy(serialyzedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + serialyzedBytes.reduce_size(27); // Used memory for Level Control TLV + break; + default: + break; + } + } + if (endpoint == TEST_ENDPOINT2) + { + switch (cluster) + { + case ON_OFF_CID: + err = CHIP_NO_ERROR; + memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + serialyzedBytes.reduce_size(15); // Used memory for Color Control TLV + break; + case CC_CTR_CID: + err = CHIP_NO_ERROR; + memcpy(serialyzedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + serialyzedBytes.reduce_size(99); // Used memory for Color Control TLV + break; + default: + break; + } + } + return err; + } + + /// @brief Simulates EFS being applied to a scene, here just validates that the data is as expected, no action taken by the + /// "cluster" + /// @param endpoint target endpoint + /// @param cluster target cluster + /// @param serialyzedBytes Data from nvm + /// @param timeMs transition time in ms + /// @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise + CHIP_ERROR + ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialyzedBytes, TransitionTimeMs timeMs) override + { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + + // Takes values from cluster in Endpoint 1 + if (endpoint == TEST_ENDPOINT1) + { + switch (cluster) + { + case ON_OFF_CID: + if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + case LV_CTR_CID: + if (!memcmp(serialyzedBytes.data(), LC_buffer, serialyzedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + default: + break; + } + } + + // Takes values from cluster in Endpoint 2 + if (endpoint == TEST_ENDPOINT2) + { + switch (cluster) + { + case ON_OFF_CID: + if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + case CC_CTR_CID: + if (!memcmp(serialyzedBytes.data(), CC_buffer, serialyzedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + default: + break; + } + } + + return CHIP_NO_ERROR; + } +}; + +static chip::TestPersistentStorageDelegate testStorage; +static SceneTableImpl sSceneTable; +static TestSceneHandler sHandler; void ResetSceneTable(SceneTableImpl * sceneTable) { @@ -159,6 +263,201 @@ void ResetSceneTable(SceneTableImpl * sceneTable) sceneTable->RemoveFabric(kFabric2); } +void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) +{ + SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + ClusterId tempCluster = 0; + + app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; + app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldSetIn; + app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; + + TLV::TLVReader reader; + TLV::TLVWriter writer; + TLV::TLVType outer; + TLV::TLVType outerRead; + + static const uint8_t OO_av_payload[1] = { 0x01 }; + static const uint8_t LC_av_payload[2][2] = { { 0x40, 0x00 }, { 0x01, 0xF0 } }; + static const uint8_t CC_av_payload[8][2] = { { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, + { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 } }; + + OOPairs[0].attributeID.SetValue(ON_OFF_ID); + OOPairs[0].attributeValue = OO_av_payload; + + LCPairs[0].attributeID.SetValue(CURRENT_LVL_ID); + LCPairs[0].attributeValue = LC_av_payload[0]; + LCPairs[0].attributeValue.reduce_size(1); + LCPairs[1].attributeID.SetValue(CURRENT_FRQ_ID); + LCPairs[1].attributeValue = LC_av_payload[1]; + + CCPairs[0].attributeID.SetValue(CURRENT_SAT_ID); + CCPairs[0].attributeValue = CC_av_payload[0]; + CCPairs[0].attributeValue.reduce_size(1); + CCPairs[1].attributeID.SetValue(CURRENT_X_ID); + CCPairs[1].attributeValue = CC_av_payload[1]; + CCPairs[2].attributeID.SetValue(CURRENT_Y_ID); + CCPairs[2].attributeValue = CC_av_payload[2]; + CCPairs[3].attributeID.SetValue(COLOR_TEMP_MIR_ID); + CCPairs[3].attributeValue = CC_av_payload[3]; + CCPairs[4].attributeID.SetValue(EN_CURRENT_HUE_ID); + CCPairs[4].attributeValue = CC_av_payload[4]; + CCPairs[5].attributeID.SetValue(C_LOOP_ACTIVE_ID); + CCPairs[5].attributeValue = CC_av_payload[5]; + CCPairs[5].attributeValue.reduce_size(1); + CCPairs[6].attributeID.SetValue(C_LOOP_DIR_ID); + CCPairs[6].attributeValue = CC_av_payload[6]; + CCPairs[6].attributeValue.reduce_size(1); + CCPairs[7].attributeID.SetValue(C_LOOP_TIME_ID); + CCPairs[7].attributeValue = CC_av_payload[7]; + + // Initialize Extension Field sets as if they were received by add commands + OOextensionFieldSet.clusterID = ON_OFF_CID; + OOextensionFieldSet.attributeValueList = OOPairs; + LCextensionFieldSet.clusterID = LV_CTR_CID; + LCextensionFieldSet.attributeValueList = LCPairs; + CCextensionFieldSet.clusterID = CC_CTR_CID; + CCextensionFieldSet.attributeValueList = CCPairs; + + ByteSpan OO_list(OO_buffer); + ByteSpan LC_list(LC_buffer); + ByteSpan CC_list(CC_buffer); + + uint8_t buffer[scenes::kMaxFieldsPerCluster] = { 0 }; + MutableByteSpan buff_span(buffer); + + // Serialize Extension Field sets as if they were recovered from memory + writer.Init(OO_buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + app::DataModel::Encode(writer, + TLV::ContextTag(to_underlying( + app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + OOextensionFieldSet.attributeValueList)); + writer.EndContainer(outer); + + writer.Init(LC_buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + app::DataModel::Encode(writer, + TLV::ContextTag(to_underlying( + app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + LCextensionFieldSet.attributeValueList)); + writer.EndContainer(outer); + + writer.Init(CC_buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + app::DataModel::Encode(writer, + TLV::ContextTag(to_underlying( + app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + CCextensionFieldSet.attributeValueList)); + writer.EndContainer(outer); + + // Test Registering SceneHandler + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&sHandler)); + NL_TEST_ASSERT(aSuite, sceneTable->GetHandlerNum() == 1); + + // Setup the On Off Extension field set in the expected state from a command + reader.Init(OO_list); + extensionFieldSetIn.clusterID = ON_OFF_CID; + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); + + // Verify the handler extracted buffer matches the initial field sets + NL_TEST_ASSERT(aSuite, 0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size())); + NL_TEST_ASSERT(aSuite, tempCluster == ON_OFF_CID); + memset(buffer, 0, buff_span.size()); + + // Setup the Level Control Extension field set in the expected state from a command + reader.Init(LC_list); + extensionFieldSetIn.clusterID = LV_CTR_CID; + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); + + // Verify the handler extracted buffer matches the initial field sets + NL_TEST_ASSERT(aSuite, 0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size())); + NL_TEST_ASSERT(aSuite, tempCluster == LV_CTR_CID); + memset(buffer, 0, buff_span.size()); + + // Setup the Color control Extension field set in the expected state from a command + reader.Init(CC_list); + extensionFieldSetIn.clusterID = CC_CTR_CID; + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT2, tempCluster, buff_span, extensionFieldSetIn)); + + // Verify the handler extracted buffer matches the initial field sets + NL_TEST_ASSERT(aSuite, 0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size())); + NL_TEST_ASSERT(aSuite, tempCluster == CC_CTR_CID); + memset(buffer, 0, buff_span.size()); + + // Verify Deserializing is properly filling out output extension field set for on off + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT1, ON_OFF_CID, OO_list, extensionFieldSetOut)); + + // Verify Encoding the Extension field set returns the same data as + writer.Init(buff_span); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + app::DataModel::Encode(writer, + TLV::ContextTag(to_underlying( + app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + extensionFieldSetOut.attributeValueList)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.EndContainer(outer)); + NL_TEST_ASSERT(aSuite, 0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size())); + memset(buffer, 0, buff_span.size()); + + // Verify Deserializing is properly filling out output extension field set for level control + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT1, LV_CTR_CID, LC_list, extensionFieldSetOut)); + + // Verify Encoding the Extension field set returns the same data as + writer.Init(buff_span); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + app::DataModel::Encode(writer, + TLV::ContextTag(to_underlying( + app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + extensionFieldSetOut.attributeValueList)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.EndContainer(outer)); + NL_TEST_ASSERT(aSuite, 0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size())); + memset(buffer, 0, buff_span.size()); + + // Verify Deserializing is properly filling out output extension field set for color control + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT2, CC_CTR_CID, CC_list, extensionFieldSetOut)); + + // Verify Encoding the Extension field set returns the same data as + writer.Init(buff_span); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + app::DataModel::Encode(writer, + TLV::ContextTag(to_underlying( + app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + extensionFieldSetOut.attributeValueList)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.EndContainer(outer)); + NL_TEST_ASSERT(aSuite, 0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size())); + memset(buffer, 0, buff_span.size()); +}; + void TestStoreScenes(nlTestSuite * aSuite, void * aContext) { SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); @@ -167,16 +466,25 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Reset test ResetSceneTable(sceneTable); - // Test SceneHandlers - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(onOffEFS1.mID, &oo_from_cluster_cb1, &oo_to_cluster_cb1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(lvCtrEFS1.mID, &lc_from_cluster_cb1, &lc_to_cluster_cb1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(coCtrEFS2.mID, &cc_from_cluster_cb1, &cc_to_cluster_cb1)); + // Populate scene1's EFS (Endpoint1) + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene1, ON_OFF_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene1, LV_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene1, CC_CTR_CID)); + + // Populate scene2's EFS (Endpoint1) + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene2, ON_OFF_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene2, LV_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene2, CC_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene1.mStorageData.mExtensionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene2.mStorageData.mExtensionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene3.mStorageData.mExtensionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene4.mStorageData.mExtensionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene5.mStorageData.mExtensionFieldsSets)); + // Populate scene3's EFS (Endpoint2) + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3, ON_OFF_CID)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene3, LV_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3, CC_CTR_CID)); + + // Populate scene3's EFS (Endpoint2) + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4, ON_OFF_CID)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene4, LV_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4, CC_CTR_CID)); SceneTableEntry scene; @@ -199,24 +507,22 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Get test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene1.mStorageId)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); NL_TEST_ASSERT(aSuite, scene == scene2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene2.mStorageId)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); NL_TEST_ASSERT(aSuite, scene == scene3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene3.mStorageId)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId4, scene)); NL_TEST_ASSERT(aSuite, scene == scene4); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene4.mStorageId)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene5); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId6, scene)); NL_TEST_ASSERT(aSuite, scene == scene6); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId7, scene)); @@ -230,18 +536,6 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); - // Test SceneHandlers overwrite - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(onOffEFS2.mID, &oo_from_cluster_cb2, &oo_to_cluster_cb2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(lvCtrEFS2.mID, &lc_from_cluster_cb2, &lc_to_cluster_cb2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(coCtrEFS2.mID, &cc_from_cluster_cb2, &cc_to_cluster_cb2)); - - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene10.mStorageData.mExtensionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene11.mStorageData.mExtensionFieldsSets)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesFromCluster(scene12.mStorageData.mExtensionFieldsSets)); - - // Verfies the overwrite hasn't changed the handlers number - NL_TEST_ASSERT(aSuite, sceneTable->GetHandlerNum() == 3); - SceneTableEntry scene; // Overwriting the first entry NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene10)); @@ -253,15 +547,12 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) // Scene 10 has the same sceneId as scene 1, Get->sceneId1 should thus return scene 10, etc. NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene10); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene11); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); NL_TEST_ASSERT(aSuite, scene == scene12); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->EFSValuesToCluster(scene.mStorageData.mExtensionFieldsSets)); } void TestIterateScenes(nlTestSuite * aSuite, void * aContext) @@ -479,11 +770,13 @@ int TestTeardown(void * inContext) } int TestSceneTable() { - static nlTest sTests[] = { - NL_TEST_DEF("TestStoreScenes", TestStoreScenes), NL_TEST_DEF("TestOverwriteScenes", TestOverwriteScenes), - NL_TEST_DEF("TestIterateScenes", TestIterateScenes), NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), - NL_TEST_DEF("TestFabricScenes", TestFabricScenes), NL_TEST_SENTINEL() - }; + static nlTest sTests[] = { NL_TEST_DEF("TestStoreScenes", TestHandlerFunctions), + NL_TEST_DEF("TestStoreScenes", TestStoreScenes), + NL_TEST_DEF("TestOverwriteScenes", TestOverwriteScenes), + NL_TEST_DEF("TestIterateScenes", TestIterateScenes), + NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), + NL_TEST_DEF("TestFabricScenes", TestFabricScenes), + NL_TEST_SENTINEL() }; nlTestSuite theSuite = { "SceneTable", diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 6bbb1208c49b47..35e01fa5fda125 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1424,7 +1424,7 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; * @brief The maximum size of a single extension field set for a single cluster */ #ifndef CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER -#define CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER 15 +#define CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER 100 #endif /** @@ -1440,4 +1440,4 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; /** * @} - */ + */ \ No newline at end of file diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h index 420d675e9a9044..a8706eaaf0638b 100644 --- a/src/lib/support/TestSceneTable.h +++ b/src/lib/support/TestSceneTable.h @@ -30,48 +30,379 @@ using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; using ExtensionFieldsSet = chip::scenes::ExtensionFieldsSet; +using TransitionTimeMs = chip::scenes::TransitionTimeMs; + +#define ON_OFF_CID 0x0006 +#define LV_CTR_CID 0x0008 +#define CC_CTR_CID 0x0300 +#define TEST_ENDPOINT1 0x0001 +#define TEST_ENDPOINT2 0x0099 + +// ON OFF ATTRIBUTE IDs +#define ON_OFF_ID 0x0000 + +// LEVEL CONTROL ATTRIBUTE IDs +#define CURRENT_LVL_ID 0x0000 +#define CURRENT_FRQ_ID 0x0004 + +// COLOR CONTROL ATTRIBUTE IDs +#define CURRENT_SAT_ID 0x0001 +#define CURRENT_X_ID 0x0003 +#define CURRENT_Y_ID 0x0004 +#define COLOR_TEMP_MIR_ID 00007 +#define EN_CURRENT_HUE_ID 0x4000 +#define C_LOOP_ACTIVE_ID 0x4002 +#define C_LOOP_DIR_ID 0x4003 +#define C_LOOP_TIME_ID 0x4004 + +// Clusters EFS data +static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type OOextensionFieldSet; +static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type LCextensionFieldSet; +static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type CCextensionFieldSet; + +static app::Clusters::Scenes::Structs::AttributeValuePair::Type OOPairs[1]; +static app::Clusters::Scenes::Structs::AttributeValuePair::Type LCPairs[2]; +static app::Clusters::Scenes::Structs::AttributeValuePair::Type CCPairs[8]; + +static uint8_t OO_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; +static uint8_t LC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; +static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; + +/// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control +class TestSceneHandler : public scenes::DefaultSceneHandlerImpl +{ +public: + static constexpr uint8_t kMaxValueSize = 4; + static constexpr uint8_t kMaxAvPair = 15; -static const ExtensionFieldsSet onOffEFS1 = ExtensionFieldsSet(0x0006, (uint8_t *) "1", 1); -static const ExtensionFieldsSet levelControlEFS1 = ExtensionFieldsSet(0x0008, (uint8_t *) "511", 3); + TestSceneHandler() = default; + ~TestSceneHandler() override {} -static CHIP_ERROR test_on_off_from_cluster_callback(ExtensionFieldsSet & fields) -{ - ReturnErrorOnFailure(fields = onOffEFS1); - return CHIP_NO_ERROR; -} -static CHIP_ERROR test_on_off_to_cluster_callback(ExtensionFieldsSet & fields) -{ - VerifyOrReturnError(fields == onOffEFS1, CHIP_ERROR_WRITE_FAILED); - return CHIP_NO_ERROR; -} -static CHIP_ERROR test_level_control_from_cluster_callback(ExtensionFieldsSet & fields) -{ - ReturnErrorOnFailure(fields = levelControlEFS1); - return CHIP_NO_ERROR; -} -static CHIP_ERROR test_level_control_to_cluster_callback(ExtensionFieldsSet & fields) + // Default function only checks if endpoint and clusters are valid + bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override + { + bool ret = false; + if (endpoint == TEST_ENDPOINT1) + { + if (cluster == ON_OFF_CID || cluster == LV_CTR_CID) + { + ret = true; + } + } + + if (endpoint == TEST_ENDPOINT2) + { + if (cluster == ON_OFF_CID || cluster == CC_CTR_CID) + { + ret = true; + } + } + + return ret; + } + + /// @brief Simulates save from cluster, data is already in an EFS struct but this isn't mandatory + /// @param endpoint target endpoint + /// @param cluster target cluster + /// @param serialyzedBytes data to serialize into EFS + /// @return success if successfully serialized the data, CHIP_ERROR_INVALID_ARGUMENT if endpoint or cluster not supported + CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialyzedBytes) override + { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + + if (endpoint == TEST_ENDPOINT1) + { + switch (cluster) + { + case ON_OFF_CID: + err = CHIP_NO_ERROR; + memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + serialyzedBytes.reduce_size(15); // Used memory for OnOff TLV + break; + case LV_CTR_CID: + err = CHIP_NO_ERROR; + memcpy(serialyzedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + serialyzedBytes.reduce_size(27); // Used memory for Level Control TLV + break; + default: + break; + } + } + if (endpoint == TEST_ENDPOINT2) + { + switch (cluster) + { + case ON_OFF_CID: + err = CHIP_NO_ERROR; + memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + serialyzedBytes.reduce_size(15); // Used memory for Color Control TLV + break; + case CC_CTR_CID: + err = CHIP_NO_ERROR; + memcpy(serialyzedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + serialyzedBytes.reduce_size(99); // Used memory for Color Control TLV + break; + default: + break; + } + } + return err; + } + + /// @brief Simulates EFS being applied to a scene, here just validates that the data is as expected, no action taken by the + /// "cluster" + /// @param endpoint target endpoint + /// @param cluster target cluster + /// @param serialyzedBytes Data from nvm + /// @param timeMs transition time in ms + /// @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise + CHIP_ERROR + ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialyzedBytes, TransitionTimeMs timeMs) override + { + CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; + + // Takes values from cluster in Endpoint 1 + if (endpoint == TEST_ENDPOINT1) + { + switch (cluster) + { + case ON_OFF_CID: + if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + case LV_CTR_CID: + if (!memcmp(serialyzedBytes.data(), LC_buffer, serialyzedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + default: + break; + } + } + + // Takes values from cluster in Endpoint 2 + if (endpoint == TEST_ENDPOINT2) + { + switch (cluster) + { + case ON_OFF_CID: + if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + case CC_CTR_CID: + if (!memcmp(serialyzedBytes.data(), CC_buffer, serialyzedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + default: + break; + } + } + + return CHIP_NO_ERROR; + } +}; + +static TestSceneHandler sHandler; + +CHIP_ERROR scene_handler_test(SceneTableImpl * provider) { - VerifyOrReturnError(fields == levelControlEFS1, CHIP_ERROR_WRITE_FAILED); + ClusterId tempCluster = 0; + + app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; + app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldSetIn; + app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; + + TLV::TLVReader reader; + TLV::TLVWriter writer; + TLV::TLVType outer; + TLV::TLVType outerRead; + + static const uint8_t OO_av_payload[1] = { 0x01 }; + static const uint8_t LC_av_payload[2][2] = { { 0x40, 0x00 }, { 0x01, 0xF0 } }; + static const uint8_t CC_av_payload[8][2] = { { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, + { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 } }; + + OOPairs[0].attributeID.SetValue(ON_OFF_ID); + OOPairs[0].attributeValue = OO_av_payload; + + LCPairs[0].attributeID.SetValue(CURRENT_LVL_ID); + LCPairs[0].attributeValue = LC_av_payload[0]; + LCPairs[0].attributeValue.reduce_size(1); + LCPairs[1].attributeID.SetValue(CURRENT_FRQ_ID); + LCPairs[1].attributeValue = LC_av_payload[1]; + + CCPairs[0].attributeID.SetValue(CURRENT_SAT_ID); + CCPairs[0].attributeValue = CC_av_payload[0]; + CCPairs[0].attributeValue.reduce_size(1); + CCPairs[1].attributeID.SetValue(CURRENT_X_ID); + CCPairs[1].attributeValue = CC_av_payload[1]; + CCPairs[2].attributeID.SetValue(CURRENT_Y_ID); + CCPairs[2].attributeValue = CC_av_payload[2]; + CCPairs[3].attributeID.SetValue(COLOR_TEMP_MIR_ID); + CCPairs[3].attributeValue = CC_av_payload[3]; + CCPairs[4].attributeID.SetValue(EN_CURRENT_HUE_ID); + CCPairs[4].attributeValue = CC_av_payload[4]; + CCPairs[5].attributeID.SetValue(C_LOOP_ACTIVE_ID); + CCPairs[5].attributeValue = CC_av_payload[5]; + CCPairs[5].attributeValue.reduce_size(1); + CCPairs[6].attributeID.SetValue(C_LOOP_DIR_ID); + CCPairs[6].attributeValue = CC_av_payload[6]; + CCPairs[6].attributeValue.reduce_size(1); + CCPairs[7].attributeID.SetValue(C_LOOP_TIME_ID); + CCPairs[7].attributeValue = CC_av_payload[7]; + + // Initialize Extension Field sets as if they were received by add commands + OOextensionFieldSet.clusterID = ON_OFF_CID; + OOextensionFieldSet.attributeValueList = OOPairs; + LCextensionFieldSet.clusterID = LV_CTR_CID; + LCextensionFieldSet.attributeValueList = LCPairs; + CCextensionFieldSet.clusterID = CC_CTR_CID; + CCextensionFieldSet.attributeValueList = CCPairs; + + ByteSpan OO_list(OO_buffer); + ByteSpan LC_list(LC_buffer); + ByteSpan CC_list(CC_buffer); + + uint8_t buffer[scenes::kMaxFieldsPerCluster] = { 0 }; + MutableByteSpan buff_span(buffer); + + // Serialize Extension Field sets as if they were recovered from memory + writer.Init(OO_buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + ReturnErrorOnFailure(app::DataModel::Encode( + writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + OOextensionFieldSet.attributeValueList)); + writer.EndContainer(outer); + + writer.Init(LC_buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + ReturnErrorOnFailure(app::DataModel::Encode( + writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + LCextensionFieldSet.attributeValueList)); + writer.EndContainer(outer); + + writer.Init(CC_buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + ReturnErrorOnFailure(app::DataModel::Encode( + writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + CCextensionFieldSet.attributeValueList)); + writer.EndContainer(outer); + + ReturnErrorOnFailure(provider->RegisterHandler(&sHandler)); + + // Setup the On Off Extension field set in the expected state from a command + reader.Init(OO_list); + extensionFieldSetIn.clusterID = ON_OFF_CID; + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.EnterContainer(outerRead)); + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); + ReturnErrorOnFailure(reader.ExitContainer(outerRead)); + + ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); + + // Verify the handler extracted buffer matches the initial field sets + VerifyOrReturnError(0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(tempCluster == ON_OFF_CID, CHIP_ERROR_WRITE_FAILED); + memset(buffer, 0, buff_span.size()); + + // Setup the Level Control Extension field set in the expected state from a command + reader.Init(LC_list); + extensionFieldSetIn.clusterID = LV_CTR_CID; + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.EnterContainer(outerRead)); + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); + ReturnErrorOnFailure(reader.ExitContainer(outerRead)); + + ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); + + // Verify the handler extracted buffer matches the initial field sets + VerifyOrReturnError(0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(tempCluster == LV_CTR_CID, CHIP_ERROR_WRITE_FAILED); + memset(buffer, 0, buff_span.size()); + + // Setup the Color control Extension field set in the expected state from a command + reader.Init(CC_list); + extensionFieldSetIn.clusterID = CC_CTR_CID; + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.EnterContainer(outerRead)); + ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); + ReturnErrorOnFailure(reader.ExitContainer(outerRead)); + + ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT2, tempCluster, buff_span, extensionFieldSetIn)); + + // Verify the handler extracted buffer matches the initial field sets + VerifyOrReturnError(0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); + VerifyOrReturnError(tempCluster == CC_CTR_CID, CHIP_ERROR_WRITE_FAILED); + memset(buffer, 0, buff_span.size()); + + // Verify Deserializing is properly filling out output extension field set for on off + ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT1, ON_OFF_CID, OO_list, extensionFieldSetOut)); + + // Verify Encoding the Extension field set returns the same data as + writer.Init(buff_span); + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(app::DataModel::Encode( + writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + extensionFieldSetOut.attributeValueList)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + VerifyOrReturnError(0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); + memset(buffer, 0, buff_span.size()); + + // Verify Deserializing is properly filling out output extension field set for level control + ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT1, LV_CTR_CID, LC_list, extensionFieldSetOut)); + + // Verify Encoding the Extension field set returns the same data as + writer.Init(buff_span); + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(app::DataModel::Encode( + writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + extensionFieldSetOut.attributeValueList)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + VerifyOrReturnError(0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); + memset(buffer, 0, buff_span.size()); + + // Verify Deserializing is properly filling out output extension field set for color control + ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT2, CC_CTR_CID, CC_list, extensionFieldSetOut)); + + // Verify Encoding the Extension field set returns the same data as + writer.Init(buff_span); + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); + ReturnErrorOnFailure(app::DataModel::Encode( + writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + extensionFieldSetOut.attributeValueList)); + ReturnErrorOnFailure(writer.EndContainer(outer)); + VerifyOrReturnError(0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); + memset(buffer, 0, buff_span.size()); + return CHIP_NO_ERROR; -} +}; CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry) { - CHIP_ERROR err = CHIP_NO_ERROR; SceneTableEntry temp; LogErrorOnFailure(provider->SetSceneTableEntry(fabric_index, entry)); LogErrorOnFailure(provider->GetSceneTableEntry(fabric_index, entry.mStorageId, temp)); VerifyOrReturnError(temp.mStorageId == entry.mStorageId, CHIP_ERROR_WRITE_FAILED); VerifyOrReturnError(temp.mStorageData == entry.mStorageData, CHIP_ERROR_WRITE_FAILED); + LogErrorOnFailure(provider->SceneApplyEFS(fabric_index, temp.mStorageId)); - return err; + return CHIP_NO_ERROR; } CHIP_ERROR scene_iterator_test(SceneTableImpl * provider, FabricIndex fabric_index, const SceneTableEntry & entry1, const SceneTableEntry & entry2, const SceneTableEntry & entry3) { - CHIP_ERROR err = CHIP_NO_ERROR; SceneTableEntry temp; auto * iterator = provider->IterateSceneEntry(fabric_index); @@ -94,13 +425,12 @@ CHIP_ERROR scene_iterator_test(SceneTableImpl * provider, FabricIndex fabric_ind iterator->Release(); } - return err; + return CHIP_NO_ERROR; } CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry1, SceneTableEntry & entry2, SceneTableEntry & entry3) { - CHIP_ERROR err = CHIP_NO_ERROR; SceneTableEntry temp; LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry2.mStorageId)); @@ -125,16 +455,16 @@ CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); iterator->Release(); - return err; + return CHIP_NO_ERROR; } CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) { CHIP_ERROR err = CHIP_NO_ERROR; // Scene storage ID - static const SceneStorageId sceneId1(1, 0xAA, 0x101); - static const SceneStorageId sceneId2(1, 0xBB, 0x00); - static const SceneStorageId sceneId3(1, 0xCC, 0x102); + static const SceneStorageId sceneId1(TEST_ENDPOINT1, 0xAA, 0x101); + static const SceneStorageId sceneId2(TEST_ENDPOINT1, 0xBB, 0x00); + static const SceneStorageId sceneId3(TEST_ENDPOINT2, 0xCC, 0x102); // Scene data static const SceneData sceneData1(CharSpan("Scene #1", sizeof("Scene #1"))); @@ -146,21 +476,21 @@ CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) SceneTableEntry scene2(sceneId2, sceneData2); SceneTableEntry scene3(sceneId3, sceneData3); - err = provider->registerHandler(onOffEFS1.mID, &test_on_off_from_cluster_callback, &test_on_off_to_cluster_callback); + LogErrorOnFailure(scene_handler_test(provider)); + + err = provider->SceneSaveEFS(scene1, ON_OFF_CID); LogErrorOnFailure(err); - err = provider->registerHandler(levelControlEFS1.mID, &test_level_control_from_cluster_callback, - &test_level_control_to_cluster_callback); + err = provider->SceneSaveEFS(scene1, LV_CTR_CID); LogErrorOnFailure(err); - err = provider->EFSValuesFromCluster(scene1.mStorageData.mExtensionFieldsSets); + + err = provider->SceneSaveEFS(scene3, ON_OFF_CID); + LogErrorOnFailure(err); + err = provider->SceneSaveEFS(scene3, CC_CTR_CID); LogErrorOnFailure(err); // Tests err = scene_store_test(provider, fabric_index, scene1); LogErrorOnFailure(err); - - err = provider->EFSValuesToCluster(scene1.mStorageData.mExtensionFieldsSets); - LogErrorOnFailure(err); - err = scene_store_test(provider, fabric_index, scene2); LogErrorOnFailure(err); err = scene_store_test(provider, fabric_index, scene3); From 0ddafd17da2cf986196a75e5f47601899295f927 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 1 Mar 2023 00:35:46 +0000 Subject: [PATCH 30/79] Restyled by whitespace --- src/lib/core/CHIPConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 35e01fa5fda125..e549e67924207d 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1440,4 +1440,4 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; /** * @} - */ \ No newline at end of file + */ From e9c9bb850d7cbdb9e974b51dee497ef4157c9705 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 1 Mar 2023 00:35:47 +0000 Subject: [PATCH 31/79] Restyled by clang-format --- src/app/clusters/scenes/SceneTable.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index a1b5bf55e93a38..98c7548694e8c7 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -306,7 +306,7 @@ class SceneTable virtual ~SceneTable() = default; // Not copyable - SceneTable(const SceneTable &) = delete; + SceneTable(const SceneTable &) = delete; SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; From 1e615ec4a9e2e9c8fca573a9f4953c7fb5a105b3 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 1 Mar 2023 16:20:09 -0500 Subject: [PATCH 32/79] Refactored for size conversion error --- src/app/clusters/scenes/SceneTableImpl.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index cfb3f0306ac82e..02c2ebf11918df 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -438,17 +438,17 @@ CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) return err; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) +CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t pos) { - VerifyOrReturnError(position < kMaxSceneHandlers, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnValue(!this->HandlerListEmpty() && !(this->mHandlers[position] == nullptr), CHIP_NO_ERROR); + VerifyOrReturnError(pos < kMaxSceneHandlers, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnValue(!this->HandlerListEmpty() && !(this->mHandlers[pos] == nullptr), CHIP_NO_ERROR); - uint8_t next = position + 1; - uint8_t moveNum = kMaxSceneHandlers - next; + uint8_t nextPos = pos++; + uint8_t moveNum = kMaxSceneHandlers - nextPos; // TODO: Implement general array management methods // Compress array after removal - memmove(&this->mHandlers[position], &this->mHandlers[next], sizeof(SceneHandler *) * moveNum); + memmove(&this->mHandlers[pos], &this->mHandlers[nextPos], sizeof(SceneHandler *) * moveNum); this->handlerNum--; // Clear last occupied position From 2bbbf5b8528d01961c6e24771525e0002a55d6de Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Thu, 2 Mar 2023 16:34:08 -0500 Subject: [PATCH 33/79] Static cast added for Wconversion errors --- src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp | 6 +++--- src/app/clusters/scenes/SceneTableImpl.cpp | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index 27038353dcec80..7c85bc7fa8d0ec 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -129,12 +129,12 @@ CHIP_ERROR ExtensionFieldsSetsImpl::RemoveFieldAtPosition(uint8_t position) VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnValue(!this->IsEmpty() && !this->mEFS[position].IsEmpty(), CHIP_NO_ERROR); - uint8_t next = position + 1; - uint8_t moveNum = kMaxClusterPerScenes - next; + uint8_t nextPos = position++; + uint8_t moveNum = static_cast(kMaxClusterPerScenes - nextPos); // TODO: Implement general array management methods // Compress array after removal - memmove(&this->mEFS[position], &this->mEFS[next], sizeof(ExtensionFieldsSet) * moveNum); + memmove(&this->mEFS[position], &this->mEFS[nextPos], sizeof(ExtensionFieldsSet) * moveNum); this->mFieldNum--; // Clear last occupied position diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 02c2ebf11918df..0c4ac6b1da2c7d 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -438,17 +438,17 @@ CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) return err; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t pos) +CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) { - VerifyOrReturnError(pos < kMaxSceneHandlers, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnValue(!this->HandlerListEmpty() && !(this->mHandlers[pos] == nullptr), CHIP_NO_ERROR); + VerifyOrReturnError(position < kMaxSceneHandlers, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnValue(!this->HandlerListEmpty() && !(this->mHandlers[position] == nullptr), CHIP_NO_ERROR); - uint8_t nextPos = pos++; - uint8_t moveNum = kMaxSceneHandlers - nextPos; + uint8_t nextPos = position++; + uint8_t moveNum = static_cast(kMaxSceneHandlers - nextPos); // TODO: Implement general array management methods // Compress array after removal - memmove(&this->mHandlers[pos], &this->mHandlers[nextPos], sizeof(SceneHandler *) * moveNum); + memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(SceneHandler *) * moveNum); this->handlerNum--; // Clear last occupied position From ba42a26f851136126c3c3b3947166839cb23b18a Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Thu, 2 Mar 2023 17:26:41 -0500 Subject: [PATCH 34/79] Unused variable removal in TestSceneTable.cpp --- src/app/tests/TestSceneTable.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index f09059cca056da..527fb349bc8a6d 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -116,9 +116,6 @@ static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { public: - static constexpr uint8_t kMaxValueSize = 4; - static constexpr uint8_t kMaxAvPair = 15; - TestSceneHandler() = default; ~TestSceneHandler() override {} From 4578c9b9d68a086fb78ae11f44514abf143aa2a7 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Sat, 4 Mar 2023 15:56:29 -0500 Subject: [PATCH 35/79] Fixed suspicious usage of sizeof, rewrote function comments, implemented test for sceneHandler registration --- .../scenes/ExtensionFieldsSetsImpl.cpp | 2 +- src/app/clusters/scenes/SceneTable.h | 87 ++++++++--- src/app/clusters/scenes/SceneTableImpl.cpp | 31 ++-- src/app/clusters/scenes/SceneTableImpl.h | 43 ++---- src/app/tests/TestSceneTable.cpp | 143 +++++++++++++----- src/lib/support/TestSceneTable.h | 77 ++++++---- 6 files changed, 240 insertions(+), 143 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp index 7c85bc7fa8d0ec..3e9a2232ad4660 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp @@ -129,7 +129,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::RemoveFieldAtPosition(uint8_t position) VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnValue(!this->IsEmpty() && !this->mEFS[position].IsEmpty(), CHIP_NO_ERROR); - uint8_t nextPos = position++; + uint8_t nextPos = static_cast(position + 1); uint8_t moveNum = static_cast(kMaxClusterPerScenes - nextPos); // TODO: Implement general array management methods diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 98c7548694e8c7..be4688a9010126 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -56,40 +56,52 @@ class SceneHandler SceneHandler(){}; virtual ~SceneHandler() = default; + /// @brief Gets the list of supported clusters for an endpoint + /// @param endpoint target endpoint + /// @param clusterBuffer Buffer to hold the supported cluster IDs, cannot hold more than + /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES + virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) = 0; + + /// @brief Returns whether or not a cluster is supported on an endpoint + /// @param endpoint Target Endpoint ID + /// @param cluster Target Cluster ID + /// @return true if supported, false if not supported virtual bool SupportsCluster(EndpointId endpoint, ClusterId cluster) = 0; /// @brief From command AddScene, allows handler to filter through clusters in command to serialize only the supported ones. /// @param endpoint Endpoint ID /// @param cluster Cluster ID to fetch from command - /// @param serialysedBytes Buffer for ExtensionFieldSet in command + /// @param serialisedBytes Buffer for ExtensionFieldSet in command /// @param extensionFieldSet ExtensionFieldSets provided by the AddScene Command - /// @return - virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialysedBytes, + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) = 0; - /// @brief From command SaveScene, retrieves ExtensionField from nvm - /// @param endpoint - /// @param cluster - /// @param serialysedBytes - /// @return - virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialysedBytes) = 0; + /// @brief From command StoreScene, retrieves ExtensionField from nvm, it is the functions responsability to resize the mutable + /// span if necessary, a number of byte equal to the span will be stored in memory + /// @param endpoint Target Endpoint + /// @param cluster Target Cluster + /// @param serialisedBytes Output buffer, data needs to be writen in there and size adjusted if smaller than + /// kMaxFieldsPerCluster + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) = 0; /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a command object /// @param endpoint Endpoint ID - /// @param cluster Cluster ID to set in command - /// @param serialysedBytes ExtensionFieldSet stored in NVM + /// @param cluster Cluster ID to save + /// @param serialisedBytes ExtensionFieldSet stored in NVM /// @param extensionFieldSet ExtensionFieldSet in command format - /// @return - virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialysedBytes, + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; /// @brief From stored scene (e.g RecallScene), applies EFS values to cluster at transition time /// @param endpoint Endpoint ID /// @param cluster Cluster ID - /// @param serialysedBytes ExtensionFieldSet stored in NVM + /// @param serialisedBytes ExtensionFieldSet stored in NVM /// @param timeMs Transition time in ms to apply the scene - /// @return - virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialysedBytes, TransitionTimeMs timeMs) = 0; + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) = 0; }; class SceneTable @@ -318,21 +330,50 @@ class SceneTable virtual CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) = 0; virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) = 0; - // Iterators - using SceneEntryIterator = CommonIterator; + // SceneHandlers + virtual CHIP_ERROR RegisterHandler(SceneHandler * handler) = 0; + virtual CHIP_ERROR UnregisterHandler(uint8_t position) = 0; - virtual SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) = 0; + // Extension field sets operation + virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; + virtual CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) = 0; // Fabrics virtual CHIP_ERROR RemoveFabric(FabricIndex fabric_index) = 0; + // Iterators + using SceneEntryIterator = CommonIterator; + + virtual SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) = 0; + // Handlers - SceneHandler * mHandlers[CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES] = { nullptr }; - uint8_t handlerNum = 0; + virtual bool HandlerListEmpty() { return (handlerNum == 0); } + virtual bool HandlerListFull() { return (handlerNum >= kMaxSceneHandlers); } + virtual uint8_t GetHandlerNum() { return this->handlerNum; } -protected: - const uint8_t mMaxScenePerFabric = kMaxScenePerFabric; + SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; + uint8_t handlerNum = 0; }; +/** + * Instance getter for the global SceneTable. + * + * Callers have to externally synchronize usage of this function. + * + * @return The global Scene Table + */ +SceneTable * GetSceneTable(); + +/** + * Instance setter for the global Scene Table. + * + * Callers have to externally synchronize usage of this function. + * + * The `provider` can be set to nullptr if the owner is done with it fully. + * + * @param[in] provider pointer to the Scene Table global instance to use + */ +void SetSceneTable(SceneTable * provider); + } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 0c4ac6b1da2c7d..df68536f763265 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -443,12 +443,12 @@ CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) VerifyOrReturnError(position < kMaxSceneHandlers, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnValue(!this->HandlerListEmpty() && !(this->mHandlers[position] == nullptr), CHIP_NO_ERROR); - uint8_t nextPos = position++; + uint8_t nextPos = static_cast(position + 1); uint8_t moveNum = static_cast(kMaxSceneHandlers - nextPos); // TODO: Implement general array management methods // Compress array after removal - memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(SceneHandler *) * moveNum); + memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(this->mHandlers[position]) * moveNum); this->handlerNum--; // Clear last occupied position @@ -457,20 +457,27 @@ CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) return CHIP_NO_ERROR; } -CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene, clusterId cluster) +CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) { - ExtensionFieldsSet EFS; - MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldsPerCluster); if (!this->HandlerListEmpty()) { for (uint8_t i = 0; i < this->handlerNum; i++) { + clusterId cArray[kMaxClusterPerScenes]; + Span cSpan(cArray); if (this->mHandlers[i] != nullptr) { - EFS.mID = cluster; - ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, cluster, EFSSpan)); - EFS.mUsedBytes = (uint8_t) EFSSpan.size(); - ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldsSets.InsertFieldSet(EFS)); + this->mHandlers[i]->GetSupportedClusters(scene.mStorageId.mEndpointId, cSpan); + for (uint8_t j = 0; j < cSpan.size(); j++) + { + ExtensionFieldsSet EFS; + MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldsPerCluster); + + EFS.mID = cArray[j]; + ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); + EFS.mUsedBytes = (uint8_t) EFSSpan.size(); + ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldsSets.InsertFieldSet(EFS)); + } } } } @@ -585,16 +592,16 @@ void DefaultSceneTableImpl::SceneEntryIteratorImpl::Release() namespace { -DefaultSceneTableImpl * gSceneTable = nullptr; +SceneTable * gSceneTable = nullptr; } // namespace -DefaultSceneTableImpl * GetSceneTable() +SceneTable * GetSceneTable() { return gSceneTable; } -void SetSceneTable(DefaultSceneTableImpl * provider) +void SetSceneTable(SceneTable * provider) { gSceneTable = provider; } diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index aac47870632db4..42576779900d29 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -44,10 +44,10 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @brief Function to serialize data from an add scene command, assume the incoming extensionFieldSet is initialized /// @param endpoint Target Endpoint /// @param cluster Cluster in the Extension field set, filled by the function - /// @param serialyzedBytes Mutable Byte span to hold EFS data from command + /// @param serialisedBytes Mutable Byte span to hold EFS data from command /// @param extensionFieldSet Extension field set from commmand, pre initialized /// @return CHIP_NO_ERROR if success, specific CHIP_ERROR otherwise - virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialyzedBytes, + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) override { app::DataModel::List attributeValueList; @@ -88,7 +88,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler attributeValueList = mAVPairs; attributeValueList.reduce_size(pairCount); - writer.Init(serialyzedBytes); + writer.Init(serialisedBytes); ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); ReturnErrorOnFailure(app::DataModel::Encode( writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), @@ -101,9 +101,9 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @brief Simulates taking data from nvm and loading it in a command object if the cluster is supported by the endpoint /// @param endpoint target endpoint /// @param cluster target cluster - /// @param serialyzedBytes data to deserialize into EFS + /// @param serialisedBytes data to deserialize into EFS /// @return CHIP_NO_ERROR if Extension Field Set was successfully populated, specific CHIP_ERROR otherwise - virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialyzedBytes, + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) override { app::DataModel::DecodableList attributeValueList; @@ -117,7 +117,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler VerifyOrReturnError(SupportsCluster(endpoint, cluster), CHIP_ERROR_INVALID_ARGUMENT); extensionFieldSet.clusterID = cluster; - reader.Init(serialyzedBytes); + reader.Init(serialisedBytes); ReturnErrorOnFailure(reader.Next()); ReturnErrorOnFailure(reader.EnterContainer(outer)); ReturnErrorOnFailure(reader.Next()); @@ -183,12 +183,12 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) override; // SceneHandlers - CHIP_ERROR RegisterHandler(SceneHandler * handler); - CHIP_ERROR UnregisterHandler(uint8_t position); + CHIP_ERROR RegisterHandler(SceneHandler * handler) override; + CHIP_ERROR UnregisterHandler(uint8_t position) override; // Extension field sets operation - CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene, clusterId cluster); - CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id); + CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) override; + CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) override; // Fabrics CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; @@ -196,10 +196,6 @@ class DefaultSceneTableImpl : public SceneTable // Iterators SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; - bool HandlerListEmpty() { return (handlerNum == 0); } - bool HandlerListFull() { return (handlerNum >= CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES); } - uint8_t GetHandlerNum() { return this->handlerNum; } - protected: class SceneEntryIteratorImpl : public SceneEntryIterator { @@ -222,24 +218,5 @@ class DefaultSceneTableImpl : public SceneTable ObjectPool mSceneEntryIterators; }; // class DefaultSceneTableImpl -/** - * Instance getter for the global SceneTable. - * - * Callers have to externally synchronize usage of this function. - * - * @return The global Scene Table - */ -DefaultSceneTableImpl * GetSceneTable(); - -/** - * Instance setter for the global Scene Table. - * - * Callers have to externally synchronize usage of this function. - * - * The `provider` can be set to nullptr if the owner is done with it fully. - * - * @param[in] provider pointer to the Scene Table global instance to use - */ -void SetSceneTable(DefaultSceneTableImpl * provider); } // namespace scenes } // namespace chip diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 527fb349bc8a6d..4f0813f9d9cb82 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -24,6 +24,8 @@ #include using namespace chip; + +using SceneTable = scenes::SceneTable; using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; using SceneTableImpl = scenes::DefaultSceneTableImpl; using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; @@ -119,6 +121,24 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl TestSceneHandler() = default; ~TestSceneHandler() override {} + // Fills in cluster buffer and adjusts its size to lower than the maximum number of cluster per scenes + virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) override + { + ClusterId * buffer = clusterBuffer.data(); + if (endpoint == TEST_ENDPOINT1) + { + buffer[0] = ON_OFF_CID; + buffer[1] = LV_CTR_CID; + clusterBuffer.reduce_size(2); + } + else if (endpoint == TEST_ENDPOINT2) + { + buffer[0] = ON_OFF_CID; + buffer[1] = CC_CTR_CID; + clusterBuffer.reduce_size(2); + } + } + // Default function only checks if endpoint and clusters are valid bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override { @@ -145,9 +165,9 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// @brief Simulates save from cluster, data is already in an EFS struct but this isn't mandatory /// @param endpoint target endpoint /// @param cluster target cluster - /// @param serialyzedBytes data to serialize into EFS + /// @param serialisedBytes data to serialize into EFS /// @return success if successfully serialized the data, CHIP_ERROR_INVALID_ARGUMENT if endpoint or cluster not supported - CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialyzedBytes) override + CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -157,13 +177,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(15); // Used memory for OnOff TLV + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(15); // Used memory for OnOff TLV break; case LV_CTR_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(27); // Used memory for Level Control TLV + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(27); // Used memory for Level Control TLV break; default: break; @@ -175,13 +195,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(15); // Used memory for Color Control TLV + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(15); // Used memory for OnOff TLV break; case CC_CTR_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(99); // Used memory for Color Control TLV + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(99); // Used memory for Color Control TLV break; default: break; @@ -194,11 +214,11 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// "cluster" /// @param endpoint target endpoint /// @param cluster target cluster - /// @param serialyzedBytes Data from nvm + /// @param serialisedBytes Data from nvm /// @param timeMs transition time in ms /// @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise CHIP_ERROR - ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialyzedBytes, TransitionTimeMs timeMs) override + ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -208,13 +228,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl switch (cluster) { case ON_OFF_CID: - if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; case LV_CTR_CID: - if (!memcmp(serialyzedBytes.data(), LC_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } @@ -230,13 +250,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl switch (cluster) { case ON_OFF_CID: - if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; case CC_CTR_CID: - if (!memcmp(serialyzedBytes.data(), CC_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } @@ -254,16 +274,61 @@ static chip::TestPersistentStorageDelegate testStorage; static SceneTableImpl sSceneTable; static TestSceneHandler sHandler; -void ResetSceneTable(SceneTableImpl * sceneTable) +void ResetSceneTable(SceneTable * sceneTable) { sceneTable->RemoveFabric(kFabric1); sceneTable->RemoveFabric(kFabric2); } +void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) +{ + SceneTable * sceneTable = scenes::GetSceneTable(); + TestSceneHandler tmpHandler[scenes::kMaxSceneHandlers]; + + for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) + { + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == i); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[i])); + } + + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == scenes::kMaxSceneHandlers); + // Removal at begining + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(0)); + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == static_cast(scenes::kMaxSceneHandlers - 1)); + // Confirm array was compressed and last position is now null + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + + // Removal at the middle + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(3)); + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == static_cast(scenes::kMaxSceneHandlers - 2)); + // Confirm array was compressed and last position is now null + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 2]); + + // Removal at the middle + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(scenes::kMaxSceneHandlers - 3)); + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == static_cast(scenes::kMaxSceneHandlers - 3)); + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 3]); + + // Emptying Handler array + for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) + { + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(0)); + } + + // Verify the handler num has been updated properly + NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == 0); + + // Verify all array is empty + for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) + { + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[i]); + } +} + void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); - ClusterId tempCluster = 0; + SceneTable * sceneTable = chip::scenes::GetSceneTable(); + ClusterId tempCluster = 0; app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldSetIn; @@ -409,7 +474,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Verify Deserializing is properly filling out output extension field set for on off NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT1, ON_OFF_CID, OO_list, extensionFieldSetOut)); - // Verify Encoding the Extension field set returns the same data as + // Verify Encoding the Extension field set returns the same data as the one serialized for on off previously writer.Init(buff_span); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); NL_TEST_ASSERT(aSuite, @@ -425,7 +490,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Verify Deserializing is properly filling out output extension field set for level control NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT1, LV_CTR_CID, LC_list, extensionFieldSetOut)); - // Verify Encoding the Extension field set returns the same data as + // Verify Encoding the Extension field set returns the same data as the one serialized for level control previously writer.Init(buff_span); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); NL_TEST_ASSERT(aSuite, @@ -441,7 +506,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Verify Deserializing is properly filling out output extension field set for color control NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT2, CC_CTR_CID, CC_list, extensionFieldSetOut)); - // Verify Encoding the Extension field set returns the same data as + // Verify Encoding the Extension field set returns the same data as the one serialized for color control previously writer.Init(buff_span); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); NL_TEST_ASSERT(aSuite, @@ -457,31 +522,23 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) void TestStoreScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); // Reset test ResetSceneTable(sceneTable); // Populate scene1's EFS (Endpoint1) - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene1, ON_OFF_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene1, LV_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene1, CC_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene1)); // Populate scene2's EFS (Endpoint1) - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene2, ON_OFF_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene2, LV_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene2, CC_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene2)); // Populate scene3's EFS (Endpoint2) - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3, ON_OFF_CID)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene3, LV_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3, CC_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3)); // Populate scene3's EFS (Endpoint2) - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4, ON_OFF_CID)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == sceneTable->SceneSaveEFS(scene4, LV_CTR_CID)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4, CC_CTR_CID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4)); SceneTableEntry scene; @@ -495,7 +552,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene7)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene8)); - // Too many scenes 1 fabric + // Too many scenes for 1 fabric NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_LIST_LENGTH == sceneTable->SetSceneTableEntry(kFabric1, scene9)); // Not Found @@ -530,7 +587,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -554,7 +611,7 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) void TestIterateScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -590,7 +647,7 @@ void TestIterateScenes(nlTestSuite * aSuite, void * aContext) void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -681,7 +738,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) void TestFabricScenes(nlTestSuite * aSuite, void * aContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); NL_TEST_ASSERT(aSuite, sceneTable); // Reset test @@ -757,7 +814,7 @@ int TestSetup(void * inContext) */ int TestTeardown(void * inContext) { - SceneTableImpl * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = chip::scenes::GetSceneTable(); if (nullptr != sceneTable) { sceneTable->Finish(); @@ -767,12 +824,14 @@ int TestTeardown(void * inContext) } int TestSceneTable() { - static nlTest sTests[] = { NL_TEST_DEF("TestStoreScenes", TestHandlerFunctions), + static nlTest sTests[] = { NL_TEST_DEF("TestHandlerRegistration", TestHandlerRegistration), + NL_TEST_DEF("TestHandlerFunctions", TestHandlerFunctions), NL_TEST_DEF("TestStoreScenes", TestStoreScenes), NL_TEST_DEF("TestOverwriteScenes", TestOverwriteScenes), NL_TEST_DEF("TestIterateScenes", TestIterateScenes), NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), NL_TEST_DEF("TestFabricScenes", TestFabricScenes), + NL_TEST_SENTINEL() }; nlTestSuite theSuite = { diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h index a8706eaaf0638b..26bfb84bd55e62 100644 --- a/src/lib/support/TestSceneTable.h +++ b/src/lib/support/TestSceneTable.h @@ -26,6 +26,7 @@ namespace SceneTesting { using FabricIndex = chip::FabricIndex; using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; +using SceneTable = chip::scenes::SceneTable; using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; @@ -72,12 +73,27 @@ static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { public: - static constexpr uint8_t kMaxValueSize = 4; - static constexpr uint8_t kMaxAvPair = 15; - TestSceneHandler() = default; ~TestSceneHandler() override {} + // Fills in cluster buffer and adjusts its size to lower than the maximum number of cluster per scenes + virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) override + { + ClusterId * buffer = clusterBuffer.data(); + if (endpoint == TEST_ENDPOINT1) + { + buffer[0] = ON_OFF_CID; + buffer[1] = LV_CTR_CID; + clusterBuffer.reduce_size(2); + } + else if (endpoint == TEST_ENDPOINT2) + { + buffer[0] = ON_OFF_CID; + buffer[1] = CC_CTR_CID; + clusterBuffer.reduce_size(2); + } + } + // Default function only checks if endpoint and clusters are valid bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override { @@ -104,9 +120,9 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// @brief Simulates save from cluster, data is already in an EFS struct but this isn't mandatory /// @param endpoint target endpoint /// @param cluster target cluster - /// @param serialyzedBytes data to serialize into EFS + /// @param serialisedBytes data to serialize into EFS /// @return success if successfully serialized the data, CHIP_ERROR_INVALID_ARGUMENT if endpoint or cluster not supported - CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialyzedBytes) override + CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -116,13 +132,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(15); // Used memory for OnOff TLV + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(15); // Used memory for OnOff TLV break; case LV_CTR_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(27); // Used memory for Level Control TLV + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(27); // Used memory for Level Control TLV break; default: break; @@ -134,13 +150,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(15); // Used memory for Color Control TLV + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(15); // Used memory for OnOff TLV break; case CC_CTR_CID: err = CHIP_NO_ERROR; - memcpy(serialyzedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); - serialyzedBytes.reduce_size(99); // Used memory for Color Control TLV + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + serialisedBytes.reduce_size(99); // Used memory for Color Control TLV break; default: break; @@ -153,11 +169,11 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// "cluster" /// @param endpoint target endpoint /// @param cluster target cluster - /// @param serialyzedBytes Data from nvm + /// @param serialisedBytes Data from nvm /// @param timeMs transition time in ms /// @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise CHIP_ERROR - ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialyzedBytes, TransitionTimeMs timeMs) override + ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -167,13 +183,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl switch (cluster) { case ON_OFF_CID: - if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; case LV_CTR_CID: - if (!memcmp(serialyzedBytes.data(), LC_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } @@ -189,13 +205,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl switch (cluster) { case ON_OFF_CID: - if (!memcmp(serialyzedBytes.data(), OO_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; case CC_CTR_CID: - if (!memcmp(serialyzedBytes.data(), CC_buffer, serialyzedBytes.size())) + if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } @@ -211,7 +227,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl static TestSceneHandler sHandler; -CHIP_ERROR scene_handler_test(SceneTableImpl * provider) +CHIP_ERROR scene_handler_test(SceneTable * provider) { ClusterId tempCluster = 0; @@ -387,7 +403,7 @@ CHIP_ERROR scene_handler_test(SceneTableImpl * provider) return CHIP_NO_ERROR; }; -CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry) +CHIP_ERROR scene_store_test(SceneTable * provider, FabricIndex fabric_index, SceneTableEntry & entry) { SceneTableEntry temp; @@ -400,7 +416,7 @@ CHIP_ERROR scene_store_test(SceneTableImpl * provider, FabricIndex fabric_index, return CHIP_NO_ERROR; } -CHIP_ERROR scene_iterator_test(SceneTableImpl * provider, FabricIndex fabric_index, const SceneTableEntry & entry1, +CHIP_ERROR scene_iterator_test(SceneTable * provider, FabricIndex fabric_index, const SceneTableEntry & entry1, const SceneTableEntry & entry2, const SceneTableEntry & entry3) { SceneTableEntry temp; @@ -428,8 +444,8 @@ CHIP_ERROR scene_iterator_test(SceneTableImpl * provider, FabricIndex fabric_ind return CHIP_NO_ERROR; } -CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index, SceneTableEntry & entry1, - SceneTableEntry & entry2, SceneTableEntry & entry3) +CHIP_ERROR scene_remove_test(SceneTable * provider, FabricIndex fabric_index, SceneTableEntry & entry1, SceneTableEntry & entry2, + SceneTableEntry & entry3) { SceneTableEntry temp; @@ -458,7 +474,7 @@ CHIP_ERROR scene_remove_test(SceneTableImpl * provider, FabricIndex fabric_index return CHIP_NO_ERROR; } -CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) +CHIP_ERROR TestSceneData(SceneTable * provider, FabricIndex fabric_index) { CHIP_ERROR err = CHIP_NO_ERROR; // Scene storage ID @@ -476,16 +492,13 @@ CHIP_ERROR TestSceneData(SceneTableImpl * provider, FabricIndex fabric_index) SceneTableEntry scene2(sceneId2, sceneData2); SceneTableEntry scene3(sceneId3, sceneData3); - LogErrorOnFailure(scene_handler_test(provider)); - - err = provider->SceneSaveEFS(scene1, ON_OFF_CID); - LogErrorOnFailure(err); - err = provider->SceneSaveEFS(scene1, LV_CTR_CID); + err = scene_handler_test(provider); LogErrorOnFailure(err); - err = provider->SceneSaveEFS(scene3, ON_OFF_CID); + err = provider->SceneSaveEFS(scene1); LogErrorOnFailure(err); - err = provider->SceneSaveEFS(scene3, CC_CTR_CID); + + err = provider->SceneSaveEFS(scene3); LogErrorOnFailure(err); // Tests From 7ae1298668c074c2efdcb7a199ee3e0be98dbe53 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Mon, 6 Mar 2023 13:50:23 -0500 Subject: [PATCH 36/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Tennessee Carmel-Veilleux --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index be4688a9010126..cd126b9a99eb13 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -62,7 +62,8 @@ class SceneHandler /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) = 0; - /// @brief Returns whether or not a cluster is supported on an endpoint + /// @brief Returns whether or not a cluster for scenes is supported on an endpoint + /// @param endpoint Target Endpoint ID /// @param cluster Target Cluster ID /// @return true if supported, false if not supported From e3bcf55341d43d17b04ebe6f67df9765eb902320 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Mon, 6 Mar 2023 16:42:32 -0500 Subject: [PATCH 37/79] Removed global SceneTable functions and pointer, reworked UnregisterHanlder --- src/app/chip_data_model.gni | 6 +- ...nsionFieldsSets.h => ExtensionFieldSets.h} | 0 ...etsImpl.cpp => ExtensionFieldSetsImpl.cpp} | 16 +-- ...ldsSetsImpl.h => ExtensionFieldSetsImpl.h} | 12 +- src/app/clusters/scenes/SceneTable.h | 63 ++++------ src/app/clusters/scenes/SceneTableImpl.cpp | 63 +++++----- src/app/clusters/scenes/SceneTableImpl.h | 3 +- src/app/server/BUILD.gn | 6 + src/app/server/Server.cpp | 4 + src/app/server/Server.h | 111 ++++++++++++++---- src/app/tests/BUILD.gn | 6 +- src/app/tests/TestSceneTable.cpp | 66 ++++++----- src/lib/support/TestSceneTable.h | 18 ++- 13 files changed, 229 insertions(+), 145 deletions(-) rename src/app/clusters/scenes/{ExtensionFieldsSets.h => ExtensionFieldSets.h} (100%) rename src/app/clusters/scenes/{ExtensionFieldsSetsImpl.cpp => ExtensionFieldSetsImpl.cpp} (87%) rename src/app/clusters/scenes/{ExtensionFieldsSetsImpl.h => ExtensionFieldSetsImpl.h} (93%) diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni index 221312a60c3906..197f81b0effdb7 100644 --- a/src/app/chip_data_model.gni +++ b/src/app/chip_data_model.gni @@ -157,9 +157,9 @@ template("chip_data_model") { "${_app_root}/clusters/identify-server/identify-server.h", "${_app_root}/clusters/level-control/level-control.h", "${_app_root}/clusters/on-off-server/on-off-server.h", - "${_app_root}/clusters/scenes/ExtensionFieldsSets.h", - "${_app_root}/clusters/scenes/ExtensionFieldsSetsImpl.cpp", - "${_app_root}/clusters/scenes/ExtensionFieldsSetsImpl.h", + "${_app_root}/clusters/scenes/ExtensionFieldSets.h", + "${_app_root}/clusters/scenes/ExtensionFieldSetsImpl.cpp", + "${_app_root}/clusters/scenes/ExtensionFieldSetsImpl.h", "${_app_root}/clusters/scenes/SceneTable.h", "${_app_root}/clusters/scenes/SceneTableImpl.cpp", "${_app_root}/clusters/scenes/SceneTableImpl.h", diff --git a/src/app/clusters/scenes/ExtensionFieldsSets.h b/src/app/clusters/scenes/ExtensionFieldSets.h similarity index 100% rename from src/app/clusters/scenes/ExtensionFieldsSets.h rename to src/app/clusters/scenes/ExtensionFieldSets.h diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp similarity index 87% rename from src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp rename to src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 3e9a2232ad4660..c4e32832cb85bc 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -15,14 +15,14 @@ * limitations under the License. */ -#include +#include namespace chip { namespace scenes { -ExtensionFieldsSetsImpl::ExtensionFieldsSetsImpl() : ExtensionFieldsSets() {} +ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldsSets() {} -CHIP_ERROR ExtensionFieldsSetsImpl::Serialize(TLV::TLVWriter & writer) const +CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(kTagEFSArrayContainer), TLV::kTLVType_Structure, container)); @@ -41,7 +41,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Serialize(TLV::TLVWriter & writer) const return writer.EndContainer(container); } -CHIP_ERROR ExtensionFieldsSetsImpl::Deserialize(TLV::TLVReader & reader) +CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader) { TLV::TLVType container; ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagEFSArrayContainer))); @@ -61,7 +61,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::Deserialize(TLV::TLVReader & reader) return reader.ExitContainer(container); } -void ExtensionFieldsSetsImpl::Clear() +void ExtensionFieldSetsImpl::Clear() { if (!this->IsEmpty()) { @@ -77,7 +77,7 @@ void ExtensionFieldsSetsImpl::Clear() /// If the same ID is present in the EFS array, it will overwrite it. /// @param fieldSet field set to be inserted /// @return CHIP_NO_ERROR if insertion worked, CHIP_ERROR_NO_MEMORY if the array is already full -CHIP_ERROR ExtensionFieldsSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet) +CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet) { CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; uint8_t idPosition = kInvalidPosition; @@ -115,7 +115,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet return err; } -CHIP_ERROR ExtensionFieldsSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & fieldSet, uint8_t position) +CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & fieldSet, uint8_t position) { VerifyOrReturnError(position < this->mFieldNum, CHIP_ERROR_BUFFER_TOO_SMALL); @@ -124,7 +124,7 @@ CHIP_ERROR ExtensionFieldsSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & f return CHIP_NO_ERROR; } -CHIP_ERROR ExtensionFieldsSetsImpl::RemoveFieldAtPosition(uint8_t position) +CHIP_ERROR ExtensionFieldSetsImpl::RemoveFieldAtPosition(uint8_t position) { VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnValue(!this->IsEmpty() && !this->mEFS[position].IsEmpty(), CHIP_NO_ERROR); diff --git a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h similarity index 93% rename from src/app/clusters/scenes/ExtensionFieldsSetsImpl.h rename to src/app/clusters/scenes/ExtensionFieldSetsImpl.h index a8b24623145dee..5e02e561b8344c 100644 --- a/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -17,7 +17,7 @@ #pragma once -#include +#include #include namespace chip { @@ -105,11 +105,11 @@ struct ExtensionFieldsSet } }; -class ExtensionFieldsSetsImpl : public ExtensionFieldsSets +class ExtensionFieldSetsImpl : public ExtensionFieldsSets { public: - ExtensionFieldsSetsImpl(); - ~ExtensionFieldsSetsImpl() override{}; + ExtensionFieldSetsImpl(); + ~ExtensionFieldSetsImpl() override{}; // overrides CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override; @@ -123,7 +123,7 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldsSet & field, uint8_t position); CHIP_ERROR RemoveFieldAtPosition(uint8_t position); - bool operator==(const ExtensionFieldsSetsImpl & other) + bool operator==(const ExtensionFieldSetsImpl & other) { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { @@ -135,7 +135,7 @@ class ExtensionFieldsSetsImpl : public ExtensionFieldsSets return true; } - ExtensionFieldsSetsImpl & operator=(const ExtensionFieldsSetsImpl & other) + ExtensionFieldSetsImpl & operator=(const ExtensionFieldSetsImpl & other) { for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index cd126b9a99eb13..0b7989d9328a15 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -17,7 +17,7 @@ #pragma once #include -#include +#include #include #include #include @@ -56,10 +56,12 @@ class SceneHandler SceneHandler(){}; virtual ~SceneHandler() = default; - /// @brief Gets the list of supported clusters for an endpoint + /// @brief Copies the list of supported clusters for an endpoint in a Span and resizes the span to fit the actual number of + /// supported clusters /// @param endpoint target endpoint /// @param clusterBuffer Buffer to hold the supported cluster IDs, cannot hold more than - /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES + /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES, the function shall use the reduce_size() method in the event it is supporting + /// less than CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES clusters virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) = 0; /// @brief Returns whether or not a cluster for scenes is supported on an endpoint @@ -78,8 +80,8 @@ class SceneHandler virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) = 0; - /// @brief From command StoreScene, retrieves ExtensionField from nvm, it is the functions responsability to resize the mutable - /// span if necessary, a number of byte equal to the span will be stored in memory + /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the functions responsability to + /// resize the mutable span if necessary, a number of byte equal to the span will be stored in memory /// @param endpoint Target Endpoint /// @param cluster Target Cluster /// @param serialisedBytes Output buffer, data needs to be writen in there and size adjusted if smaller than @@ -176,7 +178,7 @@ class SceneTable char mName[kSceneNameMax] = { 0 }; size_t mNameLength = 0; SceneTransitionTime mSceneTransitionTime = 0; - ExtensionFieldsSetsImpl mExtensionFieldsSets; + ExtensionFieldSetsImpl mExtensionFieldSets; TransitionTime100ms mTransitionTime100ms = 0; CharSpan mNameSpan; @@ -185,19 +187,19 @@ class SceneTable { this->SetName(sceneName); } - SceneData(ExtensionFieldsSetsImpl fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, + SceneData(ExtensionFieldSetsImpl fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : mSceneTransitionTime(time), mTransitionTime100ms(time100ms) { this->SetName(sceneName); - mExtensionFieldsSets = fields; + mExtensionFieldSets = fields; } SceneData(const SceneData & other) : mSceneTransitionTime(other.mSceneTransitionTime), mTransitionTime100ms(other.mTransitionTime100ms) { this->SetName(other.mNameSpan); - mExtensionFieldsSets = other.mExtensionFieldsSets; + mExtensionFieldSets = other.mExtensionFieldSets; } ~SceneData(){}; @@ -217,7 +219,7 @@ class SceneTable writer.Put(TLV::ContextTag(kTagSceneDTransitionTime), static_cast(this->mSceneTransitionTime))); ReturnErrorOnFailure( writer.Put(TLV::ContextTag(kTagSceneDTransitionTime100), static_cast(this->mTransitionTime100ms))); - ReturnErrorOnFailure(this->mExtensionFieldsSets.Serialize(writer)); + ReturnErrorOnFailure(this->mExtensionFieldSets.Serialize(writer)); return writer.EndContainer(container); } @@ -243,7 +245,7 @@ class SceneTable ReturnErrorOnFailure(reader.Get(this->mSceneTransitionTime)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime100))); ReturnErrorOnFailure(reader.Get(this->mTransitionTime100ms)); - ReturnErrorOnFailure(this->mExtensionFieldsSets.Deserialize(reader)); + ReturnErrorOnFailure(this->mExtensionFieldSets.Deserialize(reader)); return reader.ExitContainer(container); } @@ -269,20 +271,20 @@ class SceneTable this->SetName(CharSpan()); mSceneTransitionTime = 0; mTransitionTime100ms = 0; - mExtensionFieldsSets.Clear(); + mExtensionFieldSets.Clear(); } bool operator==(const SceneData & other) { return (this->mNameSpan.data_equal(other.mNameSpan) && (this->mSceneTransitionTime == other.mSceneTransitionTime) && (this->mTransitionTime100ms == other.mTransitionTime100ms) && - (this->mExtensionFieldsSets == other.mExtensionFieldsSets)); + (this->mExtensionFieldSets == other.mExtensionFieldSets)); } void operator=(const SceneData & other) { this->SetName(other.mNameSpan); - this->mExtensionFieldsSets = other.mExtensionFieldsSets; + this->mExtensionFieldSets = other.mExtensionFieldSets; this->mSceneTransitionTime = other.mSceneTransitionTime; this->mTransitionTime100ms = other.mTransitionTime100ms; } @@ -332,8 +334,9 @@ class SceneTable virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) = 0; // SceneHandlers - virtual CHIP_ERROR RegisterHandler(SceneHandler * handler) = 0; - virtual CHIP_ERROR UnregisterHandler(uint8_t position) = 0; + virtual CHIP_ERROR RegisterHandler(SceneHandler * handler) = 0; + virtual CHIP_ERROR UnregisterHandler(SceneHandler * handler) = 0; + virtual CHIP_ERROR UnregisterAllHandler() = 0; // Extension field sets operation virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; @@ -348,33 +351,13 @@ class SceneTable virtual SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) = 0; // Handlers - virtual bool HandlerListEmpty() { return (handlerNum == 0); } - virtual bool HandlerListFull() { return (handlerNum >= kMaxSceneHandlers); } - virtual uint8_t GetHandlerNum() { return this->handlerNum; } + virtual bool HandlerListEmpty() { return (mNumHandlers == 0); } + virtual bool HandlerListFull() { return (mNumHandlers >= kMaxSceneHandlers); } + virtual uint8_t GetHandlerNum() { return this->mNumHandlers; } SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; - uint8_t handlerNum = 0; + uint8_t mNumHandlers = 0; }; -/** - * Instance getter for the global SceneTable. - * - * Callers have to externally synchronize usage of this function. - * - * @return The global Scene Table - */ -SceneTable * GetSceneTable(); - -/** - * Instance setter for the global Scene Table. - * - * Callers have to externally synchronize usage of this function. - * - * The `provider` can be set to nullptr if the owner is done with it fully. - * - * @param[in] provider pointer to the Scene Table global instance to use - */ -void SetSceneTable(SceneTable * provider); - } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index df68536f763265..db44b482aa27da 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -431,17 +431,32 @@ CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) else if (fisrtEmptyPosition < kMaxSceneHandlers) { this->mHandlers[fisrtEmptyPosition] = handler; - this->handlerNum++; + this->mNumHandlers++; err = CHIP_NO_ERROR; } return err; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) +CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) { - VerifyOrReturnError(position < kMaxSceneHandlers, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnValue(!this->HandlerListEmpty() && !(this->mHandlers[position] == nullptr), CHIP_NO_ERROR); + uint8_t position = kInvalidPosition; + + // Verify list is populated and handler is not null + VerifyOrReturnValue(!this->HandlerListEmpty() && !(handler == nullptr), CHIP_NO_ERROR); + + // Finds the position of the Handler to unregister + for (uint8_t i = 0; i < this->mNumHandlers; i++) + { + if (this->mHandlers[i] == handler) + { + position = i; + break; + } + } + + // Verify Handler was found + VerifyOrReturnValue(position < kMaxSceneHandlers, CHIP_NO_ERROR); uint8_t nextPos = static_cast(position + 1); uint8_t moveNum = static_cast(kMaxSceneHandlers - nextPos); @@ -450,9 +465,19 @@ CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(uint8_t position) // Compress array after removal memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(this->mHandlers[position]) * moveNum); - this->handlerNum--; + this->mNumHandlers--; // Clear last occupied position - this->mHandlers[handlerNum] = nullptr; + this->mHandlers[mNumHandlers] = nullptr; + + return CHIP_NO_ERROR; +} + +CHIP_ERROR DefaultSceneTableImpl::UnregisterAllHandler() +{ + for (uint8_t i = 0; i < this->mNumHandlers; i++) + { + ReturnErrorOnFailure(this->UnregisterHandler(this->mHandlers[0])); + } return CHIP_NO_ERROR; } @@ -461,7 +486,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) { if (!this->HandlerListEmpty()) { - for (uint8_t i = 0; i < this->handlerNum; i++) + for (uint8_t i = 0; i < this->mNumHandlers; i++) { clusterId cArray[kMaxClusterPerScenes]; Span cSpan(cArray); @@ -476,7 +501,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) EFS.mID = cArray[j]; ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); EFS.mUsedBytes = (uint8_t) EFSSpan.size(); - ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldsSets.InsertFieldSet(EFS)); + ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldSets.InsertFieldSet(EFS)); } } } @@ -499,9 +524,9 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const if (!this->HandlerListEmpty()) { - for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldsSets.GetFieldNum(); i++) + for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldSets.GetFieldNum(); i++) { - scene.mStorageData.mExtensionFieldsSets.GetFieldSetAtPosition(EFS, i); + scene.mStorageData.mExtensionFieldSets.GetFieldSetAtPosition(EFS, i); cluster = EFS.mID; time = scene.mStorageData.mSceneTransitionTime * 1000 + (scene.mStorageData.mTransitionTime100ms ? scene.mStorageData.mTransitionTime100ms * 10 : 0); @@ -509,7 +534,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const if (!EFS.IsEmpty()) { - for (uint8_t j = 0; j < this->handlerNum; j++) + for (uint8_t j = 0; j < this->mNumHandlers; j++) { ReturnErrorOnFailure(this->mHandlers[j]->ApplyScene(scene.mStorageId.mEndpointId, cluster, EFSSpan, time)); } @@ -590,21 +615,5 @@ void DefaultSceneTableImpl::SceneEntryIteratorImpl::Release() mProvider.mSceneEntryIterators.ReleaseObject(this); } -namespace { - -SceneTable * gSceneTable = nullptr; - -} // namespace - -SceneTable * GetSceneTable() -{ - return gSceneTable; -} - -void SetSceneTable(SceneTable * provider) -{ - gSceneTable = provider; -} - } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 42576779900d29..b703c51e6547c0 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -184,7 +184,8 @@ class DefaultSceneTableImpl : public SceneTable // SceneHandlers CHIP_ERROR RegisterHandler(SceneHandler * handler) override; - CHIP_ERROR UnregisterHandler(uint8_t position) override; + CHIP_ERROR UnregisterHandler(SceneHandler * handler) override; + CHIP_ERROR UnregisterAllHandler() override; // Extension field sets operation CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) override; diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index d77162909ee5e6..c76b20ab650b9d 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -27,6 +27,12 @@ static_library("server") { output_name = "libCHIPAppServer" sources = [ + "../clusters/scenes/ExtensionFieldSets.h", + "../clusters/scenes/ExtensionFieldSetsImpl.cpp", + "../clusters/scenes/ExtensionFieldSetsImpl.h", + "../clusters/scenes/SceneTable.h", + "../clusters/scenes/SceneTableImpl.cpp", + "../clusters/scenes/SceneTableImpl.h", "AclStorage.cpp", "AclStorage.h", "CommissioningModeProvider.h", diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index b80c3ca8f45b11..229ec7ac963be5 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -162,6 +162,8 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) mGroupsProvider = initParams.groupDataProvider; SetGroupDataProvider(mGroupsProvider); + mSceneTable = initParams.sceneTable; + mTestEventTriggerDelegate = initParams.testEventTriggerDelegate; deviceInfoprovider = DeviceLayer::GetDeviceInfoProvider(); @@ -535,6 +537,8 @@ KvsPersistentStorageDelegate CommonCaseDeviceServerInitParams::sKvsPersistenStor PersistentStorageOperationalKeystore CommonCaseDeviceServerInitParams::sPersistentStorageOperationalKeystore; Credentials::PersistentStorageOpCertStore CommonCaseDeviceServerInitParams::sPersistentStorageOpCertStore; Credentials::GroupDataProviderImpl CommonCaseDeviceServerInitParams::sGroupDataProvider; +// TODO: complete scene cluster implementation before uncommenting +// scenes::DefaultSceneTableImpl CommonCaseDeviceServerInitParams::sSceneTable; IgnoreCertificateValidityPolicy CommonCaseDeviceServerInitParams::sDefaultCertValidityPolicy; #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION SimpleSessionResumptionStorage CommonCaseDeviceServerInitParams::sSessionResumptionStorage; diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 45bcf0a7290515..3b28d216874262 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -89,7 +91,7 @@ struct ServerInitParams ServerInitParams() = default; // Not copyable - ServerInitParams(const ServerInitParams &) = delete; + ServerInitParams(const ServerInitParams &) = delete; ServerInitParams & operator=(const ServerInitParams &) = delete; // Application delegate to handle some commissioning lifecycle events @@ -116,6 +118,8 @@ struct ServerInitParams // Group data provider: MUST be injected. Used to maintain critical keys such as the Identity // Protection Key (IPK) for CASE. Must be initialized before being provided. Credentials::GroupDataProvider * groupDataProvider = nullptr; + // Scene Table: optionnal, required if Scene Cluster implemented + scenes::SceneTable * sceneTable = nullptr; // Session keystore: MUST be injected. Used to derive and manage lifecycle of symmetric keys. Crypto::SessionKeystore * sessionKeystore = nullptr; // Access control delegate: MUST be injected. Used to look up access control rules. Must be @@ -205,7 +209,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams CommonCaseDeviceServerInitParams() = default; // Not copyable - CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; + CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; CommonCaseDeviceServerInitParams & operator=(const CommonCaseDeviceServerInitParams &) = delete; /** @@ -256,6 +260,11 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams ReturnErrorOnFailure(sGroupDataProvider.Init()); this->groupDataProvider = &sGroupDataProvider; + // TODO: complete scene cluster implementation before uncommenting + // Scene Table + // this->sceneTable = &sSceneTable; + // this->sceneTable->Init(this->persistentStorageDelegate); + #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION ReturnErrorOnFailure(sSessionResumptionStorage.Init(this->persistentStorageDelegate)); this->sessionResumptionStorage = &sSessionResumptionStorage; @@ -289,6 +298,8 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams static PersistentStorageOperationalKeystore sPersistentStorageOperationalKeystore; static Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore; static Credentials::GroupDataProviderImpl sGroupDataProvider; + // TODO: complete scene cluster implementation before uncommenting + // static scenes::DefaultSceneTableImpl sSceneTable; static IgnoreCertificateValidityPolicy sDefaultCertValidityPolicy; #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION static SimpleSessionResumptionStorage sSessionResumptionStorage; @@ -333,41 +344,97 @@ class Server */ void RejoinExistingMulticastGroups(); - FabricTable & GetFabricTable() { return mFabrics; } + FabricTable & GetFabricTable() + { + return mFabrics; + } + + CASESessionManager * GetCASESessionManager() + { + return &mCASESessionManager; + } - CASESessionManager * GetCASESessionManager() { return &mCASESessionManager; } + Messaging::ExchangeManager & GetExchangeManager() + { + return mExchangeMgr; + } - Messaging::ExchangeManager & GetExchangeManager() { return mExchangeMgr; } + SessionManager & GetSecureSessionManager() + { + return mSessions; + } - SessionManager & GetSecureSessionManager() { return mSessions; } + SessionResumptionStorage * GetSessionResumptionStorage() + { + return mSessionResumptionStorage; + } - SessionResumptionStorage * GetSessionResumptionStorage() { return mSessionResumptionStorage; } + app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() + { + return mSubscriptionResumptionStorage; + } - app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mSubscriptionResumptionStorage; } + TransportMgrBase & GetTransportManager() + { + return mTransports; + } - TransportMgrBase & GetTransportManager() { return mTransports; } + Credentials::GroupDataProvider * GetGroupDataProvider() + { + return mGroupsProvider; + } - Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } + scenes::SceneTable * GetSceneTable() + { + return mSceneTable; + } - Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } + Crypto::SessionKeystore * GetSessionKeystore() const + { + return mSessionKeystore; + } #if CONFIG_NETWORK_LAYER_BLE - Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } + Ble::BleLayer * GetBleLayerObject() + { + return mBleLayer; + } #endif - CommissioningWindowManager & GetCommissioningWindowManager() { return mCommissioningWindowManager; } + CommissioningWindowManager & GetCommissioningWindowManager() + { + return mCommissioningWindowManager; + } - PersistentStorageDelegate & GetPersistentStorage() { return *mDeviceStorage; } + PersistentStorageDelegate & GetPersistentStorage() + { + return *mDeviceStorage; + } - app::FailSafeContext & GetFailSafeContext() { return mFailSafeContext; } + app::FailSafeContext & GetFailSafeContext() + { + return mFailSafeContext; + } - TestEventTriggerDelegate * GetTestEventTriggerDelegate() { return mTestEventTriggerDelegate; } + TestEventTriggerDelegate * GetTestEventTriggerDelegate() + { + return mTestEventTriggerDelegate; + } - Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; } + Crypto::OperationalKeystore * GetOperationalKeystore() + { + return mOperationalKeystore; + } - Credentials::OperationalCertificateStore * GetOpCertStore() { return mOpCertStore; } + Credentials::OperationalCertificateStore * GetOpCertStore() + { + return mOpCertStore; + } - app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() { return mAttributePersister; } + app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() + { + return mAttributePersister; + } /** * This function causes the ShutDown event to be generated async on the @@ -384,7 +451,10 @@ class Server return System::SystemClock().GetMonotonicMicroseconds64() - mInitTimestamp; } - static Server & GetInstance() { return sServer; } + static Server & GetInstance() + { + return sServer; + } private: Server() = default; @@ -565,6 +635,7 @@ class Server app::SubscriptionResumptionStorage * mSubscriptionResumptionStorage; Credentials::CertificateValidityPolicy * mCertificateValidityPolicy; Credentials::GroupDataProvider * mGroupsProvider; + scenes::SceneTable * mSceneTable; Crypto::SessionKeystore * mSessionKeystore; app::DefaultAttributePersistenceProvider mAttributePersister; GroupDataProviderListener mListener; diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 606b6d74937d54..a0b580bc93c65c 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -81,9 +81,9 @@ source_set("ota-requestor-test-srcs") { source_set("scenes-table-test-srcs") { sources = [ - "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSets.h", - "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSetsImpl.cpp", - "${chip_root}/src/app/clusters/scenes/ExtensionFieldsSetsImpl.h", + "${chip_root}/src/app/clusters/scenes/ExtensionFieldSets.h", + "${chip_root}/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp", + "${chip_root}/src/app/clusters/scenes/ExtensionFieldSetsImpl.h", "${chip_root}/src/app/clusters/scenes/SceneTable.h", "${chip_root}/src/app/clusters/scenes/SceneTableImpl.cpp", "${chip_root}/src/app/clusters/scenes/SceneTableImpl.h", diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 4f0813f9d9cb82..248d2e9c7772c6 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -127,15 +127,21 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl ClusterId * buffer = clusterBuffer.data(); if (endpoint == TEST_ENDPOINT1) { - buffer[0] = ON_OFF_CID; - buffer[1] = LV_CTR_CID; - clusterBuffer.reduce_size(2); + if (clusterBuffer.size() >= 2) + { + buffer[0] = ON_OFF_CID; + buffer[1] = LV_CTR_CID; + clusterBuffer.reduce_size(2); + } } else if (endpoint == TEST_ENDPOINT2) { - buffer[0] = ON_OFF_CID; - buffer[1] = CC_CTR_CID; - clusterBuffer.reduce_size(2); + if (clusterBuffer.size() >= 2) + { + buffer[0] = ON_OFF_CID; + buffer[1] = CC_CTR_CID; + clusterBuffer.reduce_size(2); + } } } @@ -282,52 +288,55 @@ void ResetSceneTable(SceneTable * sceneTable) void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) { - SceneTable * sceneTable = scenes::GetSceneTable(); + SceneTable * sceneTable = &sSceneTable; TestSceneHandler tmpHandler[scenes::kMaxSceneHandlers]; for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) { - NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == i); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == i); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[i])); + printf("Handler : %d | Address : %p \n", i, &tmpHandler[i]); } - NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == scenes::kMaxSceneHandlers); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxSceneHandlers); // Removal at begining - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(0)); - NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == static_cast(scenes::kMaxSceneHandlers - 1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[0])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); // Confirm array was compressed and last position is now null NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); // Removal at the middle - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(3)); - NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == static_cast(scenes::kMaxSceneHandlers - 2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[3])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 2)); // Confirm array was compressed and last position is now null NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 2]); - // Removal at the middle - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(scenes::kMaxSceneHandlers - 3)); - NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == static_cast(scenes::kMaxSceneHandlers - 3)); + // Removal at the end + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[scenes::kMaxSceneHandlers - 1])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 3)); NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 3]); // Emptying Handler array + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterAllHandler()); for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) { - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(0)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[i])); } // Verify the handler num has been updated properly - NL_TEST_ASSERT(aSuite, sceneTable->handlerNum == 0); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == 0); // Verify all array is empty for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) { + printf("Handler : %d | Address : %p \n", i, sceneTable->mHandlers[i]); NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[i]); } } void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) { - SceneTable * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = &sSceneTable; ClusterId tempCluster = 0; app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; @@ -522,7 +531,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) void TestStoreScenes(nlTestSuite * aSuite, void * aContext) { - SceneTable * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = &sSceneTable; NL_TEST_ASSERT(aSuite, sceneTable); // Reset test @@ -587,7 +596,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) { - SceneTable * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = &sSceneTable; NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -611,7 +620,7 @@ void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) void TestIterateScenes(nlTestSuite * aSuite, void * aContext) { - SceneTable * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = &sSceneTable; NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -647,7 +656,7 @@ void TestIterateScenes(nlTestSuite * aSuite, void * aContext) void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) { - SceneTable * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = &sSceneTable; NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; @@ -738,7 +747,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) void TestFabricScenes(nlTestSuite * aSuite, void * aContext) { - SceneTable * sceneTable = chip::scenes::GetSceneTable(); + SceneTable * sceneTable = &sSceneTable; NL_TEST_ASSERT(aSuite, sceneTable); // Reset test @@ -804,8 +813,6 @@ int TestSetup(void * inContext) VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); VerifyOrReturnError(CHIP_NO_ERROR == sSceneTable.Init(&testStorage), FAILURE); - SetSceneTable(&sSceneTable); - return SUCCESS; } @@ -814,12 +821,9 @@ int TestSetup(void * inContext) */ int TestTeardown(void * inContext) { - SceneTable * sceneTable = chip::scenes::GetSceneTable(); - if (nullptr != sceneTable) - { - sceneTable->Finish(); - } + sSceneTable.Finish(); chip::Platform::MemoryShutdown(); + return SUCCESS; } int TestSceneTable() diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h index 26bfb84bd55e62..5a8446351334bf 100644 --- a/src/lib/support/TestSceneTable.h +++ b/src/lib/support/TestSceneTable.h @@ -82,15 +82,21 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl ClusterId * buffer = clusterBuffer.data(); if (endpoint == TEST_ENDPOINT1) { - buffer[0] = ON_OFF_CID; - buffer[1] = LV_CTR_CID; - clusterBuffer.reduce_size(2); + if (clusterBuffer.size() >= 2) + { + buffer[0] = ON_OFF_CID; + buffer[1] = LV_CTR_CID; + clusterBuffer.reduce_size(2); + } } else if (endpoint == TEST_ENDPOINT2) { - buffer[0] = ON_OFF_CID; - buffer[1] = CC_CTR_CID; - clusterBuffer.reduce_size(2); + if (clusterBuffer.size() >= 2) + { + buffer[0] = ON_OFF_CID; + buffer[1] = CC_CTR_CID; + clusterBuffer.reduce_size(2); + } } } From ff398f0d48f08325de80f11c9fb2cd6efcbe467f Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 6 Mar 2023 21:56:19 +0000 Subject: [PATCH 38/79] Restyled by clang-format --- src/app/server/Server.h | 99 +++++++++-------------------------------- 1 file changed, 21 insertions(+), 78 deletions(-) diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 3b28d216874262..a8a1d6064ddba8 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -91,7 +91,7 @@ struct ServerInitParams ServerInitParams() = default; // Not copyable - ServerInitParams(const ServerInitParams &) = delete; + ServerInitParams(const ServerInitParams &) = delete; ServerInitParams & operator=(const ServerInitParams &) = delete; // Application delegate to handle some commissioning lifecycle events @@ -209,7 +209,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams CommonCaseDeviceServerInitParams() = default; // Not copyable - CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; + CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; CommonCaseDeviceServerInitParams & operator=(const CommonCaseDeviceServerInitParams &) = delete; /** @@ -344,97 +344,43 @@ class Server */ void RejoinExistingMulticastGroups(); - FabricTable & GetFabricTable() - { - return mFabrics; - } + FabricTable & GetFabricTable() { return mFabrics; } - CASESessionManager * GetCASESessionManager() - { - return &mCASESessionManager; - } + CASESessionManager * GetCASESessionManager() { return &mCASESessionManager; } - Messaging::ExchangeManager & GetExchangeManager() - { - return mExchangeMgr; - } + Messaging::ExchangeManager & GetExchangeManager() { return mExchangeMgr; } - SessionManager & GetSecureSessionManager() - { - return mSessions; - } + SessionManager & GetSecureSessionManager() { return mSessions; } - SessionResumptionStorage * GetSessionResumptionStorage() - { - return mSessionResumptionStorage; - } + SessionResumptionStorage * GetSessionResumptionStorage() { return mSessionResumptionStorage; } - app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() - { - return mSubscriptionResumptionStorage; - } + app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mSubscriptionResumptionStorage; } - TransportMgrBase & GetTransportManager() - { - return mTransports; - } + TransportMgrBase & GetTransportManager() { return mTransports; } - Credentials::GroupDataProvider * GetGroupDataProvider() - { - return mGroupsProvider; - } + Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } - scenes::SceneTable * GetSceneTable() - { - return mSceneTable; - } + scenes::SceneTable * GetSceneTable() { return mSceneTable; } - Crypto::SessionKeystore * GetSessionKeystore() const - { - return mSessionKeystore; - } + Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } #if CONFIG_NETWORK_LAYER_BLE - Ble::BleLayer * GetBleLayerObject() - { - return mBleLayer; - } + Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } #endif - CommissioningWindowManager & GetCommissioningWindowManager() - { - return mCommissioningWindowManager; - } + CommissioningWindowManager & GetCommissioningWindowManager() { return mCommissioningWindowManager; } - PersistentStorageDelegate & GetPersistentStorage() - { - return *mDeviceStorage; - } + PersistentStorageDelegate & GetPersistentStorage() { return *mDeviceStorage; } - app::FailSafeContext & GetFailSafeContext() - { - return mFailSafeContext; - } + app::FailSafeContext & GetFailSafeContext() { return mFailSafeContext; } - TestEventTriggerDelegate * GetTestEventTriggerDelegate() - { - return mTestEventTriggerDelegate; - } + TestEventTriggerDelegate * GetTestEventTriggerDelegate() { return mTestEventTriggerDelegate; } - Crypto::OperationalKeystore * GetOperationalKeystore() - { - return mOperationalKeystore; - } + Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; } - Credentials::OperationalCertificateStore * GetOpCertStore() - { - return mOpCertStore; - } + Credentials::OperationalCertificateStore * GetOpCertStore() { return mOpCertStore; } - app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() - { - return mAttributePersister; - } + app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() { return mAttributePersister; } /** * This function causes the ShutDown event to be generated async on the @@ -451,10 +397,7 @@ class Server return System::SystemClock().GetMonotonicMicroseconds64() - mInitTimestamp; } - static Server & GetInstance() - { - return sServer; - } + static Server & GetInstance() { return sServer; } private: Server() = default; From 617d1dacba0cc1d58629c950ecc324c1aa27d106 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Mon, 6 Mar 2023 21:56:19 +0000 Subject: [PATCH 39/79] Restyled by clang-format --- src/app/clusters/scenes/BUILD.gn | 32 +++++++++++++++++++ .../scenes/ExtensionFieldSetsImpl.cpp | 2 +- src/app/server/BUILD.gn | 7 +--- src/app/server/Server.h | 2 +- src/app/tests/TestSceneTable.cpp | 11 ++++--- src/lib/core/CHIPConfig.h | 2 +- 6 files changed, 43 insertions(+), 13 deletions(-) create mode 100644 src/app/clusters/scenes/BUILD.gn diff --git a/src/app/clusters/scenes/BUILD.gn b/src/app/clusters/scenes/BUILD.gn new file mode 100644 index 00000000000000..8149460972a9e2 --- /dev/null +++ b/src/app/clusters/scenes/BUILD.gn @@ -0,0 +1,32 @@ +# Copyright (c) 2023 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. +import("//build_overrides/chip.gni") + +static_library("scenes") { + output_name = "libCHIPScenes" + + sources = [ + "ExtensionFieldSets.h", + "ExtensionFieldSetsImpl.cpp", + "ExtensionFieldSetsImpl.h", + "SceneTable.h", + "SceneTableImpl.cpp", + "SceneTableImpl.h", + ] + + cflags = [ + "-Wconversion", + "-Wshadow", + ] +} diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index c4e32832cb85bc..89d33026e9212a 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -15,7 +15,7 @@ * limitations under the License. */ -#include +#include "ExtensionFieldSetsImpl.h" namespace chip { namespace scenes { diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index c76b20ab650b9d..507f4b2882d570 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -27,12 +27,6 @@ static_library("server") { output_name = "libCHIPAppServer" sources = [ - "../clusters/scenes/ExtensionFieldSets.h", - "../clusters/scenes/ExtensionFieldSetsImpl.cpp", - "../clusters/scenes/ExtensionFieldSetsImpl.h", - "../clusters/scenes/SceneTable.h", - "../clusters/scenes/SceneTableImpl.cpp", - "../clusters/scenes/SceneTableImpl.h", "AclStorage.cpp", "AclStorage.h", "CommissioningModeProvider.h", @@ -56,6 +50,7 @@ static_library("server") { public_deps = [ "${chip_root}/src/app", + "${chip_root}/src/app/clusters/scenes", "${chip_root}/src/lib/address_resolve", "${chip_root}/src/lib/dnssd", "${chip_root}/src/messaging", diff --git a/src/app/server/Server.h b/src/app/server/Server.h index a8a1d6064ddba8..e841faf3bc70b8 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -578,7 +578,7 @@ class Server app::SubscriptionResumptionStorage * mSubscriptionResumptionStorage; Credentials::CertificateValidityPolicy * mCertificateValidityPolicy; Credentials::GroupDataProvider * mGroupsProvider; - scenes::SceneTable * mSceneTable; + scenes::SceneTable * mSceneTable = nullptr; Crypto::SessionKeystore * mSessionKeystore; app::DefaultAttributePersistenceProvider mAttributePersister; GroupDataProviderListener mListener; diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 248d2e9c7772c6..f577bf3c4c1f18 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -183,11 +183,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; + // Warning: OO_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); serialisedBytes.reduce_size(15); // Used memory for OnOff TLV break; case LV_CTR_CID: err = CHIP_NO_ERROR; + // Warning: LC_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); serialisedBytes.reduce_size(27); // Used memory for Level Control TLV break; @@ -201,11 +203,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { case ON_OFF_CID: err = CHIP_NO_ERROR; + // Warning: OO_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); serialisedBytes.reduce_size(15); // Used memory for OnOff TLV break; case CC_CTR_CID: err = CHIP_NO_ERROR; + // Warning: CC_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); serialisedBytes.reduce_size(99); // Used memory for Color Control TLV break; @@ -272,7 +276,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl } } - return CHIP_NO_ERROR; + return err; } }; @@ -295,11 +299,10 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) { NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == i); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[i])); - printf("Handler : %d | Address : %p \n", i, &tmpHandler[i]); } NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxSceneHandlers); - // Removal at begining + // Removal at beginning NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[0])); NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); // Confirm array was compressed and last position is now null @@ -669,7 +672,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, scene == scene10); iterator->Release(); - // Adde scene in middle, a spot should have been freed + // Add scene in middle, a spot should have been freed NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene9)); iterator = sceneTable->IterateSceneEntry(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 8); diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index e549e67924207d..35fd670fa1c687 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1379,7 +1379,7 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID 0x00 #endif /** - * @brief The maximum number of scenes according to spec + * @brief The minimum number of scenes to support according to spec */ #ifndef CHIP_CONFIG_SCENES_MAX_NUMBER #define CHIP_CONFIG_SCENES_MAX_NUMBER 16 From ced5701dbce27f63e5151dcbd2a55e0e0a670dd0 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Tue, 7 Mar 2023 18:35:02 -0500 Subject: [PATCH 40/79] Made comments more explicit, moved methods from interface to implementation --- src/app/clusters/scenes/BUILD.gn | 2 + src/app/clusters/scenes/ExtensionFieldSets.h | 6 +- .../scenes/ExtensionFieldSetsImpl.cpp | 2 +- .../clusters/scenes/ExtensionFieldSetsImpl.h | 2 +- src/app/clusters/scenes/SceneTable.h | 160 ++---- src/app/clusters/scenes/SceneTableImpl.cpp | 81 ++- src/app/clusters/scenes/SceneTableImpl.h | 14 +- src/app/server/Server.h | 103 +++- src/app/tests/TestSceneTable.cpp | 318 +++++++---- src/lib/core/CHIPConfig.h | 27 +- src/lib/core/DataModelTypes.h | 5 - src/lib/support/DefaultStorageKeyAllocator.h | 10 +- src/lib/support/TestSceneTable.h | 528 ------------------ 13 files changed, 430 insertions(+), 828 deletions(-) delete mode 100644 src/lib/support/TestSceneTable.h diff --git a/src/app/clusters/scenes/BUILD.gn b/src/app/clusters/scenes/BUILD.gn index 8149460972a9e2..0e34919d8307b8 100644 --- a/src/app/clusters/scenes/BUILD.gn +++ b/src/app/clusters/scenes/BUILD.gn @@ -25,6 +25,8 @@ static_library("scenes") { "SceneTableImpl.h", ] + deps = [ "${chip_root}/src/app" ] + cflags = [ "-Wconversion", "-Wshadow", diff --git a/src/app/clusters/scenes/ExtensionFieldSets.h b/src/app/clusters/scenes/ExtensionFieldSets.h index e2853fa6e09fbd..97bd4cd92c4b47 100644 --- a/src/app/clusters/scenes/ExtensionFieldSets.h +++ b/src/app/clusters/scenes/ExtensionFieldSets.h @@ -27,11 +27,11 @@ static constexpr uint8_t kInvalidPosition = 0xff; static constexpr uint8_t kMaxClusterPerScenes = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; static constexpr uint8_t kMaxFieldsPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; -class ExtensionFieldsSets +class ExtensionFieldSets { public: - ExtensionFieldsSets(){}; - virtual ~ExtensionFieldsSets() = default; + ExtensionFieldSets(){}; + virtual ~ExtensionFieldSets() = default; virtual CHIP_ERROR Serialize(TLV::TLVWriter & writer) const = 0; virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 89d33026e9212a..60cdad7cd96989 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -20,7 +20,7 @@ namespace chip { namespace scenes { -ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldsSets() {} +ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldSets() {} CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const { diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 5e02e561b8344c..c8af604c2e9060 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -105,7 +105,7 @@ struct ExtensionFieldsSet } }; -class ExtensionFieldSetsImpl : public ExtensionFieldsSets +class ExtensionFieldSetsImpl : public ExtensionFieldSets { public: ExtensionFieldSetsImpl(); diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 0b7989d9328a15..906f1fc2179fb2 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -23,26 +23,37 @@ #include #include +/** + * @brief Indicates the absence of a Scene table entry. + */ +#ifndef CHIP_CONFIG_SCENES_TABLE_NULL_INDEX +#define CHIP_CONFIG_SCENES_TABLE_NULL_INDEX 0xFF +#endif + +/** + * @brief The group identifier for the global scene. + */ +#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID +#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID 0x0000 +#endif + +/** + * @brief The scene identifier for the global scene. + */ +#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID +#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID 0x00 +#endif + namespace chip { namespace scenes { -enum SceneTLVTag -{ - kTagSceneStorageIDContainer = 1, - kTagSceneEndpointID, - kTagSceneGroupID, - kTagSceneID, - kTagSceneDataContainer, - kTagSceneName, - kTagSceneDTransitionTime, - kTagSceneDTransitionTime100, -}; - typedef uint32_t TransitionTimeMs; typedef uint16_t SceneTransitionTime; typedef uint8_t TransitionTime100ms; -static constexpr uint8_t kEFSBufferSize = 128; +constexpr SceneGroupID kGlobalGroupSceneId = CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID; +constexpr SceneIndex kUndefinedSceneIndex = 0xff; +constexpr SceneId kUndefinedSceneId = CHIP_CONFIG_SCENES_TABLE_NULL_INDEX; static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; @@ -89,7 +100,7 @@ class SceneHandler /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) = 0; - /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a command object + /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a cluster object /// @param endpoint Endpoint ID /// @param cluster Cluster ID to save /// @param serialisedBytes ExtensionFieldSet stored in NVM @@ -107,6 +118,7 @@ class SceneHandler virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) = 0; }; +template class SceneTable { public: @@ -123,36 +135,6 @@ class SceneTable SceneStorageId(EndpointId endpoint, SceneId id, SceneGroupID groupId = kGlobalGroupSceneId) : mEndpointId(endpoint), mGroupId(groupId), mSceneId(id) {} - SceneStorageId(const SceneStorageId & storageId) : - mEndpointId(storageId.mEndpointId), mGroupId(storageId.mGroupId), mSceneId(storageId.mSceneId) - {} - CHIP_ERROR Serialize(TLV::TLVWriter & writer) const - { - TLV::TLVType container; - ReturnErrorOnFailure( - writer.StartContainer(TLV::ContextTag(kTagSceneStorageIDContainer), TLV::kTLVType_Structure, container)); - - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneEndpointID), static_cast(this->mEndpointId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(this->mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(this->mSceneId))); - - return writer.EndContainer(container); - } - CHIP_ERROR Deserialize(TLV::TLVReader & reader) - { - TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagSceneStorageIDContainer))); - ReturnErrorOnFailure(reader.EnterContainer(container)); - - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); - ReturnErrorOnFailure(reader.Get(this->mEndpointId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); - ReturnErrorOnFailure(reader.Get(this->mGroupId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); - ReturnErrorOnFailure(reader.Get(this->mSceneId)); - - return reader.ExitContainer(container); - } void Clear() { @@ -160,96 +142,43 @@ class SceneTable mGroupId = kGlobalGroupSceneId; mSceneId = kUndefinedSceneId; } + bool operator==(const SceneStorageId & other) { return (this->mEndpointId == other.mEndpointId && this->mGroupId == other.mGroupId && this->mSceneId == other.mSceneId); } - void operator=(const SceneStorageId & other) - { - this->mEndpointId = other.mEndpointId; - this->mGroupId = other.mGroupId; - this->mSceneId = other.mSceneId; - } }; /// @brief struct used to store data held in a scene struct SceneData { - char mName[kSceneNameMax] = { 0 }; - size_t mNameLength = 0; - SceneTransitionTime mSceneTransitionTime = 0; - ExtensionFieldSetsImpl mExtensionFieldSets; + char mName[kSceneNameMax] = { 0 }; + size_t mNameLength = 0; + SceneTransitionTime mSceneTransitionTimeSeconds = 0; + EFStype mExtensionFieldSets; TransitionTime100ms mTransitionTime100ms = 0; - CharSpan mNameSpan; SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : - mSceneTransitionTime(time), mTransitionTime100ms(time100ms) + mSceneTransitionTimeSeconds(time), mTransitionTime100ms(time100ms) { this->SetName(sceneName); } - SceneData(ExtensionFieldSetsImpl fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, + SceneData(EFStype fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : - mSceneTransitionTime(time), + mSceneTransitionTimeSeconds(time), mTransitionTime100ms(time100ms) { this->SetName(sceneName); mExtensionFieldSets = fields; } SceneData(const SceneData & other) : - mSceneTransitionTime(other.mSceneTransitionTime), mTransitionTime100ms(other.mTransitionTime100ms) + mSceneTransitionTimeSeconds(other.mSceneTransitionTimeSeconds), mTransitionTime100ms(other.mTransitionTime100ms) { - this->SetName(other.mNameSpan); + this->SetName(CharSpan(other.mName, other.mNameLength)); mExtensionFieldSets = other.mExtensionFieldSets; } ~SceneData(){}; - CHIP_ERROR Serialize(TLV::TLVWriter & writer) const - { - TLV::TLVType container; - ReturnErrorOnFailure( - writer.StartContainer(TLV::ContextTag(kTagSceneDataContainer), TLV::kTLVType_Structure, container)); - - // A 0 size means the name wasn't used so it won't get stored - if (!this->mNameSpan.empty()) - { - ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(kTagSceneName), this->mNameSpan)); - } - - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(kTagSceneDTransitionTime), static_cast(this->mSceneTransitionTime))); - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(kTagSceneDTransitionTime100), static_cast(this->mTransitionTime100ms))); - ReturnErrorOnFailure(this->mExtensionFieldSets.Serialize(writer)); - - return writer.EndContainer(container); - } - CHIP_ERROR Deserialize(TLV::TLVReader & reader) - { - TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagSceneDataContainer))); - ReturnErrorOnFailure(reader.EnterContainer(container)); - - ReturnErrorOnFailure(reader.Next()); - TLV::Tag currTag = reader.GetTag(); - VerifyOrReturnError(TLV::ContextTag(kTagSceneName) == currTag || TLV::ContextTag(kTagSceneDTransitionTime) == currTag, - CHIP_ERROR_WRONG_TLV_TYPE); - - // If there was no error, a name is expected from the storage, if there was an unexpectec TLV element, - if (currTag == TLV::ContextTag(kTagSceneName)) - { - ReturnErrorOnFailure(reader.Get(this->mNameSpan)); - this->SetName(this->mNameSpan); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime))); - } - - ReturnErrorOnFailure(reader.Get(this->mSceneTransitionTime)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime100))); - ReturnErrorOnFailure(reader.Get(this->mTransitionTime100ms)); - ReturnErrorOnFailure(this->mExtensionFieldSets.Deserialize(reader)); - - return reader.ExitContainer(container); - } - void SetName(const CharSpan & sceneName) { if (nullptr == sceneName.data()) @@ -263,30 +192,30 @@ class SceneTable memcpy(mName, sceneName.data(), maxChars); mNameLength = maxChars; } - mNameSpan = CharSpan(mName, mNameLength); } void Clear() { this->SetName(CharSpan()); - mSceneTransitionTime = 0; - mTransitionTime100ms = 0; + mSceneTransitionTimeSeconds = 0; + mTransitionTime100ms = 0; mExtensionFieldSets.Clear(); } bool operator==(const SceneData & other) { - return (this->mNameSpan.data_equal(other.mNameSpan) && (this->mSceneTransitionTime == other.mSceneTransitionTime) && + return (!memcmp(this->mName, other.mName, this->mNameLength) && + (this->mSceneTransitionTimeSeconds == other.mSceneTransitionTimeSeconds) && (this->mTransitionTime100ms == other.mTransitionTime100ms) && (this->mExtensionFieldSets == other.mExtensionFieldSets)); } void operator=(const SceneData & other) { - this->SetName(other.mNameSpan); - this->mExtensionFieldSets = other.mExtensionFieldSets; - this->mSceneTransitionTime = other.mSceneTransitionTime; - this->mTransitionTime100ms = other.mTransitionTime100ms; + this->SetName(CharSpan(other.mName, other.mNameLength)); + this->mExtensionFieldSets = other.mExtensionFieldSets; + this->mSceneTransitionTimeSeconds = other.mSceneTransitionTimeSeconds; + this->mTransitionTime100ms = other.mTransitionTime100ms; } }; @@ -322,6 +251,7 @@ class SceneTable // Not copyable SceneTable(const SceneTable &) = delete; + SceneTable & operator=(const SceneTable &) = delete; virtual CHIP_ERROR Init(PersistentStorageDelegate * storage) = 0; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index db44b482aa27da..fcf976de12b874 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -36,14 +36,18 @@ struct FabricHavingSceneList : public CommonPersistentData::FabricList { CHIP_ERROR UpdateKey(StorageKeyName & key) override { - key = DefaultStorageKeyAllocator::SceneFabricList(); + key = DefaultStorageKeyAllocator::GroupFabricList(); return CHIP_NO_ERROR; } }; -static constexpr size_t kPersistentBufferMax = 256; +// Worst case tested: Add Scene Command with EFS using the default SerializeAdd Method. This yielded a serialized scene of 212bytes +// when using the OnOff, Level Control and Color Control as well as the maximal name length of 16 bytes. Putting 256 gives some +// slack in case different clusters are used. Value obtained by using writer.GetLengthWritten at the end of the SceneTableData +// Serialize method. +static constexpr size_t kPersistentSceneBufferMax = 256; -struct SceneTableData : public SceneTableEntry, PersistentData +struct SceneTableData : public SceneTableEntry, PersistentData { FabricIndex fabric_index = kUndefinedFabricIndex; SceneIndex index = 0; @@ -68,36 +72,82 @@ struct SceneTableData : public SceneTableEntry, PersistentData(mStorageId.mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(mStorageId.mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(mStorageId.mSceneId))); + + // Scene Data + // A length of 0 means the name wasn't used so it won't get stored + if (!NameSpan.empty()) + { + ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(kTagSceneName), NameSpan)); + } + + ReturnErrorOnFailure( + writer.Put(TLV::ContextTag(kTagSceneDTransitionTime), static_cast(mStorageData.mSceneTransitionTimeSeconds))); + ReturnErrorOnFailure( + writer.Put(TLV::ContextTag(kTagSceneDTransitionTime100), static_cast(mStorageData.mTransitionTime100ms))); + ReturnErrorOnFailure(mStorageData.mExtensionFieldSets.Serialize(writer)); return writer.EndContainer(container); } CHIP_ERROR Deserialize(TLV::TLVReader & reader) override { + CharSpan NameSpan(mStorageData.mName); + ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); TLV::TLVType container; ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(mStorageId.Deserialize(reader)); - ReturnErrorOnFailure(mStorageData.Deserialize(reader)); + // Scene ID + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); + ReturnErrorOnFailure(reader.Get(mStorageId.mEndpointId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); + ReturnErrorOnFailure(reader.Get(mStorageId.mGroupId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); + ReturnErrorOnFailure(reader.Get(mStorageId.mSceneId)); + + // Scene Data + ReturnErrorOnFailure(reader.Next()); + TLV::Tag currTag = reader.GetTag(); + VerifyOrReturnError(TLV::ContextTag(kTagSceneName) == currTag || TLV::ContextTag(kTagSceneDTransitionTime) == currTag, + CHIP_ERROR_WRONG_TLV_TYPE); + + // If there was no error, a name is expected from the storage, if there was an unexpectec TLV element, + if (currTag == TLV::ContextTag(kTagSceneName)) + { + ReturnErrorOnFailure(reader.Get(NameSpan)); + mStorageData.SetName(NameSpan); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime))); + } + + ReturnErrorOnFailure(reader.Get(mStorageData.mSceneTransitionTimeSeconds)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneDTransitionTime100))); + ReturnErrorOnFailure(reader.Get(mStorageData.mTransitionTime100ms)); + ReturnErrorOnFailure(mStorageData.mExtensionFieldSets.Deserialize(reader)); return reader.ExitContainer(container); } }; +// A Full fabric serialized TLV length is 88 bytes, 128 bytes gives some slack tested bu running writer.GetLengthWritten at the +// end of the Serialize method of FabricSceneData +static constexpr size_t kPersistentFabricBufferMax = 128; + /** * @brief Linked list of all scenes in a fabric, stored in persistent memory * * FabricSceneData is an access to a linked list of scenes */ -struct FabricSceneData : public PersistentData +struct FabricSceneData : public PersistentData { FabricIndex fabric_index = kUndefinedFabricIndex; uint8_t scene_count = 0; @@ -130,9 +180,13 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneCount), static_cast(scene_count))); + + // Storing the scene map for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure(scene_map[i].Serialize(writer)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneEndpointID), static_cast(scene_map[i].mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(scene_map[i].mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(scene_map[i].mSceneId))); } ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNext), static_cast(next))); @@ -151,7 +205,12 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(reader.Get(scene_count)); for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure(scene_map[i].Deserialize(reader)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); + ReturnErrorOnFailure(reader.Get(scene_map[i].mEndpointId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); + ReturnErrorOnFailure(reader.Get(scene_map[i].mGroupId)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); + ReturnErrorOnFailure(reader.Get(scene_map[i].mSceneId)); } ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNext))); ReturnErrorOnFailure(reader.Get(next)); @@ -528,7 +587,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const { scene.mStorageData.mExtensionFieldSets.GetFieldSetAtPosition(EFS, i); cluster = EFS.mID; - time = scene.mStorageData.mSceneTransitionTime * 1000 + + time = scene.mStorageData.mSceneTransitionTimeSeconds * 1000 + (scene.mStorageData.mTransitionTime100ms ? scene.mStorageData.mTransitionTime100ms * 10 : 0); ByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, EFS.mUsedBytes); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index b703c51e6547c0..2a66b41d47ad95 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -25,6 +25,18 @@ namespace chip { namespace scenes { +enum SceneTLVTag +{ + kTagSceneStorageIDContainer = 1, + kTagSceneEndpointID, + kTagSceneGroupID, + kTagSceneID, + kTagSceneDataContainer, + kTagSceneName, + kTagSceneDTransitionTime, + kTagSceneDTransitionTime100, +}; + using clusterId = chip::ClusterId; /// @brief Default implementation of handler, handle EFS from add scene and view scene commands for any cluster @@ -166,7 +178,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler * It is meant to be used exclusively when the scene cluster is enable for at least one endpoint * on the device. */ -class DefaultSceneTableImpl : public SceneTable +class DefaultSceneTableImpl : public SceneTable { public: DefaultSceneTableImpl() = default; diff --git a/src/app/server/Server.h b/src/app/server/Server.h index e841faf3bc70b8..03d4caaa9c2be0 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -91,7 +91,7 @@ struct ServerInitParams ServerInitParams() = default; // Not copyable - ServerInitParams(const ServerInitParams &) = delete; + ServerInitParams(const ServerInitParams &) = delete; ServerInitParams & operator=(const ServerInitParams &) = delete; // Application delegate to handle some commissioning lifecycle events @@ -119,7 +119,7 @@ struct ServerInitParams // Protection Key (IPK) for CASE. Must be initialized before being provided. Credentials::GroupDataProvider * groupDataProvider = nullptr; // Scene Table: optionnal, required if Scene Cluster implemented - scenes::SceneTable * sceneTable = nullptr; + scenes::SceneTable * sceneTable = nullptr; // Session keystore: MUST be injected. Used to derive and manage lifecycle of symmetric keys. Crypto::SessionKeystore * sessionKeystore = nullptr; // Access control delegate: MUST be injected. Used to look up access control rules. Must be @@ -209,7 +209,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams CommonCaseDeviceServerInitParams() = default; // Not copyable - CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; + CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; CommonCaseDeviceServerInitParams & operator=(const CommonCaseDeviceServerInitParams &) = delete; /** @@ -344,43 +344,97 @@ class Server */ void RejoinExistingMulticastGroups(); - FabricTable & GetFabricTable() { return mFabrics; } + FabricTable & GetFabricTable() + { + return mFabrics; + } - CASESessionManager * GetCASESessionManager() { return &mCASESessionManager; } + CASESessionManager * GetCASESessionManager() + { + return &mCASESessionManager; + } - Messaging::ExchangeManager & GetExchangeManager() { return mExchangeMgr; } + Messaging::ExchangeManager & GetExchangeManager() + { + return mExchangeMgr; + } - SessionManager & GetSecureSessionManager() { return mSessions; } + SessionManager & GetSecureSessionManager() + { + return mSessions; + } - SessionResumptionStorage * GetSessionResumptionStorage() { return mSessionResumptionStorage; } + SessionResumptionStorage * GetSessionResumptionStorage() + { + return mSessionResumptionStorage; + } - app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mSubscriptionResumptionStorage; } + app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() + { + return mSubscriptionResumptionStorage; + } - TransportMgrBase & GetTransportManager() { return mTransports; } + TransportMgrBase & GetTransportManager() + { + return mTransports; + } - Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } + Credentials::GroupDataProvider * GetGroupDataProvider() + { + return mGroupsProvider; + } - scenes::SceneTable * GetSceneTable() { return mSceneTable; } + scenes::SceneTable * GetSceneTable() + { + return mSceneTable; + } - Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } + Crypto::SessionKeystore * GetSessionKeystore() const + { + return mSessionKeystore; + } #if CONFIG_NETWORK_LAYER_BLE - Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } + Ble::BleLayer * GetBleLayerObject() + { + return mBleLayer; + } #endif - CommissioningWindowManager & GetCommissioningWindowManager() { return mCommissioningWindowManager; } + CommissioningWindowManager & GetCommissioningWindowManager() + { + return mCommissioningWindowManager; + } - PersistentStorageDelegate & GetPersistentStorage() { return *mDeviceStorage; } + PersistentStorageDelegate & GetPersistentStorage() + { + return *mDeviceStorage; + } - app::FailSafeContext & GetFailSafeContext() { return mFailSafeContext; } + app::FailSafeContext & GetFailSafeContext() + { + return mFailSafeContext; + } - TestEventTriggerDelegate * GetTestEventTriggerDelegate() { return mTestEventTriggerDelegate; } + TestEventTriggerDelegate * GetTestEventTriggerDelegate() + { + return mTestEventTriggerDelegate; + } - Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; } + Crypto::OperationalKeystore * GetOperationalKeystore() + { + return mOperationalKeystore; + } - Credentials::OperationalCertificateStore * GetOpCertStore() { return mOpCertStore; } + Credentials::OperationalCertificateStore * GetOpCertStore() + { + return mOpCertStore; + } - app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() { return mAttributePersister; } + app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() + { + return mAttributePersister; + } /** * This function causes the ShutDown event to be generated async on the @@ -397,7 +451,10 @@ class Server return System::SystemClock().GetMonotonicMicroseconds64() - mInitTimestamp; } - static Server & GetInstance() { return sServer; } + static Server & GetInstance() + { + return sServer; + } private: Server() = default; @@ -578,7 +635,7 @@ class Server app::SubscriptionResumptionStorage * mSubscriptionResumptionStorage; Credentials::CertificateValidityPolicy * mCertificateValidityPolicy; Credentials::GroupDataProvider * mGroupsProvider; - scenes::SceneTable * mSceneTable = nullptr; + scenes::SceneTable * mSceneTable = nullptr; Crypto::SessionKeystore * mSessionKeystore; app::DefaultAttributePersistenceProvider mAttributePersister; GroupDataProviderListener mListener; diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index f577bf3c4c1f18..b03a80b8a362e0 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -25,7 +25,7 @@ using namespace chip; -using SceneTable = scenes::SceneTable; +using SceneTable = scenes::SceneTable; using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; using SceneTableImpl = scenes::DefaultSceneTableImpl; using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; @@ -33,59 +33,60 @@ using SceneData = scenes::DefaultSceneTableImpl::SceneData; using ExtensionFieldsSet = scenes::ExtensionFieldsSet; using TransitionTimeMs = scenes::TransitionTimeMs; -#define ON_OFF_CID 0x0006 -#define LV_CTR_CID 0x0008 -#define CC_CTR_CID 0x0300 -#define TEST_ENDPOINT1 0x0001 -#define TEST_ENDPOINT2 0x0099 - -// ON OFF ATTRIBUTE IDs -#define ON_OFF_ID 0x0000 - -// LEVEL CONTROL ATTRIBUTE IDs -#define CURRENT_LVL_ID 0x0000 -#define CURRENT_FRQ_ID 0x0004 - -// COLOR CONTROL ATTRIBUTE IDs -#define CURRENT_SAT_ID 0x0001 -#define CURRENT_X_ID 0x0003 -#define CURRENT_Y_ID 0x0004 -#define COLOR_TEMP_MIR_ID 00007 -#define EN_CURRENT_HUE_ID 0x4000 -#define C_LOOP_ACTIVE_ID 0x4002 -#define C_LOOP_DIR_ID 0x4003 -#define C_LOOP_TIME_ID 0x4004 - namespace { +// Test Cluster ID +constexpr chip::ClusterId kOnOffClusterId = 0x0006; +constexpr chip::ClusterId kLevelControlClusterId = 0x0008; +constexpr chip::ClusterId kColorControlClusterId = 0x0300; + +// Test Endpoint ID +constexpr chip::EndpointId kTestEndpoint1 = 0x0001; +constexpr chip::EndpointId kTestEndpoint2 = 0x0099; +constexpr chip::EndpointId kTestEndpoint3 = 0x0010; + +// Test Attribute ID +constexpr uint32_t kOnOffAttId = 0x0000; +constexpr uint32_t kCurrentLevelId = 0x0000; +constexpr uint32_t kCurrentFrequencyId = 0x0004; +constexpr uint32_t kCurrentSaturationId = 0x0001; +constexpr uint32_t kCurrentXId = 0x0003; +constexpr uint32_t kCurrentYId = 0x0004; +constexpr uint32_t kColorTemperatureMiredsId = 0x0007; +constexpr uint32_t kEnhancedCurrentHueId = 0x4000; +constexpr uint32_t kColorLoopActiveId = 0x4002; +constexpr uint32_t kColorLoopDirectionId = 0x4003; +constexpr uint32_t kColorLoopTimeId = 0x4004; // Test fabrics, adding more requires to modify the "ResetSceneTable" function constexpr chip::FabricIndex kFabric1 = 1; constexpr chip::FabricIndex kFabric2 = 7; // Scene storage ID -static const SceneStorageId sceneId1(TEST_ENDPOINT1, 0xAA, 0x101); -static const SceneStorageId sceneId2(TEST_ENDPOINT1, 0xBB, 0x00); -static const SceneStorageId sceneId3(TEST_ENDPOINT2, 0xCC, 0x102); -static const SceneStorageId sceneId4(TEST_ENDPOINT2, 0xBE, 0x00); -static const SceneStorageId sceneId5(TEST_ENDPOINT1, 0x45, 0x103); -static const SceneStorageId sceneId6(TEST_ENDPOINT1, 0x65, 0x00); -static const SceneStorageId sceneId7(TEST_ENDPOINT1, 0x77, 0x101); -static const SceneStorageId sceneId8(TEST_ENDPOINT2, 0xEE, 0x101); -static const SceneStorageId sceneId9(TEST_ENDPOINT2, 0xAB, 0x101); +static const SceneStorageId sceneId1(kTestEndpoint1, 0xAA, 0x101); +static const SceneStorageId sceneId2(kTestEndpoint1, 0xBB, 0x00); +static const SceneStorageId sceneId3(kTestEndpoint2, 0xCC, 0x102); +static const SceneStorageId sceneId4(kTestEndpoint2, 0xBE, 0x00); +static const SceneStorageId sceneId5(kTestEndpoint1, 0x45, 0x103); +static const SceneStorageId sceneId6(kTestEndpoint1, 0x65, 0x00); +static const SceneStorageId sceneId7(kTestEndpoint1, 0x77, 0x101); +static const SceneStorageId sceneId8(kTestEndpoint3, 0xEE, 0x101); +static const SceneStorageId sceneId9(kTestEndpoint2, 0xAB, 0x101); + +CharSpan empty; // Scene data -static const SceneData sceneData1(CharSpan("Scene #1", sizeof("Scene #1"))); -static const SceneData sceneData2(CharSpan("Scene #2", sizeof("Scene #2")), 2, 5); -static const SceneData sceneData3(CharSpan("Scene #3", sizeof("Scene #3")), 25); -static const SceneData sceneData4(CharSpan("Scene num4", sizeof("Scene num4")), 5); -static const SceneData sceneData5(CharSpan(), 10); -static const SceneData sceneData6(CharSpan("Scene #6", sizeof("Scene #6")), 3, 15); -static const SceneData sceneData7(CharSpan("Scene #7", sizeof("Scene #7")), 20, 5); -static const SceneData sceneData8(CharSpan("NAME TOO LOOONNG", sizeof("Scene num4")), 10); -static const SceneData sceneData9(CharSpan("Scene #9", sizeof("Scene #9")), 30, 15); -static const SceneData sceneData10(CharSpan("Scene #10", sizeof("Scene #10")), 10, 1); -static const SceneData sceneData11(CharSpan("Scene #11", sizeof("Scene #11")), 20, 10); -static const SceneData sceneData12(CharSpan("Scene #12", sizeof("Scene #12")), 30, 5); +static const SceneData sceneData1(CharSpan("Scene #1")); +static const SceneData sceneData2(CharSpan("Scene #2"), 2, 5); +static const SceneData sceneData3(CharSpan("Scene #3"), 25); +static const SceneData sceneData4(CharSpan("Scene num4"), 5); +static const SceneData sceneData5(empty); +static const SceneData sceneData6(CharSpan("Scene #6"), 3, 15); +static const SceneData sceneData7(CharSpan("Scene #7"), 20, 5); +static const SceneData sceneData8(CharSpan("NAME TOO LOOONNG!"), 1, 10); +static const SceneData sceneData9(CharSpan("Scene #9"), 30, 15); +static const SceneData sceneData10(CharSpan("Scene #10"), 10, 1); +static const SceneData sceneData11(CharSpan("Scene #11"), 20, 10); +static const SceneData sceneData12(CharSpan("Scene #12"), 30, 5); // Scenes SceneTableEntry scene1(sceneId1, sceneData1); @@ -114,6 +115,10 @@ static uint8_t OO_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; static uint8_t LC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; +static uint32_t OO_buffer_serialized_length = 0; +static uint32_t LC_buffer_serialized_length = 0; +static uint32_t CC_buffer_serialized_length = 0; + /// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { @@ -125,47 +130,64 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) override { ClusterId * buffer = clusterBuffer.data(); - if (endpoint == TEST_ENDPOINT1) + if (endpoint == kTestEndpoint1) { if (clusterBuffer.size() >= 2) { - buffer[0] = ON_OFF_CID; - buffer[1] = LV_CTR_CID; + buffer[0] = kOnOffClusterId; + buffer[1] = kLevelControlClusterId; clusterBuffer.reduce_size(2); } } - else if (endpoint == TEST_ENDPOINT2) + else if (endpoint == kTestEndpoint2) { if (clusterBuffer.size() >= 2) { - buffer[0] = ON_OFF_CID; - buffer[1] = CC_CTR_CID; + buffer[0] = kOnOffClusterId; + buffer[1] = kColorControlClusterId; clusterBuffer.reduce_size(2); } } + else if (endpoint == kTestEndpoint3) + { + if (clusterBuffer.size() >= 3) + { + buffer[0] = kOnOffClusterId; + buffer[1] = kLevelControlClusterId; + buffer[2] = kColorControlClusterId; + clusterBuffer.reduce_size(3); + } + } } // Default function only checks if endpoint and clusters are valid bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override { - bool ret = false; - if (endpoint == TEST_ENDPOINT1) + if (endpoint == kTestEndpoint1) + { + if (cluster == kOnOffClusterId || cluster == kLevelControlClusterId) + { + return true; + } + } + + if (endpoint == kTestEndpoint2) { - if (cluster == ON_OFF_CID || cluster == LV_CTR_CID) + if (cluster == kOnOffClusterId || cluster == kColorControlClusterId) { - ret = true; + return true; } } - if (endpoint == TEST_ENDPOINT2) + if (endpoint == kTestEndpoint3) { - if (cluster == ON_OFF_CID || cluster == CC_CTR_CID) + if (cluster == kOnOffClusterId || cluster == kLevelControlClusterId || cluster == kColorControlClusterId) { - ret = true; + return true; } } - return ret; + return false; } /// @brief Simulates save from cluster, data is already in an EFS struct but this isn't mandatory @@ -177,41 +199,74 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; - if (endpoint == TEST_ENDPOINT1) + if (endpoint == kTestEndpoint1) { switch (cluster) { - case ON_OFF_CID: + case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(15); // Used memory for OnOff TLV + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV break; - case LV_CTR_CID: + case kLevelControlClusterId: err = CHIP_NO_ERROR; // Warning: LC_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(27); // Used memory for Level Control TLV + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(LC_buffer_serialized_length); // Used memory for Level Control TLV break; default: break; } } - if (endpoint == TEST_ENDPOINT2) + if (endpoint == kTestEndpoint2) { switch (cluster) { - case ON_OFF_CID: + case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(15); // Used memory for OnOff TLV + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV break; - case CC_CTR_CID: + case kColorControlClusterId: err = CHIP_NO_ERROR; // Warning: CC_buffer needs to be populated before calling this function memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(99); // Used memory for Color Control TLV + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(CC_buffer_serialized_length); // Used memory for Color Control TLV + break; + default: + break; + } + } + if (endpoint == kTestEndpoint3) + { + switch (cluster) + { + case kOnOffClusterId: + err = CHIP_NO_ERROR; + // Warning: OO_buffer needs to be populated before calling this function + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV + break; + case kLevelControlClusterId: + err = CHIP_NO_ERROR; + // Warning: LC_buffer needs to be populated before calling this function + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(LC_buffer_serialized_length); // Used memory for Level Control TLV + break; + case kColorControlClusterId: + err = CHIP_NO_ERROR; + // Warning: CC_buffer needs to be populated before calling this function + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + // Warning: serialized size of the buffer must also be computed before calling this function + serialisedBytes.reduce_size(CC_buffer_serialized_length); // Used memory for Color Control TLV break; default: break; @@ -233,17 +288,17 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; // Takes values from cluster in Endpoint 1 - if (endpoint == TEST_ENDPOINT1) + if (endpoint == kTestEndpoint1) { switch (cluster) { - case ON_OFF_CID: + case kOnOffClusterId: if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; - case LV_CTR_CID: + case kLevelControlClusterId: if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; @@ -255,17 +310,44 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl } // Takes values from cluster in Endpoint 2 - if (endpoint == TEST_ENDPOINT2) + if (endpoint == kTestEndpoint2) { switch (cluster) { - case ON_OFF_CID: + case kOnOffClusterId: if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; } break; - case CC_CTR_CID: + case kColorControlClusterId: + if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + default: + break; + } + } + + // Takes values from cluster in Endpoint 3 + if (endpoint == kTestEndpoint3) + { + switch (cluster) + { + case kOnOffClusterId: + if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) + { + err = CHIP_NO_ERROR; + } + break; + case kLevelControlClusterId: + if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) + { + err = CHIP_NO_ERROR; + } + case kColorControlClusterId: if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) { err = CHIP_NO_ERROR; @@ -300,6 +382,7 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == i); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[i])); } + // Hanlder order in table : [H0, H1, H2] NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxSceneHandlers); // Removal at beginning @@ -307,17 +390,25 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); // Confirm array was compressed and last position is now null NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + // Re-insert + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[0])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers)); + // Hanlder order in table : [H1, H2, H0] // Removal at the middle - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[3])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[2])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); // Confirm array was compressed and last position is now null - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 2]); + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + // Re-insert + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[2])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers)); + // Hanlder order in table : [H1, H0, H2] // Removal at the end - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[scenes::kMaxSceneHandlers - 1])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 3)); - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 3]); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[2])); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); + NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); // Emptying Handler array NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterAllHandler()); @@ -332,7 +423,6 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) // Verify all array is empty for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) { - printf("Handler : %d | Address : %p \n", i, sceneTable->mHandlers[i]); NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[i]); } } @@ -356,41 +446,41 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) static const uint8_t CC_av_payload[8][2] = { { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 } }; - OOPairs[0].attributeID.SetValue(ON_OFF_ID); + OOPairs[0].attributeID.SetValue(kOnOffAttId); OOPairs[0].attributeValue = OO_av_payload; - LCPairs[0].attributeID.SetValue(CURRENT_LVL_ID); + LCPairs[0].attributeID.SetValue(kCurrentLevelId); LCPairs[0].attributeValue = LC_av_payload[0]; LCPairs[0].attributeValue.reduce_size(1); - LCPairs[1].attributeID.SetValue(CURRENT_FRQ_ID); + LCPairs[1].attributeID.SetValue(kCurrentFrequencyId); LCPairs[1].attributeValue = LC_av_payload[1]; - CCPairs[0].attributeID.SetValue(CURRENT_SAT_ID); + CCPairs[0].attributeID.SetValue(kCurrentSaturationId); CCPairs[0].attributeValue = CC_av_payload[0]; CCPairs[0].attributeValue.reduce_size(1); - CCPairs[1].attributeID.SetValue(CURRENT_X_ID); + CCPairs[1].attributeID.SetValue(kCurrentXId); CCPairs[1].attributeValue = CC_av_payload[1]; - CCPairs[2].attributeID.SetValue(CURRENT_Y_ID); + CCPairs[2].attributeID.SetValue(kCurrentYId); CCPairs[2].attributeValue = CC_av_payload[2]; - CCPairs[3].attributeID.SetValue(COLOR_TEMP_MIR_ID); + CCPairs[3].attributeID.SetValue(kColorTemperatureMiredsId); CCPairs[3].attributeValue = CC_av_payload[3]; - CCPairs[4].attributeID.SetValue(EN_CURRENT_HUE_ID); + CCPairs[4].attributeID.SetValue(kEnhancedCurrentHueId); CCPairs[4].attributeValue = CC_av_payload[4]; - CCPairs[5].attributeID.SetValue(C_LOOP_ACTIVE_ID); + CCPairs[5].attributeID.SetValue(kColorLoopActiveId); CCPairs[5].attributeValue = CC_av_payload[5]; CCPairs[5].attributeValue.reduce_size(1); - CCPairs[6].attributeID.SetValue(C_LOOP_DIR_ID); + CCPairs[6].attributeID.SetValue(kColorLoopDirectionId); CCPairs[6].attributeValue = CC_av_payload[6]; CCPairs[6].attributeValue.reduce_size(1); - CCPairs[7].attributeID.SetValue(C_LOOP_TIME_ID); + CCPairs[7].attributeID.SetValue(kColorLoopTimeId); CCPairs[7].attributeValue = CC_av_payload[7]; // Initialize Extension Field sets as if they were received by add commands - OOextensionFieldSet.clusterID = ON_OFF_CID; + OOextensionFieldSet.clusterID = kOnOffClusterId; OOextensionFieldSet.attributeValueList = OOPairs; - LCextensionFieldSet.clusterID = LV_CTR_CID; + LCextensionFieldSet.clusterID = kLevelControlClusterId; LCextensionFieldSet.attributeValueList = LCPairs; - CCextensionFieldSet.clusterID = CC_CTR_CID; + CCextensionFieldSet.clusterID = kColorControlClusterId; CCextensionFieldSet.attributeValueList = CCPairs; ByteSpan OO_list(OO_buffer); @@ -410,6 +500,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), OOextensionFieldSet.attributeValueList)); writer.EndContainer(outer); + OO_buffer_serialized_length = writer.GetLengthWritten(); writer.Init(LC_buffer); writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); @@ -420,6 +511,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), LCextensionFieldSet.attributeValueList)); writer.EndContainer(outer); + LC_buffer_serialized_length = writer.GetLengthWritten(); writer.Init(CC_buffer); writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); @@ -430,6 +522,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), CCextensionFieldSet.attributeValueList)); writer.EndContainer(outer); + CC_buffer_serialized_length = writer.GetLengthWritten(); // Test Registering SceneHandler NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&sHandler)); @@ -437,54 +530,54 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Setup the On Off Extension field set in the expected state from a command reader.Init(OO_list); - extensionFieldSetIn.clusterID = ON_OFF_CID; + extensionFieldSetIn.clusterID = kOnOffClusterId; NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, tempCluster, buff_span, extensionFieldSetIn)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == ON_OFF_CID); + NL_TEST_ASSERT(aSuite, tempCluster == kOnOffClusterId); memset(buffer, 0, buff_span.size()); // Setup the Level Control Extension field set in the expected state from a command reader.Init(LC_list); - extensionFieldSetIn.clusterID = LV_CTR_CID; + extensionFieldSetIn.clusterID = kLevelControlClusterId; NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, tempCluster, buff_span, extensionFieldSetIn)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == LV_CTR_CID); + NL_TEST_ASSERT(aSuite, tempCluster == kLevelControlClusterId); memset(buffer, 0, buff_span.size()); // Setup the Color control Extension field set in the expected state from a command reader.Init(CC_list); - extensionFieldSetIn.clusterID = CC_CTR_CID; + extensionFieldSetIn.clusterID = kColorControlClusterId; NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(TEST_ENDPOINT2, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint2, tempCluster, buff_span, extensionFieldSetIn)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == CC_CTR_CID); + NL_TEST_ASSERT(aSuite, tempCluster == kColorControlClusterId); memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for on off - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT1, ON_OFF_CID, OO_list, extensionFieldSetOut)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint1, kOnOffClusterId, OO_list, extensionFieldSetOut)); // Verify Encoding the Extension field set returns the same data as the one serialized for on off previously writer.Init(buff_span); @@ -500,7 +593,8 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for level control - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT1, LV_CTR_CID, LC_list, extensionFieldSetOut)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint1, kLevelControlClusterId, LC_list, extensionFieldSetOut)); // Verify Encoding the Extension field set returns the same data as the one serialized for level control previously writer.Init(buff_span); @@ -516,7 +610,8 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for color control - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(TEST_ENDPOINT2, CC_CTR_CID, CC_list, extensionFieldSetOut)); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint2, kColorControlClusterId, CC_list, extensionFieldSetOut)); // Verify Encoding the Extension field set returns the same data as the one serialized for color control previously writer.Init(buff_span); @@ -549,11 +644,13 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Populate scene3's EFS (Endpoint2) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene3)); - // Populate scene3's EFS (Endpoint2) + // Populate scene4's EFS (Endpoint2) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene4)); - SceneTableEntry scene; + // Populate scene8's EFS (Endpoint3) + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneSaveEFS(scene8)); + SceneTableEntry scene; // Set test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); @@ -595,6 +692,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, scene == scene7); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); NL_TEST_ASSERT(aSuite, scene == scene8); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene8.mStorageId)); } void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 35fd670fa1c687..9007b629d81584 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1364,12 +1364,6 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #ifndef CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS #define CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS 2 #endif -/** - * @brief Indicates the absence of a Scene table entry. - */ -#ifndef CHIP_CONFIG_SCENES_TABLE_NULL_INDEX -#define CHIP_CONFIG_SCENES_TABLE_NULL_INDEX 0xFF -#endif /** * @brief Value used when setting or getting the endpoint in a Scene table @@ -1378,6 +1372,7 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #ifndef CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID #define CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID 0x00 #endif + /** * @brief The minimum number of scenes to support according to spec */ @@ -1386,26 +1381,12 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #endif /** - * @brief Maximum length of Scene names, not including the length byte. + * @brief Maximum length of Scene names */ #ifndef CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH #define CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH 16 #endif -/** - * @brief The group identifier for the global scene. - */ -#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID -#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID 0x0000 -#endif - -/** - * @brief The scene identifier for the global scene. - */ -#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID -#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID 0x00 -#endif - /** * @brief The maximum number of scenes allowed on a single fabric */ @@ -1414,10 +1395,10 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #endif /** - * @brief The maximum number of cluster per scene + * @brief The maximum number of clusters per scene */ #ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES -#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES 7 +#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES 3 #endif /** diff --git a/src/lib/core/DataModelTypes.h b/src/lib/core/DataModelTypes.h index 967deec0198bfe..8253a9017fbfcc 100644 --- a/src/lib/core/DataModelTypes.h +++ b/src/lib/core/DataModelTypes.h @@ -63,11 +63,6 @@ constexpr EndpointId kRootEndpointId = 0; constexpr ListIndex kInvalidListIndex = 0xFFFF; // List index is a uint16 thus 0xFFFF is a invalid list index. constexpr KeysetId kInvalidKeysetId = 0xFFFF; -constexpr SceneGroupID kGlobalGroupSceneId = CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID; -constexpr SceneIndex kUndefinedSceneIndex = 0xff; -constexpr SceneId kUndefinedSceneId = CHIP_CONFIG_SCENES_TABLE_NULL_INDEX; -constexpr SceneId kUnusedEndpointId = CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID; - // Invalid IC identifier is provisional. Value will most likely change when identifying token is defined // https://github.com/project-chip/connectedhomeip/issues/24251 constexpr uint64_t kInvalidIcId = 0; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index aa059a9630b110..b4fa1d602bdcca 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } @@ -197,15 +197,11 @@ class DefaultStorageKeyAllocator return StorageKeyName::Formatted("g/su/%x", static_cast(index)); } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } - // Scene Storage - static StorageKeyName SceneFabricList() - { - return StorageKeyName::FromConst("g/gfl"); - } // shares key with group fabric list to minimize flash usage + static StorageKeyName FabricScenesKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } static StorageKeyName FabricSceneKey(chip::FabricIndex fabric, uint8_t id) { - return StorageKeyName::Formatted("f/%x/s%x", fabric, id); + return StorageKeyName::Formatted("f/%x/s/%x", fabric, id); } }; diff --git a/src/lib/support/TestSceneTable.h b/src/lib/support/TestSceneTable.h deleted file mode 100644 index 5a8446351334bf..00000000000000 --- a/src/lib/support/TestSceneTable.h +++ /dev/null @@ -1,528 +0,0 @@ -/* - * - * Copyright (c) 2023 Project CHIP Authors - * All rights reserved. - * - * 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. - */ - -#pragma once - -#include - -namespace chip { - -namespace SceneTesting { - -using FabricIndex = chip::FabricIndex; -using SceneTableEntry = chip::scenes::DefaultSceneTableImpl::SceneTableEntry; -using SceneTable = chip::scenes::SceneTable; -using SceneTableImpl = chip::scenes::DefaultSceneTableImpl; -using SceneStorageId = chip::scenes::DefaultSceneTableImpl::SceneStorageId; -using SceneData = chip::scenes::DefaultSceneTableImpl::SceneData; -using ExtensionFieldsSet = chip::scenes::ExtensionFieldsSet; -using TransitionTimeMs = chip::scenes::TransitionTimeMs; - -#define ON_OFF_CID 0x0006 -#define LV_CTR_CID 0x0008 -#define CC_CTR_CID 0x0300 -#define TEST_ENDPOINT1 0x0001 -#define TEST_ENDPOINT2 0x0099 - -// ON OFF ATTRIBUTE IDs -#define ON_OFF_ID 0x0000 - -// LEVEL CONTROL ATTRIBUTE IDs -#define CURRENT_LVL_ID 0x0000 -#define CURRENT_FRQ_ID 0x0004 - -// COLOR CONTROL ATTRIBUTE IDs -#define CURRENT_SAT_ID 0x0001 -#define CURRENT_X_ID 0x0003 -#define CURRENT_Y_ID 0x0004 -#define COLOR_TEMP_MIR_ID 00007 -#define EN_CURRENT_HUE_ID 0x4000 -#define C_LOOP_ACTIVE_ID 0x4002 -#define C_LOOP_DIR_ID 0x4003 -#define C_LOOP_TIME_ID 0x4004 - -// Clusters EFS data -static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type OOextensionFieldSet; -static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type LCextensionFieldSet; -static app::Clusters::Scenes::Structs::ExtensionFieldSet::Type CCextensionFieldSet; - -static app::Clusters::Scenes::Structs::AttributeValuePair::Type OOPairs[1]; -static app::Clusters::Scenes::Structs::AttributeValuePair::Type LCPairs[2]; -static app::Clusters::Scenes::Structs::AttributeValuePair::Type CCPairs[8]; - -static uint8_t OO_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; -static uint8_t LC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; -static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; - -/// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control -class TestSceneHandler : public scenes::DefaultSceneHandlerImpl -{ -public: - TestSceneHandler() = default; - ~TestSceneHandler() override {} - - // Fills in cluster buffer and adjusts its size to lower than the maximum number of cluster per scenes - virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) override - { - ClusterId * buffer = clusterBuffer.data(); - if (endpoint == TEST_ENDPOINT1) - { - if (clusterBuffer.size() >= 2) - { - buffer[0] = ON_OFF_CID; - buffer[1] = LV_CTR_CID; - clusterBuffer.reduce_size(2); - } - } - else if (endpoint == TEST_ENDPOINT2) - { - if (clusterBuffer.size() >= 2) - { - buffer[0] = ON_OFF_CID; - buffer[1] = CC_CTR_CID; - clusterBuffer.reduce_size(2); - } - } - } - - // Default function only checks if endpoint and clusters are valid - bool SupportsCluster(EndpointId endpoint, ClusterId cluster) override - { - bool ret = false; - if (endpoint == TEST_ENDPOINT1) - { - if (cluster == ON_OFF_CID || cluster == LV_CTR_CID) - { - ret = true; - } - } - - if (endpoint == TEST_ENDPOINT2) - { - if (cluster == ON_OFF_CID || cluster == CC_CTR_CID) - { - ret = true; - } - } - - return ret; - } - - /// @brief Simulates save from cluster, data is already in an EFS struct but this isn't mandatory - /// @param endpoint target endpoint - /// @param cluster target cluster - /// @param serialisedBytes data to serialize into EFS - /// @return success if successfully serialized the data, CHIP_ERROR_INVALID_ARGUMENT if endpoint or cluster not supported - CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) override - { - CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; - - if (endpoint == TEST_ENDPOINT1) - { - switch (cluster) - { - case ON_OFF_CID: - err = CHIP_NO_ERROR; - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(15); // Used memory for OnOff TLV - break; - case LV_CTR_CID: - err = CHIP_NO_ERROR; - memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(27); // Used memory for Level Control TLV - break; - default: - break; - } - } - if (endpoint == TEST_ENDPOINT2) - { - switch (cluster) - { - case ON_OFF_CID: - err = CHIP_NO_ERROR; - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(15); // Used memory for OnOff TLV - break; - case CC_CTR_CID: - err = CHIP_NO_ERROR; - memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); - serialisedBytes.reduce_size(99); // Used memory for Color Control TLV - break; - default: - break; - } - } - return err; - } - - /// @brief Simulates EFS being applied to a scene, here just validates that the data is as expected, no action taken by the - /// "cluster" - /// @param endpoint target endpoint - /// @param cluster target cluster - /// @param serialisedBytes Data from nvm - /// @param timeMs transition time in ms - /// @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise - CHIP_ERROR - ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override - { - CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; - - // Takes values from cluster in Endpoint 1 - if (endpoint == TEST_ENDPOINT1) - { - switch (cluster) - { - case ON_OFF_CID: - if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) - { - err = CHIP_NO_ERROR; - } - break; - case LV_CTR_CID: - if (!memcmp(serialisedBytes.data(), LC_buffer, serialisedBytes.size())) - { - err = CHIP_NO_ERROR; - } - break; - default: - break; - } - } - - // Takes values from cluster in Endpoint 2 - if (endpoint == TEST_ENDPOINT2) - { - switch (cluster) - { - case ON_OFF_CID: - if (!memcmp(serialisedBytes.data(), OO_buffer, serialisedBytes.size())) - { - err = CHIP_NO_ERROR; - } - break; - case CC_CTR_CID: - if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) - { - err = CHIP_NO_ERROR; - } - break; - default: - break; - } - } - - return CHIP_NO_ERROR; - } -}; - -static TestSceneHandler sHandler; - -CHIP_ERROR scene_handler_test(SceneTable * provider) -{ - ClusterId tempCluster = 0; - - app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; - app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldSetIn; - app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; - - TLV::TLVReader reader; - TLV::TLVWriter writer; - TLV::TLVType outer; - TLV::TLVType outerRead; - - static const uint8_t OO_av_payload[1] = { 0x01 }; - static const uint8_t LC_av_payload[2][2] = { { 0x40, 0x00 }, { 0x01, 0xF0 } }; - static const uint8_t CC_av_payload[8][2] = { { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, - { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 }, { 0x00, 0x00 } }; - - OOPairs[0].attributeID.SetValue(ON_OFF_ID); - OOPairs[0].attributeValue = OO_av_payload; - - LCPairs[0].attributeID.SetValue(CURRENT_LVL_ID); - LCPairs[0].attributeValue = LC_av_payload[0]; - LCPairs[0].attributeValue.reduce_size(1); - LCPairs[1].attributeID.SetValue(CURRENT_FRQ_ID); - LCPairs[1].attributeValue = LC_av_payload[1]; - - CCPairs[0].attributeID.SetValue(CURRENT_SAT_ID); - CCPairs[0].attributeValue = CC_av_payload[0]; - CCPairs[0].attributeValue.reduce_size(1); - CCPairs[1].attributeID.SetValue(CURRENT_X_ID); - CCPairs[1].attributeValue = CC_av_payload[1]; - CCPairs[2].attributeID.SetValue(CURRENT_Y_ID); - CCPairs[2].attributeValue = CC_av_payload[2]; - CCPairs[3].attributeID.SetValue(COLOR_TEMP_MIR_ID); - CCPairs[3].attributeValue = CC_av_payload[3]; - CCPairs[4].attributeID.SetValue(EN_CURRENT_HUE_ID); - CCPairs[4].attributeValue = CC_av_payload[4]; - CCPairs[5].attributeID.SetValue(C_LOOP_ACTIVE_ID); - CCPairs[5].attributeValue = CC_av_payload[5]; - CCPairs[5].attributeValue.reduce_size(1); - CCPairs[6].attributeID.SetValue(C_LOOP_DIR_ID); - CCPairs[6].attributeValue = CC_av_payload[6]; - CCPairs[6].attributeValue.reduce_size(1); - CCPairs[7].attributeID.SetValue(C_LOOP_TIME_ID); - CCPairs[7].attributeValue = CC_av_payload[7]; - - // Initialize Extension Field sets as if they were received by add commands - OOextensionFieldSet.clusterID = ON_OFF_CID; - OOextensionFieldSet.attributeValueList = OOPairs; - LCextensionFieldSet.clusterID = LV_CTR_CID; - LCextensionFieldSet.attributeValueList = LCPairs; - CCextensionFieldSet.clusterID = CC_CTR_CID; - CCextensionFieldSet.attributeValueList = CCPairs; - - ByteSpan OO_list(OO_buffer); - ByteSpan LC_list(LC_buffer); - ByteSpan CC_list(CC_buffer); - - uint8_t buffer[scenes::kMaxFieldsPerCluster] = { 0 }; - MutableByteSpan buff_span(buffer); - - // Serialize Extension Field sets as if they were recovered from memory - writer.Init(OO_buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - OOextensionFieldSet.attributeValueList)); - writer.EndContainer(outer); - - writer.Init(LC_buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - LCextensionFieldSet.attributeValueList)); - writer.EndContainer(outer); - - writer.Init(CC_buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - CCextensionFieldSet.attributeValueList)); - writer.EndContainer(outer); - - ReturnErrorOnFailure(provider->RegisterHandler(&sHandler)); - - // Setup the On Off Extension field set in the expected state from a command - reader.Init(OO_list); - extensionFieldSetIn.clusterID = ON_OFF_CID; - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(reader.EnterContainer(outerRead)); - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); - ReturnErrorOnFailure(reader.ExitContainer(outerRead)); - - ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); - - // Verify the handler extracted buffer matches the initial field sets - VerifyOrReturnError(0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(tempCluster == ON_OFF_CID, CHIP_ERROR_WRITE_FAILED); - memset(buffer, 0, buff_span.size()); - - // Setup the Level Control Extension field set in the expected state from a command - reader.Init(LC_list); - extensionFieldSetIn.clusterID = LV_CTR_CID; - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(reader.EnterContainer(outerRead)); - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); - ReturnErrorOnFailure(reader.ExitContainer(outerRead)); - - ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT1, tempCluster, buff_span, extensionFieldSetIn)); - - // Verify the handler extracted buffer matches the initial field sets - VerifyOrReturnError(0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(tempCluster == LV_CTR_CID, CHIP_ERROR_WRITE_FAILED); - memset(buffer, 0, buff_span.size()); - - // Setup the Color control Extension field set in the expected state from a command - reader.Init(CC_list); - extensionFieldSetIn.clusterID = CC_CTR_CID; - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(reader.EnterContainer(outerRead)); - ReturnErrorOnFailure(reader.Next()); - ReturnErrorOnFailure(extensionFieldSetIn.attributeValueList.Decode(reader)); - ReturnErrorOnFailure(reader.ExitContainer(outerRead)); - - ReturnErrorOnFailure(sHandler.SerializeAdd(TEST_ENDPOINT2, tempCluster, buff_span, extensionFieldSetIn)); - - // Verify the handler extracted buffer matches the initial field sets - VerifyOrReturnError(0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(tempCluster == CC_CTR_CID, CHIP_ERROR_WRITE_FAILED); - memset(buffer, 0, buff_span.size()); - - // Verify Deserializing is properly filling out output extension field set for on off - ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT1, ON_OFF_CID, OO_list, extensionFieldSetOut)); - - // Verify Encoding the Extension field set returns the same data as - writer.Init(buff_span); - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - extensionFieldSetOut.attributeValueList)); - ReturnErrorOnFailure(writer.EndContainer(outer)); - VerifyOrReturnError(0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); - memset(buffer, 0, buff_span.size()); - - // Verify Deserializing is properly filling out output extension field set for level control - ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT1, LV_CTR_CID, LC_list, extensionFieldSetOut)); - - // Verify Encoding the Extension field set returns the same data as - writer.Init(buff_span); - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - extensionFieldSetOut.attributeValueList)); - ReturnErrorOnFailure(writer.EndContainer(outer)); - VerifyOrReturnError(0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); - memset(buffer, 0, buff_span.size()); - - // Verify Deserializing is properly filling out output extension field set for color control - ReturnErrorOnFailure(sHandler.Deserialize(TEST_ENDPOINT2, CC_CTR_CID, CC_list, extensionFieldSetOut)); - - // Verify Encoding the Extension field set returns the same data as - writer.Init(buff_span); - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); - ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), - extensionFieldSetOut.attributeValueList)); - ReturnErrorOnFailure(writer.EndContainer(outer)); - VerifyOrReturnError(0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size()), CHIP_ERROR_READ_FAILED); - memset(buffer, 0, buff_span.size()); - - return CHIP_NO_ERROR; -}; - -CHIP_ERROR scene_store_test(SceneTable * provider, FabricIndex fabric_index, SceneTableEntry & entry) -{ - SceneTableEntry temp; - - LogErrorOnFailure(provider->SetSceneTableEntry(fabric_index, entry)); - LogErrorOnFailure(provider->GetSceneTableEntry(fabric_index, entry.mStorageId, temp)); - VerifyOrReturnError(temp.mStorageId == entry.mStorageId, CHIP_ERROR_WRITE_FAILED); - VerifyOrReturnError(temp.mStorageData == entry.mStorageData, CHIP_ERROR_WRITE_FAILED); - LogErrorOnFailure(provider->SceneApplyEFS(fabric_index, temp.mStorageId)); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR scene_iterator_test(SceneTable * provider, FabricIndex fabric_index, const SceneTableEntry & entry1, - const SceneTableEntry & entry2, const SceneTableEntry & entry3) -{ - SceneTableEntry temp; - - auto * iterator = provider->IterateSceneEntry(fabric_index); - if (iterator) - { - VerifyOrReturnError(iterator->Count() == 3, CHIP_ERROR_INVALID_ARGUMENT); - - VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.mStorageId == entry1.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - - VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.mStorageId == entry2.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - - VerifyOrReturnError(iterator->Next(temp), CHIP_ERROR_INVALID_ACCESS_TOKEN); - VerifyOrReturnError(temp.mStorageId == entry3.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - - // Iterator should return false here - VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); - - iterator->Release(); - } - - return CHIP_NO_ERROR; -} - -CHIP_ERROR scene_remove_test(SceneTable * provider, FabricIndex fabric_index, SceneTableEntry & entry1, SceneTableEntry & entry2, - SceneTableEntry & entry3) -{ - SceneTableEntry temp; - - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry2.mStorageId)); - - auto * iterator = provider->IterateSceneEntry(fabric_index); - VerifyOrReturnError(iterator->Count() == 2, CHIP_ERROR_INVALID_ARGUMENT); - iterator->Next(temp); - VerifyOrReturnError(temp.mStorageId == entry1.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - iterator->Release(); - - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry1.mStorageId)); - iterator = provider->IterateSceneEntry(fabric_index); - VerifyOrReturnError(iterator->Count() == 1, CHIP_ERROR_INVALID_ARGUMENT); - iterator->Next(temp); - VerifyOrReturnError(temp.mStorageId == entry3.mStorageId, CHIP_ERROR_INVALID_ARGUMENT); - - LogErrorOnFailure(provider->RemoveSceneTableEntry(fabric_index, entry3.mStorageId)); - iterator = provider->IterateSceneEntry(fabric_index); - VerifyOrReturnError(iterator->Count() == 0, CHIP_ERROR_INVALID_ARGUMENT); - - // Iterator should return false here - VerifyOrReturnError(iterator->Next(temp) == false, CHIP_ERROR_INVALID_ACCESS_TOKEN); - iterator->Release(); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR TestSceneData(SceneTable * provider, FabricIndex fabric_index) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - // Scene storage ID - static const SceneStorageId sceneId1(TEST_ENDPOINT1, 0xAA, 0x101); - static const SceneStorageId sceneId2(TEST_ENDPOINT1, 0xBB, 0x00); - static const SceneStorageId sceneId3(TEST_ENDPOINT2, 0xCC, 0x102); - - // Scene data - static const SceneData sceneData1(CharSpan("Scene #1", sizeof("Scene #1"))); - static const SceneData sceneData2(CharSpan("Scene #2", sizeof("Scene #2")), 2, 5); - static const SceneData sceneData3(CharSpan(), 25); - - // Scenes - SceneTableEntry scene1(sceneId1, sceneData1); - SceneTableEntry scene2(sceneId2, sceneData2); - SceneTableEntry scene3(sceneId3, sceneData3); - - err = scene_handler_test(provider); - LogErrorOnFailure(err); - - err = provider->SceneSaveEFS(scene1); - LogErrorOnFailure(err); - - err = provider->SceneSaveEFS(scene3); - LogErrorOnFailure(err); - - // Tests - err = scene_store_test(provider, fabric_index, scene1); - LogErrorOnFailure(err); - err = scene_store_test(provider, fabric_index, scene2); - LogErrorOnFailure(err); - err = scene_store_test(provider, fabric_index, scene3); - LogErrorOnFailure(err); - - err = scene_iterator_test(provider, fabric_index, scene1, scene2, scene3); - LogErrorOnFailure(err); - err = scene_remove_test(provider, fabric_index, scene1, scene2, scene3); - LogErrorOnFailure(err); - - return err; -} - -} // namespace SceneTesting - -} // namespace chip From ae06c12c99571ee3b58f7683f9e08096a2388555 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 8 Mar 2023 10:53:44 -0500 Subject: [PATCH 41/79] Added comment to explicitely state the sharing of the key for the GroupFabricList in memory --- src/app/clusters/scenes/SceneTableImpl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index fcf976de12b874..7431d58f38ce24 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -34,6 +34,8 @@ using SceneData = DefaultSceneTableImpl::SceneData; struct FabricHavingSceneList : public CommonPersistentData::FabricList { + // This implementation uses the same key as the GroupFabricList from GroupDataProviderImpl to avoid duplicating the list in + // memory. If a different GroupDataProvider implementation is used, it will create the list in flash memory. CHIP_ERROR UpdateKey(StorageKeyName & key) override { key = DefaultStorageKeyAllocator::GroupFabricList(); From 11e75c590f7ed0f2b11f17b2136504267c6321bf Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:31:53 -0500 Subject: [PATCH 42/79] Update src/app/clusters/scenes/ExtensionFieldSetsImpl.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/ExtensionFieldSetsImpl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index c8af604c2e9060..802e321ea975ca 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -119,7 +119,7 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets uint8_t GetFieldNum() const override { return this->mFieldNum; }; // implementation - CHIP_ERROR InsertFieldSet(ExtensionFieldsSet & field); + CHIP_ERROR InsertFieldSet(const ExtensionFieldsSet & field); CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldsSet & field, uint8_t position); CHIP_ERROR RemoveFieldAtPosition(uint8_t position); From 637762d1273bfb5d45077568f4056f3fc2f59a86 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:32:33 -0500 Subject: [PATCH 43/79] Update src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 60cdad7cd96989..48f2d939f07675 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -93,7 +93,7 @@ CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet) break; } - if (this->mEFS[i].IsEmpty() && firstEmptyPosition == 0xFF) + if (this->mEFS[i].IsEmpty() && firstEmptyPosition == kInvalidPosition) { firstEmptyPosition = i; } From 78b9db49cb57bc8529fbc6b70a51d0839cf691af Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:34:32 -0500 Subject: [PATCH 44/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 906f1fc2179fb2..35e1de4ac5b3eb 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -91,7 +91,8 @@ class SceneHandler virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) = 0; - /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the functions responsability to + /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the function's responsibility to + /// resize the mutable span if necessary, a number of byte equal to the span will be stored in memory /// @param endpoint Target Endpoint /// @param cluster Target Cluster From 316d1db5a85c1431a9787565300340a2aa8726f5 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:37:46 -0500 Subject: [PATCH 45/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 35e1de4ac5b3eb..5fe40bb4fc255b 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -93,7 +93,8 @@ class SceneHandler /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the function's responsibility to - /// resize the mutable span if necessary, a number of byte equal to the span will be stored in memory + /// place the serialized data in serializedBytes as described below. + /// @param endpoint Target Endpoint /// @param cluster Target Cluster /// @param serialisedBytes Output buffer, data needs to be writen in there and size adjusted if smaller than From c2162a1d877e21dd955b74ffbddcaedd692911d0 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:38:10 -0500 Subject: [PATCH 46/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 5fe40bb4fc255b..5267e26d274143 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -97,8 +97,8 @@ class SceneHandler /// @param endpoint Target Endpoint /// @param cluster Target Cluster - /// @param serialisedBytes Output buffer, data needs to be writen in there and size adjusted if smaller than - /// kMaxFieldsPerCluster + /// @param serializedBytes Output buffer, data needs to be writen in there and size adjusted to the size of the data written. + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) = 0; From c1897070af7eec2e9c7b9ca23f0aa31030634326 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:38:50 -0500 Subject: [PATCH 47/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 5267e26d274143..725f8b1baa2c7f 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -100,7 +100,8 @@ class SceneHandler /// @param serializedBytes Output buffer, data needs to be writen in there and size adjusted to the size of the data written. /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serialisedBytes) = 0; + virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serializedBytes) = 0; + /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a cluster object /// @param endpoint Endpoint ID From ce0e5ce11b2691db09c86dad4481ca95f6bfb89d Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:39:35 -0500 Subject: [PATCH 48/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 725f8b1baa2c7f..d9932d17adf3a2 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -106,7 +106,8 @@ class SceneHandler /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a cluster object /// @param endpoint Endpoint ID /// @param cluster Cluster ID to save - /// @param serialisedBytes ExtensionFieldSet stored in NVM + /// @param serializedBytes ExtensionFieldSet stored in NVM + /// @param extensionFieldSet ExtensionFieldSet in command format /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, From 54af07f70be5462d8d85ed19445f91b8f27bed2a Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:40:08 -0500 Subject: [PATCH 49/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index d9932d17adf3a2..9a2122d1905042 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -110,7 +110,8 @@ class SceneHandler /// @param extensionFieldSet ExtensionFieldSet in command format /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, + app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; /// @brief From stored scene (e.g RecallScene), applies EFS values to cluster at transition time From 29e134f863dc460b815cc25c6c28fcfe28c959d3 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:41:01 -0500 Subject: [PATCH 50/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 9a2122d1905042..c17c4cc62b9101 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -117,7 +117,8 @@ class SceneHandler /// @brief From stored scene (e.g RecallScene), applies EFS values to cluster at transition time /// @param endpoint Endpoint ID /// @param cluster Cluster ID - /// @param serialisedBytes ExtensionFieldSet stored in NVM + /// @param serializedBytes ExtensionFieldSet stored in NVM + /// @param timeMs Transition time in ms to apply the scene /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) = 0; From 3f6d225d2717f71145254812634a512fb78251ff Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:42:18 -0500 Subject: [PATCH 51/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index c17c4cc62b9101..d90dade227ff29 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -121,7 +121,8 @@ class SceneHandler /// @param timeMs Transition time in ms to apply the scene /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) = 0; + virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, TransitionTimeMs timeMs) = 0; + }; template From 9b0f15b7bdbecd71ae7e21b849adfd92c1a9d4de Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:42:56 -0500 Subject: [PATCH 52/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index d90dade227ff29..8e01f0fa0f3101 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -285,7 +285,8 @@ class SceneTable // Iterators using SceneEntryIterator = CommonIterator; - virtual SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) = 0; + virtual SceneEntryIterator * IterateSceneEntries(FabricIndex fabric_index) = 0; + // Handlers virtual bool HandlerListEmpty() { return (mNumHandlers == 0); } From 5b7fe1fd25ea3645b4baeff99df91fd63fdf1c70 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:44:08 -0500 Subject: [PATCH 53/79] Update src/app/clusters/scenes/SceneTableImpl.cpp Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTableImpl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 7431d58f38ce24..01f8a0a72ec909 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -74,7 +74,7 @@ struct SceneTableData : public SceneTableEntry, PersistentData Date: Wed, 8 Mar 2023 13:44:56 -0500 Subject: [PATCH 54/79] Update src/app/clusters/scenes/SceneTable.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTable.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 8e01f0fa0f3101..d03e37583f26c4 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -273,7 +273,8 @@ class SceneTable // SceneHandlers virtual CHIP_ERROR RegisterHandler(SceneHandler * handler) = 0; virtual CHIP_ERROR UnregisterHandler(SceneHandler * handler) = 0; - virtual CHIP_ERROR UnregisterAllHandler() = 0; + virtual CHIP_ERROR UnregisterAllHandlers() = 0; + // Extension field sets operation virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; From 1c594cef8a509377df173056c9d3d08562190ce2 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:48:59 -0500 Subject: [PATCH 55/79] Apply suggestions from code review Co-authored-by: Boris Zbarsky --- src/lib/core/CHIPConfig.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 9007b629d81584..399712f228dede 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1397,7 +1397,7 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; /** * @brief The maximum number of clusters per scene */ -#ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES +#ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE #define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES 3 #endif From f666ab4f4e6b06ba80167bfd2fbb1be8069b050b Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Wed, 8 Mar 2023 13:48:59 -0500 Subject: [PATCH 56/79] Added unit test for ExtensionFieldSets and applied suggestions from comments on PR Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/ExtensionFieldSets.h | 11 +- .../scenes/ExtensionFieldSetsImpl.cpp | 73 ++--- .../clusters/scenes/ExtensionFieldSetsImpl.h | 109 ++++--- src/app/clusters/scenes/SceneTable.h | 104 +++--- src/app/clusters/scenes/SceneTableImpl.cpp | 67 ++-- src/app/clusters/scenes/SceneTableImpl.h | 49 +-- src/app/tests/BUILD.gn | 1 + src/app/tests/TestExtensionFieldSets.cpp | 308 ++++++++++++++++++ src/app/tests/TestSceneTable.cpp | 71 ++-- src/lib/core/CHIPConfig.h | 15 +- src/lib/core/DataModelTypes.h | 2 - src/lib/support/DefaultStorageKeyAllocator.h | 4 +- 12 files changed, 566 insertions(+), 248 deletions(-) create mode 100644 src/app/tests/TestExtensionFieldSets.cpp diff --git a/src/app/clusters/scenes/ExtensionFieldSets.h b/src/app/clusters/scenes/ExtensionFieldSets.h index 97bd4cd92c4b47..8c390a08fb521e 100644 --- a/src/app/clusters/scenes/ExtensionFieldSets.h +++ b/src/app/clusters/scenes/ExtensionFieldSets.h @@ -23,10 +23,11 @@ namespace chip { namespace scenes { -static constexpr uint8_t kInvalidPosition = 0xff; -static constexpr uint8_t kMaxClusterPerScenes = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; -static constexpr uint8_t kMaxFieldsPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; +static constexpr uint8_t kInvalidPosition = 0xff; +static constexpr uint8_t kMaxClusterPerScenes = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE; +static constexpr uint8_t kMaxFieldBytesPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; +/// @brief class meant serialize all extension ßfield sets of a scene so it can be stored and retrieved from flash memory. class ExtensionFieldSets { public: @@ -37,7 +38,9 @@ class ExtensionFieldSets virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; virtual void Clear() = 0; virtual bool IsEmpty() const = 0; - virtual uint8_t GetFieldNum() const = 0; + /// @brief Gets a count of how many initialized fields sets are in the object + /// @return The number of initialized field sets in the object + virtual uint8_t GetFieldSetCount() const = 0; }; } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 48f2d939f07675..7f8f7034ed19ea 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -20,20 +20,21 @@ namespace chip { namespace scenes { -ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldSets() {} +// ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldSets() {} CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(kTagEFSArrayContainer), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagEFSFieldNum), static_cast(this->mFieldNum))); - if (!this->IsEmpty()) + ReturnErrorOnFailure( + writer.StartContainer(TLV::ContextTag(TagEFS::kFieldSetArrayContainer), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kFieldSetsCount), static_cast(mFieldSetsCount))); + if (!IsEmpty()) { - for (uint8_t i = 0; i < this->mFieldNum; i++) + for (uint8_t i = 0; i < mFieldSetsCount; i++) { - if (!this->mEFS[i].IsEmpty()) + if (!mEFS[i].IsEmpty()) { - ReturnErrorOnFailure(this->mEFS[i].Serialize(writer)); + ReturnErrorOnFailure(mEFS[i].Serialize(writer)); } } } @@ -44,17 +45,17 @@ CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader) { TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagEFSArrayContainer))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(TagEFS::kFieldSetArrayContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFSFieldNum))); - ReturnErrorOnFailure(reader.Get(this->mFieldNum)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagEFS::kFieldSetsCount))); + ReturnErrorOnFailure(reader.Get(mFieldSetsCount)); if (!this->IsEmpty()) { - for (uint8_t i = 0; i < this->mFieldNum; i++) + for (uint8_t i = 0; i < mFieldSetsCount; i++) { - ReturnErrorOnFailure(this->mEFS[i].Deserialize(reader)); + ReturnErrorOnFailure(mEFS[i].Deserialize(reader)); } } @@ -65,61 +66,55 @@ void ExtensionFieldSetsImpl::Clear() { if (!this->IsEmpty()) { - for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < mFieldSetsCount; i++) { - this->mEFS[i].Clear(); + mEFS[i].Clear(); } } - this->mFieldNum = 0; + mFieldSetsCount = 0; } /// @brief Inserts a field Set set into the array of extension field Set sets for a scene entry. /// If the same ID is present in the EFS array, it will overwrite it. /// @param fieldSet field set to be inserted /// @return CHIP_NO_ERROR if insertion worked, CHIP_ERROR_NO_MEMORY if the array is already full -CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(ExtensionFieldsSet & fieldSet) +CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(const ExtensionFieldSet & fieldSet) { - CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; - uint8_t idPosition = kInvalidPosition; uint8_t firstEmptyPosition = kInvalidPosition; VerifyOrReturnError(fieldSet.mID != kInvalidClusterId, CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrReturnError(!fieldSet.IsEmpty(), CHIP_ERROR_INVALID_ARGUMENT); for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) { - if (this->mEFS[i].mID == fieldSet.mID) + if (mEFS[i].mID == fieldSet.mID) { - idPosition = i; - break; + mEFS[i] = fieldSet; + return CHIP_NO_ERROR; } - if (this->mEFS[i].IsEmpty() && firstEmptyPosition == kInvalidPosition) + if (mEFS[i].IsEmpty() && firstEmptyPosition == kInvalidPosition) { firstEmptyPosition = i; } } // if found, replace at found position, otherwise at insert first free position, otherwise return error - if (idPosition < kMaxClusterPerScenes) - { - this->mEFS[idPosition] = fieldSet; - err = CHIP_NO_ERROR; - } - else if (firstEmptyPosition < kMaxClusterPerScenes) + if (firstEmptyPosition < kMaxClusterPerScenes) { - this->mEFS[firstEmptyPosition] = fieldSet; - this->mFieldNum++; - err = CHIP_NO_ERROR; + mEFS[firstEmptyPosition] = fieldSet; + mFieldSetsCount++; + return CHIP_NO_ERROR; } - return err; + return CHIP_ERROR_NO_MEMORY; } -CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & fieldSet, uint8_t position) +CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fieldSet, uint8_t position) { - VerifyOrReturnError(position < this->mFieldNum, CHIP_ERROR_BUFFER_TOO_SMALL); + VerifyOrReturnError(position < mFieldSetsCount, CHIP_ERROR_BUFFER_TOO_SMALL); - fieldSet = this->mEFS[position]; + fieldSet = mEFS[position]; return CHIP_NO_ERROR; } @@ -127,18 +122,18 @@ CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldsSet & fi CHIP_ERROR ExtensionFieldSetsImpl::RemoveFieldAtPosition(uint8_t position) { VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnValue(!this->IsEmpty() && !this->mEFS[position].IsEmpty(), CHIP_NO_ERROR); + VerifyOrReturnValue(!this->IsEmpty() && !mEFS[position].IsEmpty(), CHIP_NO_ERROR); uint8_t nextPos = static_cast(position + 1); uint8_t moveNum = static_cast(kMaxClusterPerScenes - nextPos); // TODO: Implement general array management methods // Compress array after removal - memmove(&this->mEFS[position], &this->mEFS[nextPos], sizeof(ExtensionFieldsSet) * moveNum); + memmove(&mEFS[position], &mEFS[nextPos], sizeof(ExtensionFieldSet) * moveNum); - this->mFieldNum--; + mFieldSetsCount--; // Clear last occupied position - this->mEFS[mFieldNum].Clear(); // + mEFS[mFieldSetsCount].Clear(); // return CHIP_NO_ERROR; } diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 802e321ea975ca..7d9622e33f56df 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -23,49 +23,66 @@ namespace chip { namespace scenes { -enum EFSTLVTag +/// @brief Tags Used to serialize Extension Field Sets struct as well as individual field sets. +/// kArrayContainer: Tag for the container of the Struct with the EFS array +/// kFieldSetsCount: Tag representing the number of individual field sets +/// kIndividualContainer: Tag for the container of single EFS struct +/// kClusterID: Tag for the ClusterID of a field set +/// kBufferBytes: Tag for the serialized field set data +enum class TagEFS : uint8_t { - kTagEFSArrayContainer = 1, - kTagEFSFieldNum = 1, - kTagEFSContainer, - kTagEFSClusterID, - kTagEFS, + kFieldSetArrayContainer = 1, + kFieldSetsCount, + kIndividualContainer, + kClusterID, + kClusterFieldSetData, }; -using clusterId = chip::ClusterId; - -struct ExtensionFieldsSet +/// @brief Struct to serialize and de serialize a cluster extension field set +/// mID: Cluster ID, allows to identify which cluster is serialized +/// mBytesBuffer: Field ID serialized into a byte array +/// mUsedBytes: Number of bytes in the Buffer containing data, used for serializing only those bytes. +struct ExtensionFieldSet { - clusterId mID = kInvalidClusterId; - uint8_t mBytesBuffer[kMaxFieldsPerCluster] = { 0 }; - uint8_t mUsedBytes = 0; + ClusterId mID = kInvalidClusterId; + uint8_t mBytesBuffer[kMaxFieldBytesPerCluster] = { 0 }; + uint8_t mUsedBytes = 0; - ExtensionFieldsSet() = default; - ExtensionFieldsSet(clusterId cmID, const uint8_t * data, uint8_t dataSize) : mID(cmID), mUsedBytes(dataSize) + ExtensionFieldSet() = default; + ExtensionFieldSet(ClusterId cmID, const uint8_t * data, uint8_t dataSize) : mID(cmID), mUsedBytes(dataSize) { - if (dataSize <= kMaxFieldsPerCluster) + if (dataSize <= sizeof(mBytesBuffer)) { memcpy(mBytesBuffer, data, mUsedBytes); } + else + { + mUsedBytes = 0; + } } - ExtensionFieldsSet(clusterId cmID, ByteSpan bytes) : mID(cmID), mUsedBytes(static_cast(bytes.size())) + ExtensionFieldSet(ClusterId cmID, ByteSpan bytes) : mID(cmID), mUsedBytes(static_cast(bytes.size())) { - if (bytes.size() <= kMaxFieldsPerCluster) + if (bytes.size() <= sizeof(mBytesBuffer)) { memcpy(mBytesBuffer, bytes.data(), bytes.size()); } + else + { + mUsedBytes = 0; + } } - ~ExtensionFieldsSet() = default; + ~ExtensionFieldSet() = default; CHIP_ERROR Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(kTagEFSContainer), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure( + writer.StartContainer(TLV::ContextTag(TagEFS::kIndividualContainer), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagEFSClusterID), static_cast(this->mID))); - ReturnErrorOnFailure(writer.PutBytes(TLV::ContextTag(kTagEFS), mBytesBuffer, mUsedBytes)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kClusterID), static_cast(mID))); + ReturnErrorOnFailure(writer.PutBytes(TLV::ContextTag(TagEFS::kClusterFieldSetData), mBytesBuffer, mUsedBytes)); return writer.EndContainer(container); } @@ -74,58 +91,58 @@ struct ExtensionFieldsSet { ByteSpan buffer; TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(kTagEFSContainer))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(TagEFS::kIndividualContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFSClusterID))); - ReturnErrorOnFailure(reader.Get(this->mID)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagEFS::kClusterID))); + ReturnErrorOnFailure(reader.Get(mID)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagEFS))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagEFS::kClusterFieldSetData))); ReturnErrorOnFailure(reader.Get(buffer)); - VerifyOrReturnError(buffer.size() <= kMaxFieldsPerCluster, CHIP_ERROR_BUFFER_TOO_SMALL); - this->mUsedBytes = static_cast(buffer.size()); - memcpy(this->mBytesBuffer, buffer.data(), this->mUsedBytes); + VerifyOrReturnError(buffer.size() <= sizeof(mBytesBuffer), CHIP_ERROR_BUFFER_TOO_SMALL); + mUsedBytes = static_cast(buffer.size()); + memcpy(mBytesBuffer, buffer.data(), mUsedBytes); return reader.ExitContainer(container); } void Clear() { - this->mID = kInvalidClusterId; - memset(this->mBytesBuffer, 0, kMaxFieldsPerCluster); - this->mUsedBytes = 0; + mID = kInvalidClusterId; + memset(mBytesBuffer, 0, kMaxFieldBytesPerCluster); + mUsedBytes = 0; } bool IsEmpty() const { return (this->mUsedBytes == 0); } - bool operator==(const ExtensionFieldsSet & other) + bool operator==(const ExtensionFieldSet & other) const { - return (this->mID == other.mID && !memcmp(this->mBytesBuffer, other.mBytesBuffer, this->mUsedBytes) && - this->mUsedBytes == other.mUsedBytes); + return (this->mID == other.mID && this->mUsedBytes == other.mUsedBytes && + !memcmp(this->mBytesBuffer, other.mBytesBuffer, this->mUsedBytes)); } }; class ExtensionFieldSetsImpl : public ExtensionFieldSets { public: - ExtensionFieldSetsImpl(); + ExtensionFieldSetsImpl(){}; ~ExtensionFieldSetsImpl() override{}; // overrides CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override; CHIP_ERROR Deserialize(TLV::TLVReader & reader) override; void Clear() override; - bool IsEmpty() const override { return (this->mFieldNum == 0); } - uint8_t GetFieldNum() const override { return this->mFieldNum; }; + bool IsEmpty() const override { return (mFieldSetsCount == 0); } + uint8_t GetFieldSetCount() const override { return mFieldSetsCount; }; - // implementation - CHIP_ERROR InsertFieldSet(const ExtensionFieldsSet & field); - CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldsSet & field, uint8_t position); + CHIP_ERROR InsertFieldSet(const ExtensionFieldSet & field); + CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldSet & field, uint8_t position); CHIP_ERROR RemoveFieldAtPosition(uint8_t position); - bool operator==(const ExtensionFieldSetsImpl & other) + // implementation + bool operator==(const ExtensionFieldSetsImpl & other) const { - for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < mFieldSetsCount; i++) { if (!(this->mEFS[i] == other.mEFS[i])) { @@ -137,18 +154,18 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets ExtensionFieldSetsImpl & operator=(const ExtensionFieldSetsImpl & other) { - for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < other.mFieldSetsCount; i++) { this->mEFS[i] = other.mEFS[i]; } - mFieldNum = other.mFieldNum; + mFieldSetsCount = other.mFieldSetsCount; return *this; } protected: - ExtensionFieldsSet mEFS[kMaxClusterPerScenes]; - uint8_t mFieldNum = 0; + ExtensionFieldSet mEFS[kMaxClusterPerScenes]; + uint8_t mFieldSetsCount = 0; }; } // namespace scenes } // namespace chip diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index d03e37583f26c4..50a89221d60969 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -17,50 +17,38 @@ #pragma once #include -#include +#include #include #include #include #include -/** - * @brief Indicates the absence of a Scene table entry. - */ -#ifndef CHIP_CONFIG_SCENES_TABLE_NULL_INDEX -#define CHIP_CONFIG_SCENES_TABLE_NULL_INDEX 0xFF -#endif - -/** - * @brief The group identifier for the global scene. - */ -#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID -#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID 0x0000 -#endif - -/** - * @brief The scene identifier for the global scene. - */ -#ifndef CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID -#define CHIP_CONFIG_SCENES_GLOBAL_SCENE_SCENE_ID 0x00 -#endif - namespace chip { namespace scenes { +// Storage index for scenes in nvm +typedef uint8_t SceneIndex; + typedef uint32_t TransitionTimeMs; typedef uint16_t SceneTransitionTime; typedef uint8_t TransitionTime100ms; -constexpr SceneGroupID kGlobalGroupSceneId = CHIP_CONFIG_SCENES_GLOBAL_SCENE_GROUP_ID; +constexpr GroupId kGlobalGroupSceneId = 0x0000; constexpr SceneIndex kUndefinedSceneIndex = 0xff; -constexpr SceneId kUndefinedSceneId = CHIP_CONFIG_SCENES_TABLE_NULL_INDEX; +constexpr SceneId kUndefinedSceneId = 0xff; static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; -static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES; static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; +// Handler's are meant to retrieve a single cluster's extension field set, therefore the maximum number allowed is the maximal +// number of extension field set. +static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE; + /// @brief Abstract class allowing different Endpoints interactions with the ExtensionFieldSets added to and retrieved from the -/// scene Table +/// scene Table. The Scene Handler's are meant as interface between various clusters and the Scene table. The expected behaviour of +/// the table with the handler is: Once a scene command involving extension field set is received, the Scene Table will go through +/// the list of handlers to either retrieve, populate or apply Extension field sets. Each handler is meant to retrieve an extension +/// field set for a single cluster however it is also possible to use a single generic handler that handles all of them. class SceneHandler { public: @@ -83,46 +71,48 @@ class SceneHandler virtual bool SupportsCluster(EndpointId endpoint, ClusterId cluster) = 0; /// @brief From command AddScene, allows handler to filter through clusters in command to serialize only the supported ones. - /// @param endpoint Endpoint ID - /// @param cluster Cluster ID to fetch from command - /// @param serialisedBytes Buffer for ExtensionFieldSet in command - /// @param extensionFieldSet ExtensionFieldSets provided by the AddScene Command + /// @param endpoint[in] Endpoint ID + /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized + /// @param cluster[out] Cluster in the Extension field set, filled by the function + /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, - app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) = 0; + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, + const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, + ClusterId & cluster, MutableByteSpan & serialisedBytes) = 0; - /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the function's responsibility to + /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the function's responsibility + /// to /// place the serialized data in serializedBytes as described below. - /// @param endpoint Target Endpoint - /// @param cluster Target Cluster - /// @param serializedBytes Output buffer, data needs to be writen in there and size adjusted to the size of the data written. + /// @param endpoint[in] Target Endpoint + /// @param cluster[in] Target Cluster + /// @param serializedBytes[out] Output buffer, data needs to be writen in there and size adjusted to the size of the data + /// written. /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serializedBytes) = 0; - /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a cluster object - /// @param endpoint Endpoint ID - /// @param cluster Cluster ID to save - /// @param serializedBytes ExtensionFieldSet stored in NVM + /// @param endpoint[in] Endpoint ID + /// @param cluster[in] Cluster ID to save + /// @param serializedBytes[in] ExtensionFieldSet stored in NVM - /// @param extensionFieldSet ExtensionFieldSet in command format + /// @param extensionFieldSet[out] ExtensionFieldSet in command format /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; /// @brief From stored scene (e.g RecallScene), applies EFS values to cluster at transition time - /// @param endpoint Endpoint ID - /// @param cluster Cluster ID - /// @param serializedBytes ExtensionFieldSet stored in NVM + /// @param endpoint[in] Endpoint ID + /// @param cluster[in] Cluster ID + /// @param serializedBytes[in] ExtensionFieldSet stored in NVM - /// @param timeMs Transition time in ms to apply the scene + /// @param timeMs[in] Transition time in ms to apply the scene /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, TransitionTimeMs timeMs) = 0; - + virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, + TransitionTimeMs timeMs) = 0; }; template @@ -135,11 +125,11 @@ class SceneTable // Identifies endpoint to which this scene applies EndpointId mEndpointId = kInvalidEndpointId; // Identifies group within the scope of the given fabric - SceneGroupID mGroupId = kGlobalGroupSceneId; - SceneId mSceneId = kUndefinedSceneId; + GroupId mGroupId = kGlobalGroupSceneId; + SceneId mSceneId = kUndefinedSceneId; SceneStorageId() = default; - SceneStorageId(EndpointId endpoint, SceneId id, SceneGroupID groupId = kGlobalGroupSceneId) : + SceneStorageId(EndpointId endpoint, SceneId id, GroupId groupId = kGlobalGroupSceneId) : mEndpointId(endpoint), mGroupId(groupId), mSceneId(id) {} @@ -157,6 +147,13 @@ class SceneTable }; /// @brief struct used to store data held in a scene + /// Members: + /// mName: char buffer holding the name of the scene, only serialized when mNameLenght is greater than 0 + /// mNameLength: lentgh of the name if a name was provided at scene creation + /// mSceneTransitionTimeSeconds: Time in seconds it will take a cluster to change to the scene + /// mExtensionFieldSets: class holding the different field sets of each cluster values to store with the scene + /// mTransitionTime100ms: Transition time in tenths of a second, allows for more precise transition when combiened with + /// mSceneTransitionTimeSeconds in enhanced scene commands struct SceneData { char mName[kSceneNameMax] = { 0 }; @@ -211,7 +208,7 @@ class SceneTable bool operator==(const SceneData & other) { - return (!memcmp(this->mName, other.mName, this->mNameLength) && + return (this->mNameLength == other.mNameLength && !memcmp(this->mName, other.mName, this->mNameLength) && (this->mSceneTransitionTimeSeconds == other.mSceneTransitionTimeSeconds) && (this->mTransitionTime100ms == other.mTransitionTime100ms) && (this->mExtensionFieldSets == other.mExtensionFieldSets)); @@ -229,7 +226,6 @@ class SceneTable /// @brief Struct combining both ID and data of a table entry struct SceneTableEntry { - // ID SceneStorageId mStorageId; @@ -268,14 +264,13 @@ class SceneTable virtual CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) = 0; virtual CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) = 0; virtual CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) = 0; - virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) = 0; + virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) = 0; // SceneHandlers virtual CHIP_ERROR RegisterHandler(SceneHandler * handler) = 0; virtual CHIP_ERROR UnregisterHandler(SceneHandler * handler) = 0; virtual CHIP_ERROR UnregisterAllHandlers() = 0; - // Extension field sets operation virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; virtual CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) = 0; @@ -288,7 +283,6 @@ class SceneTable virtual SceneEntryIterator * IterateSceneEntries(FabricIndex fabric_index) = 0; - // Handlers virtual bool HandlerListEmpty() { return (mNumHandlers == 0); } virtual bool HandlerListFull() { return (mNumHandlers >= kMaxSceneHandlers); } diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 01f8a0a72ec909..05ace24ad50b29 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -79,21 +79,21 @@ struct SceneTableData : public SceneTableEntry, PersistentData(mStorageId.mEndpointId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(mStorageId.mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(mStorageId.mSceneId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), static_cast(mStorageId.mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), static_cast(mStorageId.mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), static_cast(mStorageId.mSceneId))); // Scene Data // A length of 0 means the name wasn't used so it won't get stored - if (!NameSpan.empty()) + if (!nameSpan.empty()) { - ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(kTagSceneName), NameSpan)); + ReturnErrorOnFailure(writer.PutString(TLV::ContextTag(TagScene::kName), nameSpan)); } + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kTransitionTime), + static_cast(mStorageData.mSceneTransitionTimeSeconds))); ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(kTagSceneDTransitionTime), static_cast(mStorageData.mSceneTransitionTimeSeconds))); - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(kTagSceneDTransitionTime100), static_cast(mStorageData.mTransitionTime100ms))); + writer.Put(TLV::ContextTag(TagScene::kTransitionTime100), static_cast(mStorageData.mTransitionTime100ms))); ReturnErrorOnFailure(mStorageData.mExtensionFieldSets.Serialize(writer)); return writer.EndContainer(container); @@ -101,7 +101,7 @@ struct SceneTableData : public SceneTableEntry, PersistentData CHIP_ERROR UpdateKey(StorageKeyName & key) override { VerifyOrReturnError(kUndefinedFabricIndex != fabric_index, CHIP_ERROR_INVALID_FABRIC_INDEX); - key = DefaultStorageKeyAllocator::FabricScenesKey(fabric_index); + key = DefaultStorageKeyAllocator::FabricSceneDataKey(fabric_index); return CHIP_NO_ERROR; } @@ -186,9 +186,10 @@ struct FabricSceneData : public PersistentData // Storing the scene map for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneEndpointID), static_cast(scene_map[i].mEndpointId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneGroupID), static_cast(scene_map[i].mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneID), static_cast(scene_map[i].mSceneId))); + ReturnErrorOnFailure( + writer.Put(TLV::ContextTag(TagScene::kEndpointID), static_cast(scene_map[i].mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), static_cast(scene_map[i].mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), static_cast(scene_map[i].mSceneId))); } ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNext), static_cast(next))); @@ -207,11 +208,11 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(reader.Get(scene_count)); for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneEndpointID))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kEndpointID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mEndpointId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneGroupID))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kGroupID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mGroupId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneID))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mSceneId)); } ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNext))); @@ -445,10 +446,10 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index /// @param fabric_index Fabric in which the scene belongs /// @param scened_idx Position in the Scene Table /// @return CHIP_NO_ERROR if removal was successful, errors if failed to remove the scene or to update the fabric after removing it -CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) +CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) { FabricSceneData fabric(fabric_index); - SceneTableData scene(fabric_index, scened_idx); + SceneTableData scene(fabric_index, scene_idx); ReturnErrorOnFailure(scene.Delete(mStorage)); @@ -533,7 +534,7 @@ CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) return CHIP_NO_ERROR; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterAllHandler() +CHIP_ERROR DefaultSceneTableImpl::UnregisterAllHandlers() { for (uint8_t i = 0; i < this->mNumHandlers; i++) { @@ -556,8 +557,8 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) this->mHandlers[i]->GetSupportedClusters(scene.mStorageId.mEndpointId, cSpan); for (uint8_t j = 0; j < cSpan.size(); j++) { - ExtensionFieldsSet EFS; - MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldsPerCluster); + ExtensionFieldSet EFS; + MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); EFS.mID = cArray[j]; ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); @@ -575,7 +576,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const { FabricSceneData fabric(fabric_index); SceneTableData scene(fabric_index); - ExtensionFieldsSet EFS; + ExtensionFieldSet EFS; TransitionTimeMs time; clusterId cluster; @@ -585,7 +586,7 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const if (!this->HandlerListEmpty()) { - for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldSets.GetFieldNum(); i++) + for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldSets.GetFieldSetCount(); i++) { scene.mStorageData.mExtensionFieldSets.GetFieldSetAtPosition(EFS, i); cluster = EFS.mID; @@ -624,7 +625,7 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) return fabric.Delete(mStorage); } -DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntry(FabricIndex fabric_index) +DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntries(FabricIndex fabric_index) { VerifyOrReturnError(IsInitialized(), nullptr); return mSceneEntryIterators.CreateObject(*this, fabric_index); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 2a66b41d47ad95..419cab78e9a601 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -16,6 +16,7 @@ */ #pragma once +#include #include #include #include @@ -25,16 +26,21 @@ namespace chip { namespace scenes { -enum SceneTLVTag +/// @brief Tags Used to serialize Scenes so they can be stored in flash memory. +/// kEndpointID: Tag for the Endpoint ID to which this scene applies to +/// kGroupID: Tag for GroupID if the Scene is a Group Scene +/// kID: Tag for the scene ID together with the two previous tag, forms the SceneStorageID +/// kName: Tag for the name of the scene +/// kTransitionTime: Tag for the transition time of the scene in seconds +/// kTransitionTime100: Tag for the transition time of the scene in tenth of a second (enhanced scenes) +enum class TagScene : uint8_t { - kTagSceneStorageIDContainer = 1, - kTagSceneEndpointID, - kTagSceneGroupID, - kTagSceneID, - kTagSceneDataContainer, - kTagSceneName, - kTagSceneDTransitionTime, - kTagSceneDTransitionTime100, + kEndpointID = 1, + kGroupID, + kID, + kName, + kTransitionTime, + kTransitionTime100, }; using clusterId = chip::ClusterId; @@ -53,14 +59,15 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler DefaultSceneHandlerImpl() = default; ~DefaultSceneHandlerImpl() override{}; - /// @brief Function to serialize data from an add scene command, assume the incoming extensionFieldSet is initialized - /// @param endpoint Target Endpoint - /// @param cluster Cluster in the Extension field set, filled by the function - /// @param serialisedBytes Mutable Byte span to hold EFS data from command - /// @param extensionFieldSet Extension field set from commmand, pre initialized - /// @return CHIP_NO_ERROR if success, specific CHIP_ERROR otherwise - virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, ClusterId & cluster, MutableByteSpan & serialisedBytes, - app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet) override + /// @brief From command AddScene, allows handler to filter through clusters in command to serialize only the supported ones. + /// @param endpoint[in] Endpoint ID + /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized + /// @param cluster[out] Cluster in the Extension field set, filled by the function + /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, + const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, + ClusterId & cluster, MutableByteSpan & serialisedBytes) override { app::DataModel::List attributeValueList; app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; @@ -115,7 +122,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @param cluster target cluster /// @param serialisedBytes data to deserialize into EFS /// @return CHIP_NO_ERROR if Extension Field Set was successfully populated, specific CHIP_ERROR otherwise - virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, + virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) override { app::DataModel::DecodableList attributeValueList; @@ -192,12 +199,12 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR SetSceneTableEntry(FabricIndex fabric_index, const SceneTableEntry & entry) override; CHIP_ERROR GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) override; CHIP_ERROR RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) override; - CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scened_idx) override; + CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) override; // SceneHandlers CHIP_ERROR RegisterHandler(SceneHandler * handler) override; CHIP_ERROR UnregisterHandler(SceneHandler * handler) override; - CHIP_ERROR UnregisterAllHandler() override; + CHIP_ERROR UnregisterAllHandlers() override; // Extension field sets operation CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) override; @@ -207,7 +214,7 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; // Iterators - SceneEntryIterator * IterateSceneEntry(FabricIndex fabric_index) override; + SceneEntryIterator * IterateSceneEntries(FabricIndex fabric_index) override; protected: class SceneEntryIteratorImpl : public SceneEntryIterator diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index a0b580bc93c65c..999691688c86f2 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -115,6 +115,7 @@ chip_test_suite("tests") { "TestEventLoggingNoUTCTime.cpp", "TestEventOverflow.cpp", "TestEventPathParams.cpp", + "TestExtensionFieldSets.cpp", "TestFabricScopedEventLogging.cpp", "TestInteractionModelEngine.cpp", "TestMessageDef.cpp", diff --git a/src/app/tests/TestExtensionFieldSets.cpp b/src/app/tests/TestExtensionFieldSets.cpp new file mode 100644 index 00000000000000..900ffc1e25249f --- /dev/null +++ b/src/app/tests/TestExtensionFieldSets.cpp @@ -0,0 +1,308 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * All rights reserved. + * + * 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. + */ + +#include +#include +#include +#include +#include + +using namespace chip; + +namespace { + +static constexpr size_t kPersistentSceneBufferMax = 256; + +// Test Cluster ID +constexpr chip::ClusterId kOnOffClusterId = 0x0006; +constexpr chip::ClusterId kLevelControlClusterId = 0x0008; +constexpr chip::ClusterId kColorControlClusterId = 0x0300; + +constexpr uint8_t kOnOffSize = 1; +constexpr uint8_t kLevelControlSize = 3; +constexpr uint8_t kColorControlSize = 14; + +static uint8_t onOffBuffer[scenes::kMaxFieldBytesPerCluster] = "0"; +static uint8_t levelControlBuffer[scenes::kMaxFieldBytesPerCluster] = "123"; +static uint8_t colorControlBuffer[scenes::kMaxFieldBytesPerCluster] = "abcdefghijklmn"; + +static const scenes::ExtensionFieldSet EFS1(kOnOffClusterId, onOffBuffer, kOnOffSize); +static const scenes::ExtensionFieldSet EFS2(kLevelControlClusterId, levelControlBuffer, kLevelControlSize); +static const scenes::ExtensionFieldSet EFS3(kColorControlClusterId, colorControlBuffer, kColorControlSize); + +static scenes::ExtensionFieldSetsImpl sEFSets; + +void TestInsertExtensionFieldSet(nlTestSuite * aSuite, void * aContext) +{ + scenes::ExtensionFieldSetsImpl * EFS = &sEFSets; + scenes::ExtensionFieldSet tempEFS; + + uint8_t empty_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + uint8_t double_size_buffer[scenes::kMaxFieldBytesPerCluster * 2]; + ByteSpan bufferSpan(double_size_buffer); + + memset(double_size_buffer, static_cast(1), sizeof(double_size_buffer)); + + NL_TEST_ASSERT(aSuite, true == EFS->IsEmpty()); + + // Test creators of single ExtensionFieldSet + NL_TEST_ASSERT(aSuite, EFS1.mID == kOnOffClusterId); + NL_TEST_ASSERT(aSuite, EFS1.mUsedBytes == kOnOffSize); + NL_TEST_ASSERT(aSuite, !memcmp(onOffBuffer, EFS1.mBytesBuffer, EFS1.mUsedBytes)); + + NL_TEST_ASSERT(aSuite, EFS2.mID == kLevelControlClusterId); + NL_TEST_ASSERT(aSuite, EFS2.mUsedBytes == kLevelControlSize); + NL_TEST_ASSERT(aSuite, !memcmp(levelControlBuffer, EFS2.mBytesBuffer, EFS2.mUsedBytes)); + + NL_TEST_ASSERT(aSuite, EFS3.mID == kColorControlClusterId); + NL_TEST_ASSERT(aSuite, EFS3.mUsedBytes == kColorControlSize); + NL_TEST_ASSERT(aSuite, !memcmp(colorControlBuffer, EFS3.mBytesBuffer, EFS3.mUsedBytes)); + + // Test creation of EFS from Array and ByteSpan that are to big + tempEFS = scenes::ExtensionFieldSet(kOnOffClusterId, double_size_buffer, sizeof(double_size_buffer)); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kOnOffClusterId); + // Confirm EFS empty + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == 0); + NL_TEST_ASSERT(aSuite, !memcmp(empty_buffer, tempEFS.mBytesBuffer, sizeof(empty_buffer))); + + tempEFS = scenes::ExtensionFieldSet(kLevelControlClusterId, bufferSpan); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kLevelControlClusterId); + // Confirm EFS empty + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == 0); + NL_TEST_ASSERT(aSuite, !memcmp(empty_buffer, tempEFS.mBytesBuffer, sizeof(empty_buffer))); + + // Test creation of EFS from truncating an Array + tempEFS = scenes::ExtensionFieldSet(kColorControlClusterId, double_size_buffer, sizeof(tempEFS.mBytesBuffer)); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kColorControlClusterId); + // Confirm EFS was written + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == static_cast(sizeof(tempEFS.mBytesBuffer))); + NL_TEST_ASSERT(aSuite, !memcmp(double_size_buffer, tempEFS.mBytesBuffer, sizeof(tempEFS.mBytesBuffer))); + + // Test clear EFS + tempEFS.Clear(); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kInvalidClusterId); + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == 0); + NL_TEST_ASSERT(aSuite, !memcmp(empty_buffer, tempEFS.mBytesBuffer, sizeof(tempEFS.mBytesBuffer))); + + // Test insertion of uninitialized EFS + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == EFS->InsertFieldSet(tempEFS)); + NL_TEST_ASSERT(aSuite, 0 == EFS->GetFieldSetCount()); + + // Test insertion of empty EFS + tempEFS.mID = kOnOffClusterId; + NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == EFS->InsertFieldSet(tempEFS)); + NL_TEST_ASSERT(aSuite, 0 == EFS->GetFieldSetCount()); + + // Test insert + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS1)); + NL_TEST_ASSERT(aSuite, 1 == EFS->GetFieldSetCount()); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS2)); + NL_TEST_ASSERT(aSuite, 2 == EFS->GetFieldSetCount()); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS3)); + NL_TEST_ASSERT(aSuite, 3 == EFS->GetFieldSetCount()); + + // Test get + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 0)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 1)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 2)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); +} + +void TestSerializeDerializeExtensionFieldSet(nlTestSuite * aSuite, void * aContext) +{ + scenes::ExtensionFieldSetsImpl * EFS = &sEFSets; + scenes::ExtensionFieldSetsImpl testSceneEFS; + + scenes::ExtensionFieldSet tempEFS; + + uint8_t EFS1Buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + uint8_t EFS2Buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + uint8_t EFS3Buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + uint8_t sceneEFSBuffer[kPersistentSceneBufferMax] = { 0 }; + + uint32_t EFS1_serialized_length = 0; + uint32_t EFS2_serialized_length = 0; + uint32_t EFS3_serialized_length = 0; + uint32_t sceneEFS_serialized_length = 0; + + TLV::TLVReader reader; + TLV::TLVWriter writer; + TLV::TLVType outer; + TLV::TLVType outerRead; + + // Individual Field Sets serialize / deserialize + writer.Init(EFS1Buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS1.Serialize(writer)); + writer.EndContainer(outer); + EFS1_serialized_length = writer.GetLengthWritten(); + NL_TEST_ASSERT(aSuite, EFS1_serialized_length <= scenes::kMaxFieldBytesPerCluster); + + writer.Init(EFS2Buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS2.Serialize(writer)); + writer.EndContainer(outer); + EFS2_serialized_length = writer.GetLengthWritten(); + NL_TEST_ASSERT(aSuite, EFS2_serialized_length <= scenes::kMaxFieldBytesPerCluster); + + writer.Init(EFS3Buffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS3.Serialize(writer)); + writer.EndContainer(outer); + EFS3_serialized_length = writer.GetLengthWritten(); + NL_TEST_ASSERT(aSuite, EFS3_serialized_length <= scenes::kMaxFieldBytesPerCluster); + + reader.Init(EFS1Buffer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == tempEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + NL_TEST_ASSERT(aSuite, EFS1 == tempEFS); + + reader.Init(EFS2Buffer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == tempEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + NL_TEST_ASSERT(aSuite, EFS2 == tempEFS); + + reader.Init(EFS3Buffer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == tempEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + NL_TEST_ASSERT(aSuite, EFS3 == tempEFS); + + // All ExtensionFieldSets serialize / deserialize + writer.Init(sceneEFSBuffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->Serialize(writer)); + writer.EndContainer(outer); + sceneEFS_serialized_length = writer.GetLengthWritten(); + NL_TEST_ASSERT(aSuite, sceneEFS_serialized_length <= kPersistentSceneBufferMax); + + reader.Init(sceneEFSBuffer); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testSceneEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); + NL_TEST_ASSERT(aSuite, *EFS == testSceneEFS); +} + +void TestRemoveExtensionFieldSet(nlTestSuite * aSuite, void * aContext) +{ + scenes::ExtensionFieldSetsImpl * EFS = &sEFSets; + scenes::ExtensionFieldSet tempEFS; + + // Order in EFS at this point: [EFS1, EFS2, EFS3] + // Removal at beginning + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->RemoveFieldAtPosition(0)); + NL_TEST_ASSERT(aSuite, 2 == EFS->GetFieldSetCount()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS1)); + NL_TEST_ASSERT(aSuite, 3 == EFS->GetFieldSetCount()); + + // Verify order + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 0)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 1)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 2)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + + // Order in EFS at this point: [EFS2, EFS3, EFS1] + // Removal at middle + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->RemoveFieldAtPosition(1)); + NL_TEST_ASSERT(aSuite, 2 == EFS->GetFieldSetCount()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS3)); + NL_TEST_ASSERT(aSuite, 3 == EFS->GetFieldSetCount()); + + // Verify order + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 0)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 1)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 2)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); + + // Order in EFS at this point: [EFS2, EFS1, EFS3] + // Removal at end + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->RemoveFieldAtPosition(2)); + NL_TEST_ASSERT(aSuite, 2 == EFS->GetFieldSetCount()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS3)); + NL_TEST_ASSERT(aSuite, 3 == EFS->GetFieldSetCount()); + + // Verify order + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 0)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 1)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->GetFieldSetAtPosition(tempEFS, 2)); + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); + + // Emptying the table + EFS->Clear(); + NL_TEST_ASSERT(aSuite, true == EFS->IsEmpty()); +} + +} // namespace +/** + * Tear down the test suite. + */ +int TestSetup(void * inContext) +{ + VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); + + return SUCCESS; +} + +/** + * Tear down the test suite. + */ +int TestTeardown(void * inContext) +{ + chip::Platform::MemoryShutdown(); + + return SUCCESS; +} + +int TestExtensionFieldSets() +{ + static nlTest sTests[] = { NL_TEST_DEF("TestInsertExtensionFieldSet", TestInsertExtensionFieldSet), + NL_TEST_DEF("TestSerializeDerializeExtensionFieldSet", TestSerializeDerializeExtensionFieldSet), + NL_TEST_DEF("TestRemoveExtensionFieldSet", TestRemoveExtensionFieldSet), + + NL_TEST_SENTINEL() }; + + nlTestSuite theSuite = { + "SceneTable", + &sTests[0], + TestSetup, + TestTeardown, + }; + + nlTestRunner(&theSuite, nullptr); + return (nlTestRunnerStats(&theSuite)); +} + +CHIP_REGISTER_TEST_SUITE(TestExtensionFieldSets) \ No newline at end of file diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index b03a80b8a362e0..7f776e6f3639ec 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -25,13 +25,13 @@ using namespace chip; -using SceneTable = scenes::SceneTable; -using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; -using SceneTableImpl = scenes::DefaultSceneTableImpl; -using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; -using SceneData = scenes::DefaultSceneTableImpl::SceneData; -using ExtensionFieldsSet = scenes::ExtensionFieldsSet; -using TransitionTimeMs = scenes::TransitionTimeMs; +using SceneTable = scenes::SceneTable; +using SceneTableEntry = scenes::DefaultSceneTableImpl::SceneTableEntry; +using SceneTableImpl = scenes::DefaultSceneTableImpl; +using SceneStorageId = scenes::DefaultSceneTableImpl::SceneStorageId; +using SceneData = scenes::DefaultSceneTableImpl::SceneData; +using ExtensionFieldSet = scenes::ExtensionFieldSet; +using TransitionTimeMs = scenes::TransitionTimeMs; namespace { // Test Cluster ID @@ -111,9 +111,9 @@ static app::Clusters::Scenes::Structs::AttributeValuePair::Type OOPairs[1]; static app::Clusters::Scenes::Structs::AttributeValuePair::Type LCPairs[2]; static app::Clusters::Scenes::Structs::AttributeValuePair::Type CCPairs[8]; -static uint8_t OO_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; -static uint8_t LC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; -static uint8_t CC_buffer[scenes::kMaxFieldsPerCluster] = { 0 }; +static uint8_t OO_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; +static uint8_t LC_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; +static uint8_t CC_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; static uint32_t OO_buffer_serialized_length = 0; static uint32_t LC_buffer_serialized_length = 0; @@ -206,14 +206,14 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldBytesPerCluster); // Warning: serialized size of the buffer must also be computed before calling this function serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV break; case kLevelControlClusterId: err = CHIP_NO_ERROR; // Warning: LC_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldBytesPerCluster); // Warning: serialized size of the buffer must also be computed before calling this function serialisedBytes.reduce_size(LC_buffer_serialized_length); // Used memory for Level Control TLV break; @@ -228,14 +228,14 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldBytesPerCluster); // Warning: serialized size of the buffer must also be computed before calling this function serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV break; case kColorControlClusterId: err = CHIP_NO_ERROR; // Warning: CC_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldBytesPerCluster); // Warning: serialized size of the buffer must also be computed before calling this function serialisedBytes.reduce_size(CC_buffer_serialized_length); // Used memory for Color Control TLV break; @@ -250,21 +250,21 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl case kOnOffClusterId: err = CHIP_NO_ERROR; // Warning: OO_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), OO_buffer, scenes::kMaxFieldBytesPerCluster); // Warning: serialized size of the buffer must also be computed before calling this function serialisedBytes.reduce_size(OO_buffer_serialized_length); // Used memory for OnOff TLV break; case kLevelControlClusterId: err = CHIP_NO_ERROR; // Warning: LC_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), LC_buffer, scenes::kMaxFieldBytesPerCluster); // Warning: serialized size of the buffer must also be computed before calling this function serialisedBytes.reduce_size(LC_buffer_serialized_length); // Used memory for Level Control TLV break; case kColorControlClusterId: err = CHIP_NO_ERROR; // Warning: CC_buffer needs to be populated before calling this function - memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldsPerCluster); + memcpy(serialisedBytes.data(), CC_buffer, scenes::kMaxFieldBytesPerCluster); // Warning: serialized size of the buffer must also be computed before calling this function serialisedBytes.reduce_size(CC_buffer_serialized_length); // Used memory for Color Control TLV break; @@ -283,7 +283,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl /// @param timeMs transition time in ms /// @return CHIP_NO_ERROR if value as expected, CHIP_ERROR_INVALID_ARGUMENT otherwise CHIP_ERROR - ApplyScene(EndpointId endpoint, ClusterId cluster, ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override + ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serialisedBytes, TransitionTimeMs timeMs) override { CHIP_ERROR err = CHIP_ERROR_INVALID_ARGUMENT; @@ -411,7 +411,7 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); // Emptying Handler array - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterAllHandler()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterAllHandlers()); for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) { NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[i])); @@ -487,7 +487,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) ByteSpan LC_list(LC_buffer); ByteSpan CC_list(CC_buffer); - uint8_t buffer[scenes::kMaxFieldsPerCluster] = { 0 }; + uint8_t buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; MutableByteSpan buff_span(buffer); // Serialize Extension Field sets as if they were recovered from memory @@ -537,7 +537,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldSetIn, tempCluster, buff_span)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size())); @@ -553,7 +553,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldSetIn, tempCluster, buff_span)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size())); @@ -569,7 +569,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint2, tempCluster, buff_span, extensionFieldSetIn)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint2, extensionFieldSetIn, tempCluster, buff_span)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size())); @@ -725,7 +725,7 @@ void TestIterateScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, sceneTable); SceneTableEntry scene; - auto * iterator = sceneTable->IterateSceneEntry(kFabric1); + auto * iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator != nullptr); @@ -764,7 +764,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove middle NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene5.mStorageId)); - auto * iterator = sceneTable->IterateSceneEntry(kFabric1); + auto * iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); @@ -772,7 +772,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Add scene in middle, a spot should have been freed NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene9)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 8); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId9, scene)); NL_TEST_ASSERT(aSuite, scene == scene9); @@ -780,7 +780,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove the recently added scene 9 NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene9.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 7); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene10); @@ -788,7 +788,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove first NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 6); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene2); @@ -796,7 +796,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove Next NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene3.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 5); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene2); @@ -805,28 +805,28 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene2.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 4); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene4); iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene4.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 3); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene6); iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene6.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 2); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene7); iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene7.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 1); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); NL_TEST_ASSERT(aSuite, scene == scene12); @@ -834,14 +834,14 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove last NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); NL_TEST_ASSERT(aSuite, iterator->Next(scene) == false); iterator->Release(); NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); - iterator = sceneTable->IterateSceneEntry(kFabric1); + iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); iterator->Release(); } @@ -927,6 +927,7 @@ int TestTeardown(void * inContext) return SUCCESS; } + int TestSceneTable() { static nlTest sTests[] = { NL_TEST_DEF("TestHandlerRegistration", TestHandlerRegistration), diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 399712f228dede..ff13a20a6db647 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1365,14 +1365,6 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_MAX_SUBSCRIPTION_RESUMPTION_STORAGE_CONCURRENT_ITERATORS 2 #endif -/** - * @brief Value used when setting or getting the endpoint in a Scene table - * entry. It indicates that the entry is not in use. - */ -#ifndef CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID -#define CHIP_CONFIG_SCENES_TABLE_UNUSED_ENDPOINT_ID 0x00 -#endif - /** * @brief The minimum number of scenes to support according to spec */ @@ -1398,14 +1390,15 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; * @brief The maximum number of clusters per scene */ #ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE -#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES 3 -#endif +#define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE 3 +#endif + /** * @brief The maximum size of a single extension field set for a single cluster */ #ifndef CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER -#define CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER 100 +#define CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER 128 #endif /** diff --git a/src/lib/core/DataModelTypes.h b/src/lib/core/DataModelTypes.h index 8253a9017fbfcc..5ae16fa51f6544 100644 --- a/src/lib/core/DataModelTypes.h +++ b/src/lib/core/DataModelTypes.h @@ -40,7 +40,6 @@ typedef uint32_t EventId; typedef uint64_t EventNumber; typedef uint64_t FabricId; typedef uint8_t FabricIndex; -typedef uint8_t SceneIndex; typedef uint32_t FieldId; typedef uint16_t ListIndex; typedef uint16_t LocalizedStringIdentifier; @@ -48,7 +47,6 @@ typedef uint32_t TransactionId; typedef uint16_t KeysetId; typedef uint8_t InteractionModelRevision; typedef uint32_t SubscriptionId; -typedef GroupId SceneGroupID; typedef uint8_t SceneId; constexpr CompressedFabricId kUndefinedCompressedFabricId = 0ULL; diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index b4fa1d602bdcca..3348335488df8f 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -198,10 +198,10 @@ class DefaultStorageKeyAllocator } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } - static StorageKeyName FabricScenesKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } + static StorageKeyName FabricSceneDataKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } static StorageKeyName FabricSceneKey(chip::FabricIndex fabric, uint8_t id) { - return StorageKeyName::Formatted("f/%x/s/%x", fabric, id); + return StorageKeyName::Formatted("f/%x/sc/%x", fabric, id); } }; From 1824d427c8f7c9a49f0e5582afcd85936ec5c021 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 9 Mar 2023 20:12:32 +0000 Subject: [PATCH 57/79] Restyled by whitespace --- src/app/tests/TestExtensionFieldSets.cpp | 2 +- src/lib/core/CHIPConfig.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/tests/TestExtensionFieldSets.cpp b/src/app/tests/TestExtensionFieldSets.cpp index 900ffc1e25249f..718e151acb6d21 100644 --- a/src/app/tests/TestExtensionFieldSets.cpp +++ b/src/app/tests/TestExtensionFieldSets.cpp @@ -305,4 +305,4 @@ int TestExtensionFieldSets() return (nlTestRunnerStats(&theSuite)); } -CHIP_REGISTER_TEST_SUITE(TestExtensionFieldSets) \ No newline at end of file +CHIP_REGISTER_TEST_SUITE(TestExtensionFieldSets) diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index ff13a20a6db647..867d22da43cbdc 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1391,7 +1391,7 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; */ #ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE #define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE 3 -#endif +#endif /** From 7b67b3c9af3c5ec9f7804595a3c78d5e40a3f78d Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 9 Mar 2023 20:12:43 +0000 Subject: [PATCH 58/79] Restyled by clang-format --- src/app/server/Server.h | 99 +++++--------------- src/lib/core/CHIPConfig.h | 1 - src/lib/support/DefaultStorageKeyAllocator.h | 2 +- 3 files changed, 22 insertions(+), 80 deletions(-) diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 03d4caaa9c2be0..18d2d2b948f55f 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -91,7 +91,7 @@ struct ServerInitParams ServerInitParams() = default; // Not copyable - ServerInitParams(const ServerInitParams &) = delete; + ServerInitParams(const ServerInitParams &) = delete; ServerInitParams & operator=(const ServerInitParams &) = delete; // Application delegate to handle some commissioning lifecycle events @@ -209,7 +209,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams CommonCaseDeviceServerInitParams() = default; // Not copyable - CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; + CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; CommonCaseDeviceServerInitParams & operator=(const CommonCaseDeviceServerInitParams &) = delete; /** @@ -344,97 +344,43 @@ class Server */ void RejoinExistingMulticastGroups(); - FabricTable & GetFabricTable() - { - return mFabrics; - } + FabricTable & GetFabricTable() { return mFabrics; } - CASESessionManager * GetCASESessionManager() - { - return &mCASESessionManager; - } + CASESessionManager * GetCASESessionManager() { return &mCASESessionManager; } - Messaging::ExchangeManager & GetExchangeManager() - { - return mExchangeMgr; - } + Messaging::ExchangeManager & GetExchangeManager() { return mExchangeMgr; } - SessionManager & GetSecureSessionManager() - { - return mSessions; - } + SessionManager & GetSecureSessionManager() { return mSessions; } - SessionResumptionStorage * GetSessionResumptionStorage() - { - return mSessionResumptionStorage; - } + SessionResumptionStorage * GetSessionResumptionStorage() { return mSessionResumptionStorage; } - app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() - { - return mSubscriptionResumptionStorage; - } + app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mSubscriptionResumptionStorage; } - TransportMgrBase & GetTransportManager() - { - return mTransports; - } + TransportMgrBase & GetTransportManager() { return mTransports; } - Credentials::GroupDataProvider * GetGroupDataProvider() - { - return mGroupsProvider; - } + Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } - scenes::SceneTable * GetSceneTable() - { - return mSceneTable; - } + scenes::SceneTable * GetSceneTable() { return mSceneTable; } - Crypto::SessionKeystore * GetSessionKeystore() const - { - return mSessionKeystore; - } + Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } #if CONFIG_NETWORK_LAYER_BLE - Ble::BleLayer * GetBleLayerObject() - { - return mBleLayer; - } + Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } #endif - CommissioningWindowManager & GetCommissioningWindowManager() - { - return mCommissioningWindowManager; - } + CommissioningWindowManager & GetCommissioningWindowManager() { return mCommissioningWindowManager; } - PersistentStorageDelegate & GetPersistentStorage() - { - return *mDeviceStorage; - } + PersistentStorageDelegate & GetPersistentStorage() { return *mDeviceStorage; } - app::FailSafeContext & GetFailSafeContext() - { - return mFailSafeContext; - } + app::FailSafeContext & GetFailSafeContext() { return mFailSafeContext; } - TestEventTriggerDelegate * GetTestEventTriggerDelegate() - { - return mTestEventTriggerDelegate; - } + TestEventTriggerDelegate * GetTestEventTriggerDelegate() { return mTestEventTriggerDelegate; } - Crypto::OperationalKeystore * GetOperationalKeystore() - { - return mOperationalKeystore; - } + Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; } - Credentials::OperationalCertificateStore * GetOpCertStore() - { - return mOpCertStore; - } + Credentials::OperationalCertificateStore * GetOpCertStore() { return mOpCertStore; } - app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() - { - return mAttributePersister; - } + app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() { return mAttributePersister; } /** * This function causes the ShutDown event to be generated async on the @@ -451,10 +397,7 @@ class Server return System::SystemClock().GetMonotonicMicroseconds64() - mInitTimestamp; } - static Server & GetInstance() - { - return sServer; - } + static Server & GetInstance() { return sServer; } private: Server() = default; diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 867d22da43cbdc..96de94294d1df4 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1393,7 +1393,6 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE 3 #endif - /** * @brief The maximum size of a single extension field set for a single cluster */ diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index 3348335488df8f..bee51293b22ef2 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } From a1b70c113c7369c0511e2bf7424721936b7aa493 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Thu, 9 Mar 2023 15:53:28 -0500 Subject: [PATCH 59/79] Apply suggestions from code review Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/SceneTableImpl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 05ace24ad50b29..cf1ddc9280a199 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -123,7 +123,7 @@ struct SceneTableData : public SceneTableEntry, PersistentData Date: Fri, 10 Mar 2023 18:04:18 -0500 Subject: [PATCH 60/79] Added testing to validate interaction with group table, removed useless casts, addressed problem on change on maximum scene changes --- src/app/clusters/scenes/SceneTableImpl.cpp | 139 +++++++++-------- src/app/clusters/scenes/SceneTableImpl.h | 2 +- src/app/tests/TestSceneTable.cpp | 172 ++++++++++++++++++++- 3 files changed, 247 insertions(+), 66 deletions(-) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index cf1ddc9280a199..af67496def2686 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -22,10 +22,13 @@ namespace chip { namespace scenes { -enum SceneImplTLVTag +/// @brief Tags Used to serialize Scene specific Fabric data +/// kSceneCount: Tag for the number of scenes in Fabric +/// kGroupID: Tag for the next Fabric +enum class TagSceneImpl : uint8_t { - kTagSceneCount = 1, - kTagNext, + kSceneCount = 1, + kNextFabric, }; using SceneTableEntry = DefaultSceneTableImpl::SceneTableEntry; @@ -79,9 +82,9 @@ struct SceneTableData : public SceneTableEntry, PersistentData(mStorageId.mEndpointId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), static_cast(mStorageId.mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), static_cast(mStorageId.mSceneId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), mStorageId.mEndpointId)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), mStorageId.mGroupId)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), mStorageId.mSceneId)); // Scene Data // A length of 0 means the name wasn't used so it won't get stored @@ -90,10 +93,8 @@ struct SceneTableData : public SceneTableEntry, PersistentData(mStorageData.mSceneTransitionTimeSeconds))); - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(TagScene::kTransitionTime100), static_cast(mStorageData.mTransitionTime100ms))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kTransitionTime), mStorageData.mSceneTransitionTimeSeconds)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kTransitionTime100), mStorageData.mTransitionTime100ms)); ReturnErrorOnFailure(mStorageData.mExtensionFieldSets.Serialize(writer)); return writer.EndContainer(container); @@ -101,7 +102,8 @@ struct SceneTableData : public SceneTableEntry, PersistentData TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagSceneCount), static_cast(scene_count))); - + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kSceneCount), (scene_count))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kNextFabric), (next))); // Storing the scene map for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { - ReturnErrorOnFailure( - writer.Put(TLV::ContextTag(TagScene::kEndpointID), static_cast(scene_map[i].mEndpointId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), static_cast(scene_map[i].mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), static_cast(scene_map[i].mSceneId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), (scene_map[i].mEndpointId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), (scene_map[i].mGroupId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), (scene_map[i].mSceneId))); } - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(kTagNext), static_cast(next))); return writer.EndContainer(container); } CHIP_ERROR Deserialize(TLV::TLVReader & reader) override { - ReturnErrorOnFailure(reader.Next(TLV::AnonymousTag())); - VerifyOrReturnError(TLV::kTLVType_Structure == reader.GetType(), CHIP_ERROR_INTERNAL); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); TLV::TLVType container; ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagSceneCount))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagSceneImpl::kSceneCount))); ReturnErrorOnFailure(reader.Get(scene_count)); - for (uint8_t i = 0; i < kMaxScenePerFabric; i++) + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagSceneImpl::kNextFabric))); + ReturnErrorOnFailure(reader.Get(next)); + + uint8_t i = 0; + while (reader.Next(TLV::ContextTag(TagScene::kEndpointID)) != CHIP_END_OF_TLV) { - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kEndpointID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mEndpointId)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kGroupID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mGroupId)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mSceneId)); + + i++; } - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(kTagNext))); - ReturnErrorOnFailure(reader.Get(next)); return reader.ExitContainer(container); } @@ -263,7 +265,8 @@ struct FabricSceneData : public PersistentData { FabricHavingSceneList fabric_list; CHIP_ERROR err = fabric_list.Load(storage); - VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); + VerifyOrReturnValue(CHIP_ERROR_NOT_FOUND != err, CHIP_NO_ERROR); + ReturnErrorOnFailure(err); // Existing fabric list, search for existing entry FabricSceneData fabric(fabric_list.first_entry); @@ -347,7 +350,7 @@ struct FabricSceneData : public PersistentData CHIP_ERROR SaveScene(PersistentStorageDelegate * storage, const SceneTableEntry & entry) { - CHIP_ERROR err; + CHIP_ERROR err = CHIP_NO_ERROR; SceneTableData scene(fabric_index, entry.mStorageId, entry.mStorageData); // Look for empty storage space @@ -355,7 +358,6 @@ struct FabricSceneData : public PersistentData if (CHIP_NO_ERROR == err) { - return scene.Save(storage); } @@ -365,7 +367,17 @@ struct FabricSceneData : public PersistentData scene_map[scene.index] = scene.mStorageId; ReturnErrorOnFailure(this->Save(storage)); - return scene.Save(storage); + err = scene.Save(storage); + + // on failure to save the scene, undoes the changes to Fabric Scene Data + if (err != CHIP_NO_ERROR) + { + scene_count--; + scene_map[scene.index].Clear(); + ReturnErrorOnFailure(this->Save(storage)); + } + + return err; } return CHIP_ERROR_INVALID_LIST_LENGTH; @@ -373,20 +385,30 @@ struct FabricSceneData : public PersistentData CHIP_ERROR RemoveScene(PersistentStorageDelegate * storage, const SceneStorageId & scene_id) { + CHIP_ERROR err = CHIP_NO_ERROR; SceneTableData scene(fabric_index, scene_id); - // Look for empty storage space - - VerifyOrReturnError(this->Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); - ReturnErrorOnFailure(scene.Delete(storage)); + // Empty Scene Fabric Data returns CHIP_NO_ERROR on remove if (scene_count > 0) { + // If Find doesn't return CHIP_NO_ERROR, the scene wasn't found, which doesn't return an error + VerifyOrReturnValue(this->Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_NO_ERROR); + scene_count--; scene_map[scene.index].Clear(); ReturnErrorOnFailure(this->Save(storage)); - } - return CHIP_NO_ERROR; + err = scene.Delete(storage); + + // On failure to delete scene, undoes the change to the Fabric Scene Data + if (err != CHIP_NO_ERROR) + { + scene_count++; + scene_map[scene.index] = scene.mStorageId; + ReturnErrorOnFailure(this->Save(storage)); + } + } + return err; } }; @@ -448,18 +470,16 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index /// @return CHIP_NO_ERROR if removal was successful, errors if failed to remove the scene or to update the fabric after removing it CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) { + CHIP_ERROR err = CHIP_NO_ERROR; FabricSceneData fabric(fabric_index); SceneTableData scene(fabric_index, scene_idx); - ReturnErrorOnFailure(scene.Delete(mStorage)); - - if (fabric.scene_count > 0) - { - fabric.scene_count--; - ReturnErrorOnFailure(fabric.Save(mStorage)); - } + ReturnErrorOnFailure(fabric.Load(mStorage)); + err = scene.Load(mStorage); + VerifyOrReturnValue(CHIP_ERROR_NOT_FOUND != err, CHIP_NO_ERROR); + ReturnErrorOnFailure(err); - return CHIP_NO_ERROR; + return fabric.RemoveScene(mStorage, scene.mStorageId); } /// @brief Register a handler in the handler list @@ -467,37 +487,30 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fa /// @return CHIP_NO_ERROR if handler was registered, CHIP_ERROR_NO_MEMORY if the handler list is full CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) { - CHIP_ERROR err = CHIP_ERROR_NO_MEMORY; - uint8_t idPosition = kInvalidPosition; uint8_t firstEmptyPosition = kInvalidPosition; for (uint8_t i = 0; i < kMaxSceneHandlers; i++) { if (this->mHandlers[i] == handler) { - idPosition = i; - break; + this->mHandlers[i] = handler; + return CHIP_NO_ERROR; } - if (this->mHandlers[i] == nullptr && fisrtEmptyPosition == kInvalidPosition) + if (this->mHandlers[i] == nullptr && firstEmptyPosition == kInvalidPosition) { - fisrtEmptyPosition = i; + firstEmptyPosition = i; } } // if found, insert at found position, otherwise at first free possition, otherwise return error - if (idPosition < kMaxSceneHandlers) - { - this->mHandlers[idPosition] = handler; - err = CHIP_NO_ERROR; - } - else if (fisrtEmptyPosition < kMaxSceneHandlers) + if (firstEmptyPosition < kMaxSceneHandlers) { - this->mHandlers[fisrtEmptyPosition] = handler; + this->mHandlers[firstEmptyPosition] = handler; this->mNumHandlers++; - err = CHIP_NO_ERROR; + return CHIP_NO_ERROR; } - return err; + return CHIP_ERROR_NO_MEMORY; } CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) @@ -555,14 +568,14 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) if (this->mHandlers[i] != nullptr) { this->mHandlers[i]->GetSupportedClusters(scene.mStorageId.mEndpointId, cSpan); - for (uint8_t j = 0; j < cSpan.size(); j++) + for (clusterId cluster : cSpan) { ExtensionFieldSet EFS; MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); - EFS.mID = cArray[j]; + EFS.mID = cluster; ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); - EFS.mUsedBytes = (uint8_t) EFSSpan.size(); + EFS.mUsedBytes = static_cast(EFSSpan.size()); ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldSets.InsertFieldSet(EFS)); } } @@ -636,8 +649,8 @@ DefaultSceneTableImpl::SceneEntryIteratorImpl::SceneEntryIteratorImpl(DefaultSce { FabricSceneData fabric(fabric_index); ReturnOnFailure(fabric.Load(provider.mStorage)); - mTotalScene = fabric.scene_count; - mSceneIndex = 0; + mTotalScenes = fabric.scene_count; + mSceneIndex = 0; } size_t DefaultSceneTableImpl::SceneEntryIteratorImpl::Count() diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 419cab78e9a601..56724b33cb9ccd 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -230,7 +230,7 @@ class DefaultSceneTableImpl : public SceneTable FabricIndex mFabric = kUndefinedFabricIndex; SceneIndex mNextSceneIdx; SceneIndex mSceneIndex = 0; - uint8_t mTotalScene = 0; + uint8_t mTotalScenes = 0; }; bool IsInitialized() { return (mStorage != nullptr); } diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 7f776e6f3639ec..2dbba1b92468f1 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -17,6 +17,8 @@ */ #include +#include +#include #include #include #include @@ -34,6 +36,11 @@ using ExtensionFieldSet = scenes::ExtensionFieldSet; using TransitionTimeMs = scenes::TransitionTimeMs; namespace { + +// Group constants +constexpr uint16_t kMaxGroupsPerFabric = 5; +constexpr uint16_t kMaxGroupKeysPerFabric = 4; + // Test Cluster ID constexpr chip::ClusterId kOnOffClusterId = 0x0006; constexpr chip::ClusterId kLevelControlClusterId = 0x0008; @@ -119,6 +126,15 @@ static uint32_t OO_buffer_serialized_length = 0; static uint32_t LC_buffer_serialized_length = 0; static uint32_t CC_buffer_serialized_length = 0; +// Group related data +constexpr chip::GroupId kGroup1 = kMinFabricGroupId; +constexpr chip::GroupId kGroup2 = 0x2222; +constexpr chip::GroupId kGroup3 = 0x1111; + +static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_1(kGroup1, "Group-1.1"); +static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_2(kGroup2, "Group-1.2"); +static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_3(kGroup3, "Group-1.3"); + /// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { @@ -362,7 +378,13 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl } }; +// Storage static chip::TestPersistentStorageDelegate testStorage; + +// Groups +static chip::Crypto::DefaultSessionKeystore sSessionKeystore; +static chip::Credentials::GroupDataProviderImpl sProvider(kMaxGroupsPerFabric, kMaxGroupKeysPerFabric); +// Scene static SceneTableImpl sSceneTable; static TestSceneHandler sHandler; @@ -372,6 +394,12 @@ void ResetSceneTable(SceneTable * sceneTable) sceneTable->RemoveFabric(kFabric2); } +void ResetProvider(chip::Credentials::GroupDataProvider * provider) +{ + provider->RemoveFabric(kFabric1); + provider->RemoveFabric(kFabric2); +} + void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) { SceneTable * sceneTable = &sSceneTable; @@ -762,6 +790,9 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) SceneTableEntry scene; + // Removing non-existing entry should not return errors + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene9.mStorageId)); + // Remove middle NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene5.mStorageId)); auto * iterator = sceneTable->IterateSceneEntries(kFabric1); @@ -787,7 +818,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) iterator->Release(); // Remove first - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntry(kFabric1, scene1.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntryAtPosition(kFabric1, 0)); iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 6); NL_TEST_ASSERT(aSuite, iterator->Next(scene)); @@ -839,7 +870,9 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, iterator->Next(scene) == false); iterator->Release(); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->RemoveSceneTableEntry(kFabric1, scene8.mStorageId)); + // Remove at empty position, shouldn't trigger error + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntryAtPosition(kFabric1, chip::scenes::kMaxScenePerFabric - 1)); iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); @@ -904,6 +937,125 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); } +void TestGroupScenesInteraction(nlTestSuite * aSuite, void * aContext) +{ + chip::Credentials::GroupDataProvider * provider = chip::Credentials::GetGroupDataProvider(); + NL_TEST_ASSERT(aSuite, provider); + SceneTable * sceneTable = &sSceneTable; + NL_TEST_ASSERT(aSuite, sceneTable); + + // Scene Entry + SceneTableEntry scene; + + // Reset test + ResetSceneTable(sceneTable); + ResetProvider(provider); + + // Group Info + chip::Credentials::GroupDataProvider::GroupInfo group; + + // Setup Group Data in Fabric 1 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 0, kGroupInfo1_1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 1, kGroupInfo1_2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 2, kGroupInfo1_3)); + + // Validate data written properly + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 0, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 1, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 2, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); + + // Setup Scene Data in Fabric 1 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene3)); + + // Validate data written properly + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + + // Setup Group Data in Fabric 2 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 0, kGroupInfo1_3)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 1, kGroupInfo1_1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 2, kGroupInfo1_2)); + + // Validate data written properly + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 0, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 1, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 2, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); + + // Setup Scene Data in Fabric 1 + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene3)); + + // Validate data written properly + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, scene == scene1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, scene == scene2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); + NL_TEST_ASSERT(aSuite, scene == scene3); + + // Verify removing a Fabric Scene Data doesn't impact Fabric Group Data + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric1)); + + // Scene Entry + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); + + // Group Info + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 0, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 1, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 2, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 0, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 1, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 2, group)); + NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->RemoveFabric(kFabric1)); + + // Group Info + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 0, group)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 1, group)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 2, group)); + + // Verify removing a Fabric Group Data doesn't impact Fabric Scene Data + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->RemoveFabric(kFabric2)); + + // Group Info + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 0, group)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 1, group)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 2, group)); + + // Scene Entry + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric2)); + + // Scene Entry + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); + NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); +} + } // namespace /** @@ -912,7 +1064,17 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) int TestSetup(void * inContext) { VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); + printf("1\n"); + // Initialize Group Data Provider + sProvider.SetStorageDelegate(&testStorage); + sProvider.SetSessionKeystore(&sSessionKeystore); + VerifyOrReturnError(CHIP_NO_ERROR == sProvider.Init(), FAILURE); + SetGroupDataProvider(&sProvider); + printf("2\n"); + + // Initialize Scene Table VerifyOrReturnError(CHIP_NO_ERROR == sSceneTable.Init(&testStorage), FAILURE); + printf("3\n"); return SUCCESS; } @@ -923,6 +1085,11 @@ int TestSetup(void * inContext) int TestTeardown(void * inContext) { sSceneTable.Finish(); + chip::Credentials::GroupDataProvider * provider = chip::Credentials::GetGroupDataProvider(); + if (nullptr != provider) + { + provider->Finish(); + } chip::Platform::MemoryShutdown(); return SUCCESS; @@ -937,6 +1104,7 @@ int TestSceneTable() NL_TEST_DEF("TestIterateScenes", TestIterateScenes), NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), NL_TEST_DEF("TestFabricScenes", TestFabricScenes), + NL_TEST_DEF("TestGroupScenesInteraction", TestGroupScenesInteraction), NL_TEST_SENTINEL() }; From d990450c17ef739f9f81cd8859440a900e0dacdf Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Sat, 11 Mar 2023 16:04:32 -0500 Subject: [PATCH 61/79] Removed the fabric_list completely from scene table, change scene table to now store transition time in ms, added security on array compression and dissociated handler number from cluster number --- .../scenes/ExtensionFieldSetsImpl.cpp | 10 +- src/app/clusters/scenes/SceneTable.h | 37 ++-- src/app/clusters/scenes/SceneTableImpl.cpp | 129 +------------ src/app/clusters/scenes/SceneTableImpl.h | 6 +- src/app/tests/TestSceneTable.cpp | 173 +----------------- src/lib/core/CHIPConfig.h | 7 + 6 files changed, 49 insertions(+), 313 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 7f8f7034ed19ea..05b49a0d615e03 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -121,15 +121,17 @@ CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fie CHIP_ERROR ExtensionFieldSetsImpl::RemoveFieldAtPosition(uint8_t position) { - VerifyOrReturnError(position < kMaxClusterPerScenes, CHIP_ERROR_INVALID_ARGUMENT); - VerifyOrReturnValue(!this->IsEmpty() && !mEFS[position].IsEmpty(), CHIP_NO_ERROR); + VerifyOrReturnValue(position < mFieldSetsCount, CHIP_NO_ERROR); uint8_t nextPos = static_cast(position + 1); uint8_t moveNum = static_cast(kMaxClusterPerScenes - nextPos); // TODO: Implement general array management methods - // Compress array after removal - memmove(&mEFS[position], &mEFS[nextPos], sizeof(ExtensionFieldSet) * moveNum); + // Compress array after removal, if the removed position is not the last + if (moveNum) + { + memmove(&mEFS[position], &mEFS[nextPos], sizeof(ExtensionFieldSet) * moveNum); + } mFieldSetsCount--; // Clear last occupied position diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 50a89221d60969..d1ea719231c44e 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include namespace chip { @@ -30,8 +30,7 @@ namespace scenes { typedef uint8_t SceneIndex; typedef uint32_t TransitionTimeMs; -typedef uint16_t SceneTransitionTime; -typedef uint8_t TransitionTime100ms; +typedef uint32_t SceneTransitionTime; constexpr GroupId kGlobalGroupSceneId = 0x0000; constexpr SceneIndex kUndefinedSceneIndex = 0xff; @@ -42,7 +41,7 @@ static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM // Handler's are meant to retrieve a single cluster's extension field set, therefore the maximum number allowed is the maximal // number of extension field set. -static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE; +static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_SCENE_HANDLERS; /// @brief Abstract class allowing different Endpoints interactions with the ExtensionFieldSets added to and retrieved from the /// scene Table. The Scene Handler's are meant as interface between various clusters and the Scene table. The expected behaviour of @@ -156,27 +155,22 @@ class SceneTable /// mSceneTransitionTimeSeconds in enhanced scene commands struct SceneData { - char mName[kSceneNameMax] = { 0 }; - size_t mNameLength = 0; - SceneTransitionTime mSceneTransitionTimeSeconds = 0; + char mName[kSceneNameMax] = { 0 }; + size_t mNameLength = 0; + SceneTransitionTime mSceneTransitionTimeMs = 0; EFStype mExtensionFieldSets; - TransitionTime100ms mTransitionTime100ms = 0; - SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, TransitionTime100ms time100ms = 0) : - mSceneTransitionTimeSeconds(time), mTransitionTime100ms(time100ms) + SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0) : mSceneTransitionTimeMs(time) { this->SetName(sceneName); } - SceneData(EFStype fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0, - TransitionTime100ms time100ms = 0) : - mSceneTransitionTimeSeconds(time), - mTransitionTime100ms(time100ms) + SceneData(EFStype fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0) : + mSceneTransitionTimeMs(time) { this->SetName(sceneName); mExtensionFieldSets = fields; } - SceneData(const SceneData & other) : - mSceneTransitionTimeSeconds(other.mSceneTransitionTimeSeconds), mTransitionTime100ms(other.mTransitionTime100ms) + SceneData(const SceneData & other) : mSceneTransitionTimeMs(other.mSceneTransitionTimeMs) { this->SetName(CharSpan(other.mName, other.mNameLength)); mExtensionFieldSets = other.mExtensionFieldSets; @@ -201,25 +195,22 @@ class SceneTable void Clear() { this->SetName(CharSpan()); - mSceneTransitionTimeSeconds = 0; - mTransitionTime100ms = 0; + mSceneTransitionTimeMs = 0; mExtensionFieldSets.Clear(); } bool operator==(const SceneData & other) { return (this->mNameLength == other.mNameLength && !memcmp(this->mName, other.mName, this->mNameLength) && - (this->mSceneTransitionTimeSeconds == other.mSceneTransitionTimeSeconds) && - (this->mTransitionTime100ms == other.mTransitionTime100ms) && + (this->mSceneTransitionTimeMs == other.mSceneTransitionTimeMs) && (this->mExtensionFieldSets == other.mExtensionFieldSets)); } void operator=(const SceneData & other) { this->SetName(CharSpan(other.mName, other.mNameLength)); - this->mExtensionFieldSets = other.mExtensionFieldSets; - this->mSceneTransitionTimeSeconds = other.mSceneTransitionTimeSeconds; - this->mTransitionTime100ms = other.mTransitionTime100ms; + this->mExtensionFieldSets = other.mExtensionFieldSets; + this->mSceneTransitionTimeMs = other.mSceneTransitionTimeMs; } }; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index af67496def2686..e502f57a530290 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -28,24 +28,12 @@ namespace scenes { enum class TagSceneImpl : uint8_t { kSceneCount = 1, - kNextFabric, }; using SceneTableEntry = DefaultSceneTableImpl::SceneTableEntry; using SceneStorageId = DefaultSceneTableImpl::SceneStorageId; using SceneData = DefaultSceneTableImpl::SceneData; -struct FabricHavingSceneList : public CommonPersistentData::FabricList -{ - // This implementation uses the same key as the GroupFabricList from GroupDataProviderImpl to avoid duplicating the list in - // memory. If a different GroupDataProvider implementation is used, it will create the list in flash memory. - CHIP_ERROR UpdateKey(StorageKeyName & key) override - { - key = DefaultStorageKeyAllocator::GroupFabricList(); - return CHIP_NO_ERROR; - } -}; - // Worst case tested: Add Scene Command with EFS using the default SerializeAdd Method. This yielded a serialized scene of 212bytes // when using the OnOff, Level Control and Color Control as well as the maximal name length of 16 bytes. Putting 256 gives some // slack in case different clusters are used. Value obtained by using writer.GetLengthWritten at the end of the SceneTableData @@ -93,8 +81,7 @@ struct SceneTableData : public SceneTableEntry, PersistentData FabricIndex fabric_index = kUndefinedFabricIndex; uint8_t scene_count = 0; SceneStorageId scene_map[kMaxScenePerFabric]; - FabricIndex next = kUndefinedFabricIndex; FabricSceneData() = default; FabricSceneData(FabricIndex fabric) : fabric_index(fabric) {} @@ -175,7 +159,6 @@ struct FabricSceneData : public PersistentData { scene_map[i].Clear(); } - next = kUndefinedFabricIndex; } CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override @@ -184,7 +167,6 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kSceneCount), (scene_count))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kNextFabric), (next))); // Storing the scene map for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { @@ -205,8 +187,6 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagSceneImpl::kSceneCount))); ReturnErrorOnFailure(reader.Get(scene_count)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagSceneImpl::kNextFabric))); - ReturnErrorOnFailure(reader.Get(next)); uint8_t i = 0; while (reader.Next(TLV::ContextTag(TagScene::kEndpointID)) != CHIP_END_OF_TLV) @@ -223,86 +203,6 @@ struct FabricSceneData : public PersistentData return reader.ExitContainer(container); } - // Register the fabric in the list of fabrics having scenes - CHIP_ERROR Register(PersistentStorageDelegate * storage) - { - FabricHavingSceneList fabric_list; - CHIP_ERROR err = fabric_list.Load(storage); - if (CHIP_ERROR_NOT_FOUND == err) - { - // New fabric list - fabric_list.first_entry = fabric_index; - fabric_list.entry_count = 1; - return fabric_list.Save(storage); - } - ReturnErrorOnFailure(err); - - // Existing fabric list, search for existing entry - FabricSceneData fabric(fabric_list.first_entry); - for (size_t i = 0; i < fabric_list.entry_count; i++) - { - err = fabric.Load(storage); - if (CHIP_NO_ERROR != err) - { - break; - } - if (fabric.fabric_index == this->fabric_index) - { - // Fabric already registered - return CHIP_NO_ERROR; - } - fabric.fabric_index = fabric.next; - } - // Add this fabric to the fabric list - this->next = fabric_list.first_entry; - fabric_list.first_entry = this->fabric_index; - fabric_list.entry_count++; - return fabric_list.Save(storage); - } - - // Remove the fabric from the fabrics' linked list - CHIP_ERROR Unregister(PersistentStorageDelegate * storage) const - { - FabricHavingSceneList fabric_list; - CHIP_ERROR err = fabric_list.Load(storage); - VerifyOrReturnValue(CHIP_ERROR_NOT_FOUND != err, CHIP_NO_ERROR); - ReturnErrorOnFailure(err); - - // Existing fabric list, search for existing entry - FabricSceneData fabric(fabric_list.first_entry); - FabricSceneData prev; - - for (size_t i = 0; i < fabric_list.entry_count; i++) - { - err = fabric.Load(storage); - if (CHIP_NO_ERROR != err) - { - break; - } - if (fabric.fabric_index == this->fabric_index) - { - // Fabric found - if (i == 0) - { - // Remove first fabric - fabric_list.first_entry = this->next; - } - else - { - // Remove intermediate fabric - prev.next = this->next; - ReturnErrorOnFailure(prev.Save(storage)); - } - VerifyOrReturnError(fabric_list.entry_count > 0, CHIP_ERROR_INTERNAL); - fabric_list.entry_count--; - return fabric_list.Save(storage); - } - prev = fabric; - fabric.fabric_index = fabric.next; - } - // Fabric not in the list - return CHIP_ERROR_NOT_FOUND; - } /// @brief Finds the index where to insert current scene by going through the whole table and looking if the scene is already in /// there. If the target is not in the table, sets idx to the first empty space /// @param target_scene Storage Id of scene to store @@ -336,17 +236,6 @@ struct FabricSceneData : public PersistentData return CHIP_ERROR_NO_MEMORY; } - CHIP_ERROR Save(PersistentStorageDelegate * storage) override - { - ReturnErrorOnFailure(Register(storage)); - return PersistentData::Save(storage); - } - - CHIP_ERROR Delete(PersistentStorageDelegate * storage) override - { - ReturnErrorOnFailure(Unregister(storage)); - return PersistentData::Delete(storage); - } CHIP_ERROR SaveScene(PersistentStorageDelegate * storage, const SceneTableEntry & entry) { @@ -538,7 +427,10 @@ CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) // TODO: Implement general array management methods // Compress array after removal - memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(this->mHandlers[position]) * moveNum); + if (moveNum) + { + memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(this->mHandlers[position]) * moveNum); + } this->mNumHandlers--; // Clear last occupied position @@ -602,9 +494,8 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldSets.GetFieldSetCount(); i++) { scene.mStorageData.mExtensionFieldSets.GetFieldSetAtPosition(EFS, i); - cluster = EFS.mID; - time = scene.mStorageData.mSceneTransitionTimeSeconds * 1000 + - (scene.mStorageData.mTransitionTime100ms ? scene.mStorageData.mTransitionTime100ms * 10 : 0); + cluster = EFS.mID; + time = scene.mStorageData.mSceneTransitionTimeMs; ByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, EFS.mUsedBytes); if (!EFS.IsEmpty()) diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 56724b33cb9ccd..e80e68a9d3145a 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -31,16 +31,14 @@ namespace scenes { /// kGroupID: Tag for GroupID if the Scene is a Group Scene /// kID: Tag for the scene ID together with the two previous tag, forms the SceneStorageID /// kName: Tag for the name of the scene -/// kTransitionTime: Tag for the transition time of the scene in seconds -/// kTransitionTime100: Tag for the transition time of the scene in tenth of a second (enhanced scenes) +/// kTransitionTime: Tag for the transition time of the scene in miliseconds enum class TagScene : uint8_t { kEndpointID = 1, kGroupID, kID, kName, - kTransitionTime, - kTransitionTime100, + kTransitionTimeMs, }; using clusterId = chip::ClusterId; diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 2dbba1b92468f1..dc4049b11e0cbe 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -17,7 +17,6 @@ */ #include -#include #include #include #include @@ -83,17 +82,17 @@ CharSpan empty; // Scene data static const SceneData sceneData1(CharSpan("Scene #1")); -static const SceneData sceneData2(CharSpan("Scene #2"), 2, 5); -static const SceneData sceneData3(CharSpan("Scene #3"), 25); -static const SceneData sceneData4(CharSpan("Scene num4"), 5); +static const SceneData sceneData2(CharSpan("Scene #2"), 2000); +static const SceneData sceneData3(CharSpan("Scene #3"), 250); +static const SceneData sceneData4(CharSpan("Scene num4"), 5000); static const SceneData sceneData5(empty); -static const SceneData sceneData6(CharSpan("Scene #6"), 3, 15); -static const SceneData sceneData7(CharSpan("Scene #7"), 20, 5); -static const SceneData sceneData8(CharSpan("NAME TOO LOOONNG!"), 1, 10); -static const SceneData sceneData9(CharSpan("Scene #9"), 30, 15); -static const SceneData sceneData10(CharSpan("Scene #10"), 10, 1); -static const SceneData sceneData11(CharSpan("Scene #11"), 20, 10); -static const SceneData sceneData12(CharSpan("Scene #12"), 30, 5); +static const SceneData sceneData6(CharSpan("Scene #6"), 3000); +static const SceneData sceneData7(CharSpan("Scene #7"), 20000); +static const SceneData sceneData8(CharSpan("NAME TOO LOOONNG!"), 15000); +static const SceneData sceneData9(CharSpan("Scene #9"), 3000); +static const SceneData sceneData10(CharSpan("Scene #10"), 1000); +static const SceneData sceneData11(CharSpan("Scene #11"), 50); +static const SceneData sceneData12(CharSpan("Scene #12"), 100); // Scenes SceneTableEntry scene1(sceneId1, sceneData1); @@ -126,15 +125,6 @@ static uint32_t OO_buffer_serialized_length = 0; static uint32_t LC_buffer_serialized_length = 0; static uint32_t CC_buffer_serialized_length = 0; -// Group related data -constexpr chip::GroupId kGroup1 = kMinFabricGroupId; -constexpr chip::GroupId kGroup2 = 0x2222; -constexpr chip::GroupId kGroup3 = 0x1111; - -static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_1(kGroup1, "Group-1.1"); -static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_2(kGroup2, "Group-1.2"); -static const chip::Credentials::GroupDataProvider::GroupInfo kGroupInfo1_3(kGroup3, "Group-1.3"); - /// @brief Simulates a Handler where Endpoint 1 supports onoff and level control and Endpoint 2 supports onoff and color control class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { @@ -380,10 +370,6 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl // Storage static chip::TestPersistentStorageDelegate testStorage; - -// Groups -static chip::Crypto::DefaultSessionKeystore sSessionKeystore; -static chip::Credentials::GroupDataProviderImpl sProvider(kMaxGroupsPerFabric, kMaxGroupKeysPerFabric); // Scene static SceneTableImpl sSceneTable; static TestSceneHandler sHandler; @@ -394,12 +380,6 @@ void ResetSceneTable(SceneTable * sceneTable) sceneTable->RemoveFabric(kFabric2); } -void ResetProvider(chip::Credentials::GroupDataProvider * provider) -{ - provider->RemoveFabric(kFabric1); - provider->RemoveFabric(kFabric2); -} - void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) { SceneTable * sceneTable = &sSceneTable; @@ -937,125 +917,6 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); } -void TestGroupScenesInteraction(nlTestSuite * aSuite, void * aContext) -{ - chip::Credentials::GroupDataProvider * provider = chip::Credentials::GetGroupDataProvider(); - NL_TEST_ASSERT(aSuite, provider); - SceneTable * sceneTable = &sSceneTable; - NL_TEST_ASSERT(aSuite, sceneTable); - - // Scene Entry - SceneTableEntry scene; - - // Reset test - ResetSceneTable(sceneTable); - ResetProvider(provider); - - // Group Info - chip::Credentials::GroupDataProvider::GroupInfo group; - - // Setup Group Data in Fabric 1 - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 0, kGroupInfo1_1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 1, kGroupInfo1_2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric1, 2, kGroupInfo1_3)); - - // Validate data written properly - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 0, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 1, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 2, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); - - // Setup Scene Data in Fabric 1 - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene3)); - - // Validate data written properly - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); - NL_TEST_ASSERT(aSuite, scene == scene1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); - NL_TEST_ASSERT(aSuite, scene == scene2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); - NL_TEST_ASSERT(aSuite, scene == scene3); - - // Setup Group Data in Fabric 2 - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 0, kGroupInfo1_3)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 1, kGroupInfo1_1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->SetGroupInfoAt(kFabric2, 2, kGroupInfo1_2)); - - // Validate data written properly - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 0, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 1, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 2, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); - - // Setup Scene Data in Fabric 1 - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene1)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene2)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric2, scene3)); - - // Validate data written properly - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); - NL_TEST_ASSERT(aSuite, scene == scene1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); - NL_TEST_ASSERT(aSuite, scene == scene2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); - NL_TEST_ASSERT(aSuite, scene == scene3); - - // Verify removing a Fabric Scene Data doesn't impact Fabric Group Data - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric1)); - - // Scene Entry - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); - - // Group Info - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 0, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 1, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric2, 2, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 0, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 1, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->GetGroupInfoAt(kFabric1, 2, group)); - NL_TEST_ASSERT(aSuite, group == kGroupInfo1_3); - - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->RemoveFabric(kFabric1)); - - // Group Info - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 0, group)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 1, group)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric1, 2, group)); - - // Verify removing a Fabric Group Data doesn't impact Fabric Scene Data - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == provider->RemoveFabric(kFabric2)); - - // Group Info - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 0, group)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 1, group)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == provider->GetGroupInfoAt(kFabric2, 2, group)); - - // Scene Entry - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); - - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RemoveFabric(kFabric2)); - - // Scene Entry - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId1, scene)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId2, scene)); - NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); -} - } // namespace /** @@ -1064,17 +925,9 @@ void TestGroupScenesInteraction(nlTestSuite * aSuite, void * aContext) int TestSetup(void * inContext) { VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); - printf("1\n"); - // Initialize Group Data Provider - sProvider.SetStorageDelegate(&testStorage); - sProvider.SetSessionKeystore(&sSessionKeystore); - VerifyOrReturnError(CHIP_NO_ERROR == sProvider.Init(), FAILURE); - SetGroupDataProvider(&sProvider); - printf("2\n"); // Initialize Scene Table VerifyOrReturnError(CHIP_NO_ERROR == sSceneTable.Init(&testStorage), FAILURE); - printf("3\n"); return SUCCESS; } @@ -1085,11 +938,6 @@ int TestSetup(void * inContext) int TestTeardown(void * inContext) { sSceneTable.Finish(); - chip::Credentials::GroupDataProvider * provider = chip::Credentials::GetGroupDataProvider(); - if (nullptr != provider) - { - provider->Finish(); - } chip::Platform::MemoryShutdown(); return SUCCESS; @@ -1104,7 +952,6 @@ int TestSceneTable() NL_TEST_DEF("TestIterateScenes", TestIterateScenes), NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), NL_TEST_DEF("TestFabricScenes", TestFabricScenes), - NL_TEST_DEF("TestGroupScenesInteraction", TestGroupScenesInteraction), NL_TEST_SENTINEL() }; diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 96de94294d1df4..ef1d5bd64a16b3 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1393,6 +1393,13 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE 3 #endif +/** + * @brief The maximum number of handlers used for extension field sets per scene. + */ +#ifndef CHIP_CONFIG_SCENES_MAX_SCENE_HANDLERS +#define CHIP_CONFIG_SCENES_MAX_SCENE_HANDLERS 3 +#endif + /** * @brief The maximum size of a single extension field set for a single cluster */ From 735c7a0467ac850f6d817650e1b4f61c5e73b0f4 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Thu, 16 Mar 2023 15:26:39 -0400 Subject: [PATCH 62/79] SceneHandlers are now stored inside a linked list, reworked the logic for applying scene handlers, added stubs to allow testing --- .../scenes/ExtensionFieldSetsImpl.cpp | 2 +- .../clusters/scenes/ExtensionFieldSetsImpl.h | 2 +- src/app/clusters/scenes/SceneTable.h | 26 ++-- src/app/clusters/scenes/SceneTableImpl.cpp | 141 +++++++----------- src/app/clusters/scenes/SceneTableImpl.h | 12 +- src/app/server/BUILD.gn | 1 - src/app/server/Server.cpp | 4 - src/app/server/Server.h | 108 +++++++++----- src/app/tests/BUILD.gn | 2 + src/app/tests/TestSceneTable.cpp | 77 +++++----- src/app/util/mock/attribute-storage.cpp | 38 +++-- src/lib/core/CHIPConfig.h | 7 - src/lib/support/DefaultStorageKeyAllocator.h | 4 +- 13 files changed, 225 insertions(+), 199 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 05b49a0d615e03..0ee7e155481427 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -110,7 +110,7 @@ CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(const ExtensionFieldSet & fiel return CHIP_ERROR_NO_MEMORY; } -CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fieldSet, uint8_t position) +CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fieldSet, uint8_t position) const { VerifyOrReturnError(position < mFieldSetsCount, CHIP_ERROR_BUFFER_TOO_SMALL); diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 7d9622e33f56df..4d822af3410df8 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -136,7 +136,7 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets uint8_t GetFieldSetCount() const override { return mFieldSetsCount; }; CHIP_ERROR InsertFieldSet(const ExtensionFieldSet & field); - CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldSet & field, uint8_t position); + CHIP_ERROR GetFieldSetAtPosition(ExtensionFieldSet & field, uint8_t position) const; CHIP_ERROR RemoveFieldAtPosition(uint8_t position); // implementation diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index d1ea719231c44e..eb60cf7827131b 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -39,16 +40,15 @@ static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; -// Handler's are meant to retrieve a single cluster's extension field set, therefore the maximum number allowed is the maximal -// number of extension field set. -static constexpr uint8_t kMaxSceneHandlers = CHIP_CONFIG_SCENES_MAX_SCENE_HANDLERS; - /// @brief Abstract class allowing different Endpoints interactions with the ExtensionFieldSets added to and retrieved from the /// scene Table. The Scene Handler's are meant as interface between various clusters and the Scene table. The expected behaviour of /// the table with the handler is: Once a scene command involving extension field set is received, the Scene Table will go through /// the list of handlers to either retrieve, populate or apply Extension field sets. Each handler is meant to retrieve an extension /// field set for a single cluster however it is also possible to use a single generic handler that handles all of them. -class SceneHandler +/// +/// @note If more than one handler is implemented for a specific pair, ONLY THE FIRST HANDLER FOR THAT SPECIFIC +/// PAIR will get called on executing extension field sets related ations on the scene table. +class SceneHandler : public IntrusiveListNodeBase<> { public: SceneHandler(){}; @@ -258,13 +258,13 @@ class SceneTable virtual CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) = 0; // SceneHandlers - virtual CHIP_ERROR RegisterHandler(SceneHandler * handler) = 0; - virtual CHIP_ERROR UnregisterHandler(SceneHandler * handler) = 0; - virtual CHIP_ERROR UnregisterAllHandlers() = 0; + virtual void RegisterHandler(SceneHandler * handler) = 0; + virtual void UnregisterHandler(SceneHandler * handler) = 0; + virtual void UnregisterAllHandlers() = 0; // Extension field sets operation - virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; - virtual CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) = 0; + virtual CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) = 0; + virtual CHIP_ERROR SceneApplyEFS(const SceneTableEntry & scene) = 0; // Fabrics virtual CHIP_ERROR RemoveFabric(FabricIndex fabric_index) = 0; @@ -276,11 +276,11 @@ class SceneTable // Handlers virtual bool HandlerListEmpty() { return (mNumHandlers == 0); } - virtual bool HandlerListFull() { return (mNumHandlers >= kMaxSceneHandlers); } virtual uint8_t GetHandlerNum() { return this->mNumHandlers; } - SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; - uint8_t mNumHandlers = 0; + // SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; + IntrusiveList mHandlerList; + uint8_t mNumHandlers = 0; }; } // namespace scenes diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index e502f57a530290..98276b3c17d995 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -16,6 +16,7 @@ */ #include +#include #include #include @@ -314,6 +315,7 @@ CHIP_ERROR DefaultSceneTableImpl::Init(PersistentStorageDelegate * storage) void DefaultSceneTableImpl::Finish() { + UnregisterAllHandlers(); mSceneEntryIterators.ReleaseAll(); } @@ -329,6 +331,7 @@ CHIP_ERROR DefaultSceneTableImpl::SetSceneTableEntry(FabricIndex fabric_index, c return fabric.SaveScene(mStorage, entry); } + CHIP_ERROR DefaultSceneTableImpl::GetSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id, SceneTableEntry & entry) { FabricSceneData fabric(fabric_index); @@ -343,6 +346,7 @@ CHIP_ERROR DefaultSceneTableImpl::GetSceneTableEntry(FabricIndex fabric_index, S return CHIP_NO_ERROR; } + CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntry(FabricIndex fabric_index, SceneStorageId scene_id) { FabricSceneData fabric(fabric_index); @@ -371,105 +375,64 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fa return fabric.RemoveScene(mStorage, scene.mStorageId); } -/// @brief Register a handler in the handler list +/// @brief Register a handler in the handler linked list /// @param handler Cluster specific handler for extension field sets interaction -/// @return CHIP_NO_ERROR if handler was registered, CHIP_ERROR_NO_MEMORY if the handler list is full -CHIP_ERROR DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) +void DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) { - uint8_t firstEmptyPosition = kInvalidPosition; - for (uint8_t i = 0; i < kMaxSceneHandlers; i++) - { - if (this->mHandlers[i] == handler) - { - this->mHandlers[i] = handler; - return CHIP_NO_ERROR; - } - if (this->mHandlers[i] == nullptr && firstEmptyPosition == kInvalidPosition) - { - firstEmptyPosition = i; - } - } - - // if found, insert at found position, otherwise at first free possition, otherwise return error - if (firstEmptyPosition < kMaxSceneHandlers) - { - this->mHandlers[firstEmptyPosition] = handler; - this->mNumHandlers++; - return CHIP_NO_ERROR; - } - - return CHIP_ERROR_NO_MEMORY; + mHandlerList.PushFront(handler); + mNumHandlers++; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) +void DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) { - uint8_t position = kInvalidPosition; - // Verify list is populated and handler is not null - VerifyOrReturnValue(!this->HandlerListEmpty() && !(handler == nullptr), CHIP_NO_ERROR); - - // Finds the position of the Handler to unregister - for (uint8_t i = 0; i < this->mNumHandlers; i++) - { - if (this->mHandlers[i] == handler) - { - position = i; - break; - } - } - - // Verify Handler was found - VerifyOrReturnValue(position < kMaxSceneHandlers, CHIP_NO_ERROR); - - uint8_t nextPos = static_cast(position + 1); - uint8_t moveNum = static_cast(kMaxSceneHandlers - nextPos); - - // TODO: Implement general array management methods - // Compress array after removal - if (moveNum) - { - memmove(&this->mHandlers[position], &this->mHandlers[nextPos], sizeof(this->mHandlers[position]) * moveNum); - } - - this->mNumHandlers--; - // Clear last occupied position - this->mHandlers[mNumHandlers] = nullptr; - - return CHIP_NO_ERROR; + VerifyOrReturn(!this->HandlerListEmpty() && !(handler == nullptr)); + mHandlerList.Remove(handler); + mNumHandlers--; } -CHIP_ERROR DefaultSceneTableImpl::UnregisterAllHandlers() +void DefaultSceneTableImpl::UnregisterAllHandlers() { - for (uint8_t i = 0; i < this->mNumHandlers; i++) + while (!mHandlerList.Empty()) { - ReturnErrorOnFailure(this->UnregisterHandler(this->mHandlers[0])); + IntrusiveList::Iterator foo = mHandlerList.begin(); + SceneHandler * handle = &(*foo); + mHandlerList.Remove((handle)); + mNumHandlers--; } - - return CHIP_NO_ERROR; } +/// @brief Gets the field sets for the clusters implemented on a specific endpoint and store them in an EFS (extension field set). +/// Does so by going through the SceneHandler list and calling the first handler the list find for each specific clusters. +/// @param scene Scene in which the EFS gets populated CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) { + if (!this->HandlerListEmpty()) { - for (uint8_t i = 0; i < this->mNumHandlers; i++) + uint8_t clusterCount = 0; + clusterId cArray[kMaxClusterPerScenes]; + Span cSpan(cArray); + clusterCount = GetClustersFromEndpoint(scene.mStorageId.mEndpointId, cArray, kMaxClusterPerScenes); + cSpan.reduce_size(clusterCount); + for (clusterId cluster : cSpan) { - clusterId cArray[kMaxClusterPerScenes]; - Span cSpan(cArray); - if (this->mHandlers[i] != nullptr) + ExtensionFieldSet EFS; + MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); + EFS.mID = cluster; + + IntrusiveList::Iterator iter = mHandlerList.begin(); + while (iter != mHandlerList.end()) { - this->mHandlers[i]->GetSupportedClusters(scene.mStorageId.mEndpointId, cSpan); - for (clusterId cluster : cSpan) + if (iter->SupportsCluster(scene.mStorageId.mEndpointId, cluster)) { - ExtensionFieldSet EFS; - MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); - - EFS.mID = cluster; - ReturnErrorOnFailure(this->mHandlers[i]->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); + ReturnErrorOnFailure(iter->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); EFS.mUsedBytes = static_cast(EFSSpan.size()); ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldSets.InsertFieldSet(EFS)); + break; } + iter++; } } } @@ -477,18 +440,16 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) return CHIP_NO_ERROR; } -CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) +/// @brief Retrieves the values of extension field sets on a scene and applies them to each cluster on the endpoint of the scene. +/// Does so by iterating through mHandlerList for each cluster in the EFS and calling the FIRST handler found that supports the +/// cluster. Does so by going through the SceneHandler list and calling the first handler the list find for each specific clusters. +/// @param scene Scene providing the EFSs (extension field sets) +CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(const SceneTableEntry & scene) { - FabricSceneData fabric(fabric_index); - SceneTableData scene(fabric_index); ExtensionFieldSet EFS; TransitionTimeMs time; clusterId cluster; - ReturnErrorOnFailure(fabric.Load(mStorage)); - VerifyOrReturnError(fabric.Find(scene_id, scene.index) == CHIP_NO_ERROR, CHIP_ERROR_NOT_FOUND); - ReturnErrorOnFailure(scene.Load(mStorage)); - if (!this->HandlerListEmpty()) { for (uint8_t i = 0; i < scene.mStorageData.mExtensionFieldSets.GetFieldSetCount(); i++) @@ -500,9 +461,14 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(FabricIndex fabric_index, const if (!EFS.IsEmpty()) { - for (uint8_t j = 0; j < this->mNumHandlers; j++) + IntrusiveList::Iterator iter = mHandlerList.begin(); + while (iter != mHandlerList.end()) { - ReturnErrorOnFailure(this->mHandlers[j]->ApplyScene(scene.mStorageId.mEndpointId, cluster, EFSSpan, time)); + if (iter->SupportsCluster(scene.mStorageId.mEndpointId, cluster)) + { + ReturnErrorOnFailure(iter->ApplyScene(scene.mStorageId.mEndpointId, cluster, EFSSpan, time)); + break; + } } } } @@ -529,6 +495,13 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) return fabric.Delete(mStorage); } +/// @brief wrapper function around emberAfGetClustersFromEndpoint to allow testing, shimed in test configuration because +/// emberAfGetClusterFromEndpoint relies on , which relies on zap generated files +uint8_t DefaultSceneTableImpl::GetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen) +{ + return emberAfGetClustersFromEndpoint(endpoint, clusterList, listLen, true); +} + DefaultSceneTableImpl::SceneEntryIterator * DefaultSceneTableImpl::IterateSceneEntries(FabricIndex fabric_index) { VerifyOrReturnError(IsInitialized(), nullptr); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index e80e68a9d3145a..87edee4bb425a1 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -200,13 +200,14 @@ class DefaultSceneTableImpl : public SceneTable CHIP_ERROR RemoveSceneTableEntryAtPosition(FabricIndex fabric_index, SceneIndex scene_idx) override; // SceneHandlers - CHIP_ERROR RegisterHandler(SceneHandler * handler) override; - CHIP_ERROR UnregisterHandler(SceneHandler * handler) override; - CHIP_ERROR UnregisterAllHandlers() override; + void RegisterHandler(SceneHandler * handler) override; + void UnregisterHandler(SceneHandler * handler) override; + void UnregisterAllHandlers() override; // Extension field sets operation + CHIP_ERROR SceneSaveEFS(SceneTableEntry & scene) override; - CHIP_ERROR SceneApplyEFS(FabricIndex fabric_index, const SceneStorageId & scene_id) override; + CHIP_ERROR SceneApplyEFS(const SceneTableEntry & scene) override; // Fabrics CHIP_ERROR RemoveFabric(FabricIndex fabric_index) override; @@ -215,6 +216,9 @@ class DefaultSceneTableImpl : public SceneTable SceneEntryIterator * IterateSceneEntries(FabricIndex fabric_index) override; protected: + // wrapper function around emberAfGetClustersFromEndpoint to allow override when testing + virtual uint8_t GetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen); + class SceneEntryIteratorImpl : public SceneEntryIterator { public: diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index 507f4b2882d570..d77162909ee5e6 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -50,7 +50,6 @@ static_library("server") { public_deps = [ "${chip_root}/src/app", - "${chip_root}/src/app/clusters/scenes", "${chip_root}/src/lib/address_resolve", "${chip_root}/src/lib/dnssd", "${chip_root}/src/messaging", diff --git a/src/app/server/Server.cpp b/src/app/server/Server.cpp index 229ec7ac963be5..b80c3ca8f45b11 100644 --- a/src/app/server/Server.cpp +++ b/src/app/server/Server.cpp @@ -162,8 +162,6 @@ CHIP_ERROR Server::Init(const ServerInitParams & initParams) mGroupsProvider = initParams.groupDataProvider; SetGroupDataProvider(mGroupsProvider); - mSceneTable = initParams.sceneTable; - mTestEventTriggerDelegate = initParams.testEventTriggerDelegate; deviceInfoprovider = DeviceLayer::GetDeviceInfoProvider(); @@ -537,8 +535,6 @@ KvsPersistentStorageDelegate CommonCaseDeviceServerInitParams::sKvsPersistenStor PersistentStorageOperationalKeystore CommonCaseDeviceServerInitParams::sPersistentStorageOperationalKeystore; Credentials::PersistentStorageOpCertStore CommonCaseDeviceServerInitParams::sPersistentStorageOpCertStore; Credentials::GroupDataProviderImpl CommonCaseDeviceServerInitParams::sGroupDataProvider; -// TODO: complete scene cluster implementation before uncommenting -// scenes::DefaultSceneTableImpl CommonCaseDeviceServerInitParams::sSceneTable; IgnoreCertificateValidityPolicy CommonCaseDeviceServerInitParams::sDefaultCertValidityPolicy; #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION SimpleSessionResumptionStorage CommonCaseDeviceServerInitParams::sSessionResumptionStorage; diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 18d2d2b948f55f..8a0b872cd36ec9 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -28,8 +28,6 @@ #include #include #include -#include -#include #include #include #include @@ -91,7 +89,7 @@ struct ServerInitParams ServerInitParams() = default; // Not copyable - ServerInitParams(const ServerInitParams &) = delete; + ServerInitParams(const ServerInitParams &) = delete; ServerInitParams & operator=(const ServerInitParams &) = delete; // Application delegate to handle some commissioning lifecycle events @@ -118,8 +116,6 @@ struct ServerInitParams // Group data provider: MUST be injected. Used to maintain critical keys such as the Identity // Protection Key (IPK) for CASE. Must be initialized before being provided. Credentials::GroupDataProvider * groupDataProvider = nullptr; - // Scene Table: optionnal, required if Scene Cluster implemented - scenes::SceneTable * sceneTable = nullptr; // Session keystore: MUST be injected. Used to derive and manage lifecycle of symmetric keys. Crypto::SessionKeystore * sessionKeystore = nullptr; // Access control delegate: MUST be injected. Used to look up access control rules. Must be @@ -209,7 +205,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams CommonCaseDeviceServerInitParams() = default; // Not copyable - CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; + CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; CommonCaseDeviceServerInitParams & operator=(const CommonCaseDeviceServerInitParams &) = delete; /** @@ -260,11 +256,6 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams ReturnErrorOnFailure(sGroupDataProvider.Init()); this->groupDataProvider = &sGroupDataProvider; - // TODO: complete scene cluster implementation before uncommenting - // Scene Table - // this->sceneTable = &sSceneTable; - // this->sceneTable->Init(this->persistentStorageDelegate); - #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION ReturnErrorOnFailure(sSessionResumptionStorage.Init(this->persistentStorageDelegate)); this->sessionResumptionStorage = &sSessionResumptionStorage; @@ -298,8 +289,6 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams static PersistentStorageOperationalKeystore sPersistentStorageOperationalKeystore; static Credentials::PersistentStorageOpCertStore sPersistentStorageOpCertStore; static Credentials::GroupDataProviderImpl sGroupDataProvider; - // TODO: complete scene cluster implementation before uncommenting - // static scenes::DefaultSceneTableImpl sSceneTable; static IgnoreCertificateValidityPolicy sDefaultCertValidityPolicy; #if CHIP_CONFIG_ENABLE_SESSION_RESUMPTION static SimpleSessionResumptionStorage sSessionResumptionStorage; @@ -344,43 +333,92 @@ class Server */ void RejoinExistingMulticastGroups(); - FabricTable & GetFabricTable() { return mFabrics; } - - CASESessionManager * GetCASESessionManager() { return &mCASESessionManager; } + FabricTable & GetFabricTable() + { + return mFabrics; + } - Messaging::ExchangeManager & GetExchangeManager() { return mExchangeMgr; } + CASESessionManager * GetCASESessionManager() + { + return &mCASESessionManager; + } - SessionManager & GetSecureSessionManager() { return mSessions; } + Messaging::ExchangeManager & GetExchangeManager() + { + return mExchangeMgr; + } - SessionResumptionStorage * GetSessionResumptionStorage() { return mSessionResumptionStorage; } + SessionManager & GetSecureSessionManager() + { + return mSessions; + } - app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mSubscriptionResumptionStorage; } + SessionResumptionStorage * GetSessionResumptionStorage() + { + return mSessionResumptionStorage; + } - TransportMgrBase & GetTransportManager() { return mTransports; } + app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() + { + return mSubscriptionResumptionStorage; + } - Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } + TransportMgrBase & GetTransportManager() + { + return mTransports; + } - scenes::SceneTable * GetSceneTable() { return mSceneTable; } + Credentials::GroupDataProvider * GetGroupDataProvider() + { + return mGroupsProvider; + } - Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } + Crypto::SessionKeystore * GetSessionKeystore() const + { + return mSessionKeystore; + } #if CONFIG_NETWORK_LAYER_BLE - Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } + Ble::BleLayer * GetBleLayerObject() + { + return mBleLayer; + } #endif - CommissioningWindowManager & GetCommissioningWindowManager() { return mCommissioningWindowManager; } + CommissioningWindowManager & GetCommissioningWindowManager() + { + return mCommissioningWindowManager; + } - PersistentStorageDelegate & GetPersistentStorage() { return *mDeviceStorage; } + PersistentStorageDelegate & GetPersistentStorage() + { + return *mDeviceStorage; + } - app::FailSafeContext & GetFailSafeContext() { return mFailSafeContext; } + app::FailSafeContext & GetFailSafeContext() + { + return mFailSafeContext; + } - TestEventTriggerDelegate * GetTestEventTriggerDelegate() { return mTestEventTriggerDelegate; } + TestEventTriggerDelegate * GetTestEventTriggerDelegate() + { + return mTestEventTriggerDelegate; + } - Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; } + Crypto::OperationalKeystore * GetOperationalKeystore() + { + return mOperationalKeystore; + } - Credentials::OperationalCertificateStore * GetOpCertStore() { return mOpCertStore; } + Credentials::OperationalCertificateStore * GetOpCertStore() + { + return mOpCertStore; + } - app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() { return mAttributePersister; } + app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() + { + return mAttributePersister; + } /** * This function causes the ShutDown event to be generated async on the @@ -397,7 +435,10 @@ class Server return System::SystemClock().GetMonotonicMicroseconds64() - mInitTimestamp; } - static Server & GetInstance() { return sServer; } + static Server & GetInstance() + { + return sServer; + } private: Server() = default; @@ -578,7 +619,6 @@ class Server app::SubscriptionResumptionStorage * mSubscriptionResumptionStorage; Credentials::CertificateValidityPolicy * mCertificateValidityPolicy; Credentials::GroupDataProvider * mGroupsProvider; - scenes::SceneTable * mSceneTable = nullptr; Crypto::SessionKeystore * mSessionKeystore; app::DefaultAttributePersistenceProvider mAttributePersister; GroupDataProviderListener mListener; diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 999691688c86f2..f64f0f58fe5154 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -91,7 +91,9 @@ source_set("scenes-table-test-srcs") { ] public_deps = [ + "${chip_root}/src/app", "${chip_root}/src/app/common:cluster-objects", + "${chip_root}/src/app/util/mock:mock_ember", "${chip_root}/src/lib/core", ] } diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index dc4049b11e0cbe..27abf69b7659b6 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -368,10 +368,26 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl } }; +class TestSceneTableImpl : public SceneTableImpl +{ + uint8_t GetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen) override + { + if (listLen >= 3) + { + clusterList[0] = kOnOffClusterId; + clusterList[1] = kLevelControlClusterId; + clusterList[2] = kColorControlClusterId; + return 3; + } + + return 0; + } +}; + // Storage static chip::TestPersistentStorageDelegate testStorage; // Scene -static SceneTableImpl sSceneTable; +static TestSceneTableImpl sSceneTable; static TestSceneHandler sHandler; void ResetSceneTable(SceneTable * sceneTable) @@ -383,56 +399,41 @@ void ResetSceneTable(SceneTable * sceneTable) void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) { SceneTable * sceneTable = &sSceneTable; - TestSceneHandler tmpHandler[scenes::kMaxSceneHandlers]; + TestSceneHandler tmpHandler[scenes::kMaxClusterPerScenes]; - for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) + for (uint8_t i = 0; i < scenes::kMaxClusterPerScenes; i++) { NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == i); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[i])); + sceneTable->RegisterHandler(&tmpHandler[i]); } // Hanlder order in table : [H0, H1, H2] - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxSceneHandlers); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxClusterPerScenes); // Removal at beginning - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[0])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); - // Confirm array was compressed and last position is now null - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + sceneTable->UnregisterHandler(&tmpHandler[0]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); // Re-insert - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[0])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers)); - // Hanlder order in table : [H1, H2, H0] + sceneTable->RegisterHandler(&tmpHandler[0]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes)); + // Hanlder order in table : [H0, H1, H2] // Removal at the middle - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[2])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); - // Confirm array was compressed and last position is now null - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + sceneTable->UnregisterHandler(&tmpHandler[2]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); // Re-insert - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&tmpHandler[2])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers)); + sceneTable->RegisterHandler(&tmpHandler[2]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes)); // Hanlder order in table : [H1, H0, H2] // Removal at the end - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[2])); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxSceneHandlers - 1)); - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[scenes::kMaxSceneHandlers - 1]); + sceneTable->UnregisterHandler(&tmpHandler[2]); + NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); // Emptying Handler array - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterAllHandlers()); - for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) - { - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->UnregisterHandler(&tmpHandler[i])); - } + sceneTable->UnregisterAllHandlers(); // Verify the handler num has been updated properly NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == 0); - - // Verify all array is empty - for (uint8_t i = 0; i < scenes::kMaxSceneHandlers; i++) - { - NL_TEST_ASSERT(aSuite, nullptr == sceneTable->mHandlers[i]); - } } void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) @@ -533,7 +534,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) CC_buffer_serialized_length = writer.GetLengthWritten(); // Test Registering SceneHandler - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->RegisterHandler(&sHandler)); + sceneTable->RegisterHandler(&sHandler); NL_TEST_ASSERT(aSuite, sceneTable->GetHandlerNum() == 1); // Setup the On Off Extension field set in the expected state from a command @@ -678,19 +679,19 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) // Get test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId1, scene)); NL_TEST_ASSERT(aSuite, scene == scene1); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene1.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId2, scene)); NL_TEST_ASSERT(aSuite, scene == scene2); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene2.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId3, scene)); NL_TEST_ASSERT(aSuite, scene == scene3); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene3.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId4, scene)); NL_TEST_ASSERT(aSuite, scene == scene4); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene4.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId5, scene)); NL_TEST_ASSERT(aSuite, scene == scene5); @@ -700,7 +701,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, scene == scene7); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->GetSceneTableEntry(kFabric1, sceneId8, scene)); NL_TEST_ASSERT(aSuite, scene == scene8); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(kFabric1, scene8.mStorageId)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SceneApplyEFS(scene)); } void TestOverwriteScenes(nlTestSuite * aSuite, void * aContext) diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index 09b43f614136c7..95e12dad065da5 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -61,11 +61,11 @@ EndpointId endpoints[] = { kMockEndpoint1, kMockEndpoint2, kMockEndpoint3 }; uint16_t clusterIndex[] = { 0, 2, 5 }; uint8_t clusterCount[] = { 2, 3, 4 }; ClusterId clusters[] = { MockClusterId(1), MockClusterId(2), MockClusterId(1), MockClusterId(2), MockClusterId(3), - MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; + MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; uint16_t attributeIndex[] = { 0, 2, 5, 7, 11, 16, 19, 25, 27 }; uint16_t attributeCount[] = { 2, 3, 2, 4, 5, 3, 6, 2, 2 }; AttributeId attributes[] = { - // clang-format off + // clang-format off Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, MockAttributeId(1), Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, @@ -84,14 +84,14 @@ bool mockAttribute1 = true; int16_t mockAttribute2 = 42; uint64_t mockAttribute3 = 0xdeadbeef0000cafe; uint8_t mockAttribute4[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, }; } // namespace @@ -184,6 +184,24 @@ chip::Optional emberAfGetNthClusterId(chip::EndpointId endpoint return chip::Optional(clusters[clusterIndex[emberAfIndexFromEndpoint(endpoint)] + n]); } +// Returns number of clusters put into the passed cluster list +// for the given endpoint and client/server polarity +uint8_t emberAfGetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen, bool server) +{ + uint8_t cluster_Count = emberAfClusterCount(endpoint, server); + uint8_t i; + + if (cluster_Count > listLen) + { + cluster_Count = listLen; + } + for (i = 0; i < cluster_Count; i++) + { + clusterList[i] = emberAfGetNthClusterId(endpoint, i, server).Value(); + } + return cluster_Count; +} + chip::Optional emberAfGetServerAttributeIdByIndex(chip::EndpointId endpoint, chip::ClusterId cluster, uint16_t index) { diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index ef1d5bd64a16b3..96de94294d1df4 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1393,13 +1393,6 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE 3 #endif -/** - * @brief The maximum number of handlers used for extension field sets per scene. - */ -#ifndef CHIP_CONFIG_SCENES_MAX_SCENE_HANDLERS -#define CHIP_CONFIG_SCENES_MAX_SCENE_HANDLERS 3 -#endif - /** * @brief The maximum size of a single extension field set for a single cluster */ diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index bee51293b22ef2..84dcb15379e6ef 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } @@ -198,7 +198,7 @@ class DefaultStorageKeyAllocator } static StorageKeyName SubscriptionResumptionMaxCount() { return StorageKeyName::Formatted("g/sum"); } - static StorageKeyName FabricSceneDataKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/s", fabric); } + static StorageKeyName FabricSceneDataKey(chip::FabricIndex fabric) { return StorageKeyName::Formatted("f/%x/sc", fabric); } static StorageKeyName FabricSceneKey(chip::FabricIndex fabric, uint8_t id) { return StorageKeyName::Formatted("f/%x/sc/%x", fabric, id); From cded564a689ec8fe11d1488f2dbcef299a56915c Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Thu, 16 Mar 2023 22:24:53 +0000 Subject: [PATCH 63/79] Restyled by clang-format --- src/app/server/Server.h | 94 +++++--------------- src/app/util/mock/attribute-storage.cpp | 20 ++--- src/lib/support/DefaultStorageKeyAllocator.h | 2 +- 3 files changed, 31 insertions(+), 85 deletions(-) diff --git a/src/app/server/Server.h b/src/app/server/Server.h index 8a0b872cd36ec9..45bcf0a7290515 100644 --- a/src/app/server/Server.h +++ b/src/app/server/Server.h @@ -89,7 +89,7 @@ struct ServerInitParams ServerInitParams() = default; // Not copyable - ServerInitParams(const ServerInitParams &) = delete; + ServerInitParams(const ServerInitParams &) = delete; ServerInitParams & operator=(const ServerInitParams &) = delete; // Application delegate to handle some commissioning lifecycle events @@ -205,7 +205,7 @@ struct CommonCaseDeviceServerInitParams : public ServerInitParams CommonCaseDeviceServerInitParams() = default; // Not copyable - CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; + CommonCaseDeviceServerInitParams(const CommonCaseDeviceServerInitParams &) = delete; CommonCaseDeviceServerInitParams & operator=(const CommonCaseDeviceServerInitParams &) = delete; /** @@ -333,92 +333,41 @@ class Server */ void RejoinExistingMulticastGroups(); - FabricTable & GetFabricTable() - { - return mFabrics; - } + FabricTable & GetFabricTable() { return mFabrics; } - CASESessionManager * GetCASESessionManager() - { - return &mCASESessionManager; - } + CASESessionManager * GetCASESessionManager() { return &mCASESessionManager; } - Messaging::ExchangeManager & GetExchangeManager() - { - return mExchangeMgr; - } + Messaging::ExchangeManager & GetExchangeManager() { return mExchangeMgr; } - SessionManager & GetSecureSessionManager() - { - return mSessions; - } + SessionManager & GetSecureSessionManager() { return mSessions; } - SessionResumptionStorage * GetSessionResumptionStorage() - { - return mSessionResumptionStorage; - } + SessionResumptionStorage * GetSessionResumptionStorage() { return mSessionResumptionStorage; } - app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() - { - return mSubscriptionResumptionStorage; - } + app::SubscriptionResumptionStorage * GetSubscriptionResumptionStorage() { return mSubscriptionResumptionStorage; } - TransportMgrBase & GetTransportManager() - { - return mTransports; - } + TransportMgrBase & GetTransportManager() { return mTransports; } - Credentials::GroupDataProvider * GetGroupDataProvider() - { - return mGroupsProvider; - } + Credentials::GroupDataProvider * GetGroupDataProvider() { return mGroupsProvider; } - Crypto::SessionKeystore * GetSessionKeystore() const - { - return mSessionKeystore; - } + Crypto::SessionKeystore * GetSessionKeystore() const { return mSessionKeystore; } #if CONFIG_NETWORK_LAYER_BLE - Ble::BleLayer * GetBleLayerObject() - { - return mBleLayer; - } + Ble::BleLayer * GetBleLayerObject() { return mBleLayer; } #endif - CommissioningWindowManager & GetCommissioningWindowManager() - { - return mCommissioningWindowManager; - } + CommissioningWindowManager & GetCommissioningWindowManager() { return mCommissioningWindowManager; } - PersistentStorageDelegate & GetPersistentStorage() - { - return *mDeviceStorage; - } + PersistentStorageDelegate & GetPersistentStorage() { return *mDeviceStorage; } - app::FailSafeContext & GetFailSafeContext() - { - return mFailSafeContext; - } + app::FailSafeContext & GetFailSafeContext() { return mFailSafeContext; } - TestEventTriggerDelegate * GetTestEventTriggerDelegate() - { - return mTestEventTriggerDelegate; - } + TestEventTriggerDelegate * GetTestEventTriggerDelegate() { return mTestEventTriggerDelegate; } - Crypto::OperationalKeystore * GetOperationalKeystore() - { - return mOperationalKeystore; - } + Crypto::OperationalKeystore * GetOperationalKeystore() { return mOperationalKeystore; } - Credentials::OperationalCertificateStore * GetOpCertStore() - { - return mOpCertStore; - } + Credentials::OperationalCertificateStore * GetOpCertStore() { return mOpCertStore; } - app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() - { - return mAttributePersister; - } + app::DefaultAttributePersistenceProvider & GetDefaultAttributePersister() { return mAttributePersister; } /** * This function causes the ShutDown event to be generated async on the @@ -435,10 +384,7 @@ class Server return System::SystemClock().GetMonotonicMicroseconds64() - mInitTimestamp; } - static Server & GetInstance() - { - return sServer; - } + static Server & GetInstance() { return sServer; } private: Server() = default; diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index 95e12dad065da5..4e760b8c01c6d5 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -61,11 +61,11 @@ EndpointId endpoints[] = { kMockEndpoint1, kMockEndpoint2, kMockEndpoint3 }; uint16_t clusterIndex[] = { 0, 2, 5 }; uint8_t clusterCount[] = { 2, 3, 4 }; ClusterId clusters[] = { MockClusterId(1), MockClusterId(2), MockClusterId(1), MockClusterId(2), MockClusterId(3), - MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; + MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; uint16_t attributeIndex[] = { 0, 2, 5, 7, 11, 16, 19, 25, 27 }; uint16_t attributeCount[] = { 2, 3, 2, 4, 5, 3, 6, 2, 2 }; AttributeId attributes[] = { - // clang-format off + // clang-format off Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, MockAttributeId(1), Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, @@ -84,14 +84,14 @@ bool mockAttribute1 = true; int16_t mockAttribute2 = 42; uint64_t mockAttribute3 = 0xdeadbeef0000cafe; uint8_t mockAttribute4[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, }; } // namespace diff --git a/src/lib/support/DefaultStorageKeyAllocator.h b/src/lib/support/DefaultStorageKeyAllocator.h index 84dcb15379e6ef..6be4b307eda680 100644 --- a/src/lib/support/DefaultStorageKeyAllocator.h +++ b/src/lib/support/DefaultStorageKeyAllocator.h @@ -33,7 +33,7 @@ namespace chip { class StorageKeyName { public: - StorageKeyName(const StorageKeyName & other) = default; + StorageKeyName(const StorageKeyName & other) = default; StorageKeyName & operator=(const StorageKeyName & other) = default; ~StorageKeyName() { memset(mKeyNameBuffer, 0, sizeof(mKeyNameBuffer)); } From b01a6b446add7325cf6ac3fc1ff1f88138c6ac93 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:23:03 -0400 Subject: [PATCH 64/79] Update src/app/clusters/scenes/ExtensionFieldSets.h Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/ExtensionFieldSets.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSets.h b/src/app/clusters/scenes/ExtensionFieldSets.h index 8c390a08fb521e..174d49cbafb3be 100644 --- a/src/app/clusters/scenes/ExtensionFieldSets.h +++ b/src/app/clusters/scenes/ExtensionFieldSets.h @@ -24,7 +24,7 @@ namespace chip { namespace scenes { static constexpr uint8_t kInvalidPosition = 0xff; -static constexpr uint8_t kMaxClusterPerScenes = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE; +static constexpr uint8_t kMaxClustersPerScene = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE; static constexpr uint8_t kMaxFieldBytesPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; /// @brief class meant serialize all extension ßfield sets of a scene so it can be stored and retrieved from flash memory. From 936c8018df06e29d29c48a39b6620e1a64075d07 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:43:40 -0400 Subject: [PATCH 65/79] Apply suggestions from code review Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/ExtensionFieldSets.h | 2 +- .../scenes/ExtensionFieldSetsImpl.cpp | 2 +- .../clusters/scenes/ExtensionFieldSetsImpl.h | 10 +-- src/app/clusters/scenes/SceneTable.h | 74 ++++++++++++------- src/app/clusters/scenes/SceneTableImpl.cpp | 15 ++-- src/app/util/mock/attribute-storage.cpp | 2 +- 6 files changed, 61 insertions(+), 44 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSets.h b/src/app/clusters/scenes/ExtensionFieldSets.h index 174d49cbafb3be..4753995d9421e3 100644 --- a/src/app/clusters/scenes/ExtensionFieldSets.h +++ b/src/app/clusters/scenes/ExtensionFieldSets.h @@ -27,7 +27,7 @@ static constexpr uint8_t kInvalidPosition = 0xff; static constexpr uint8_t kMaxClustersPerScene = CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE; static constexpr uint8_t kMaxFieldBytesPerCluster = CHIP_CONFIG_SCENES_MAX_EXTENSION_FIELDSET_SIZE_PER_CLUSTER; -/// @brief class meant serialize all extension ßfield sets of a scene so it can be stored and retrieved from flash memory. +/// @brief A way to serialize and deserialize all cluster attribute data for a scene. class ExtensionFieldSets { public: diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 0ee7e155481427..1bd09ea64eea62 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -99,7 +99,7 @@ CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(const ExtensionFieldSet & fiel } } - // if found, replace at found position, otherwise at insert first free position, otherwise return error + // if found, replace at found position, otherwise insert at first free position, otherwise return error if (firstEmptyPosition < kMaxClusterPerScenes) { mEFS[firstEmptyPosition] = fieldSet; diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 4d822af3410df8..7a5996502a0d28 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -81,7 +81,7 @@ struct ExtensionFieldSet ReturnErrorOnFailure( writer.StartContainer(TLV::ContextTag(TagEFS::kIndividualContainer), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kClusterID), static_cast(mID))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kClusterID), mID)); ReturnErrorOnFailure(writer.PutBytes(TLV::ContextTag(TagEFS::kClusterFieldSetData), mBytesBuffer, mUsedBytes)); return writer.EndContainer(container); @@ -113,12 +113,12 @@ struct ExtensionFieldSet mUsedBytes = 0; } - bool IsEmpty() const { return (this->mUsedBytes == 0); } + bool IsEmpty() const { return (mUsedBytes == 0); } bool operator==(const ExtensionFieldSet & other) const { - return (this->mID == other.mID && this->mUsedBytes == other.mUsedBytes && - !memcmp(this->mBytesBuffer, other.mBytesBuffer, this->mUsedBytes)); + return (mID == other.mID && mUsedBytes == other.mUsedBytes && + !memcmp(mBytesBuffer, other.mBytesBuffer, mUsedBytes)); } }; @@ -164,7 +164,7 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets } protected: - ExtensionFieldSet mEFS[kMaxClusterPerScenes]; + ExtensionFieldSet mFieldSets[kMaxClusterPerScenes]; uint8_t mFieldSetsCount = 0; }; } // namespace scenes diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index eb60cf7827131b..cf7e4fcf4caa2c 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -36,18 +36,25 @@ typedef uint32_t SceneTransitionTime; constexpr GroupId kGlobalGroupSceneId = 0x0000; constexpr SceneIndex kUndefinedSceneIndex = 0xff; constexpr SceneId kUndefinedSceneId = 0xff; -static constexpr uint8_t kMaxScenePerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; +static constexpr uint8_t kMaxScenesPerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; + static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; -static constexpr size_t kSceneNameMax = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; +static constexpr size_t kSceneNameMaxLength = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; + -/// @brief Abstract class allowing different Endpoints interactions with the ExtensionFieldSets added to and retrieved from the -/// scene Table. The Scene Handler's are meant as interface between various clusters and the Scene table. The expected behaviour of -/// the table with the handler is: Once a scene command involving extension field set is received, the Scene Table will go through -/// the list of handlers to either retrieve, populate or apply Extension field sets. Each handler is meant to retrieve an extension -/// field set for a single cluster however it is also possible to use a single generic handler that handles all of them. +/// @brief SceneHandlers are meant as interface between various clusters and the Scene table. +/// When a scene command involving extension field sets is received, the Scene Table will go through +/// the list of handlers to either retrieve, populate or apply those extension field sets. +/// +/// Generally, for each specific pair there should be one and only one handler +/// registered with the scene table that claims to handle that pair. /// -/// @note If more than one handler is implemented for a specific pair, ONLY THE FIRST HANDLER FOR THAT SPECIFIC -/// PAIR will get called on executing extension field sets related ations on the scene table. +/// A SceneHandler can handle a single pair, or many such pairs. +/// +/// @note If more than one handler claims to handl a specific pair, only one of +/// those handlers will get called when executing actions related to extension field sets on the scene +/// table. It is not defined which handler will be selected. + class SceneHandler : public IntrusiveListNodeBase<> { public: @@ -58,8 +65,10 @@ class SceneHandler : public IntrusiveListNodeBase<> /// supported clusters /// @param endpoint target endpoint /// @param clusterBuffer Buffer to hold the supported cluster IDs, cannot hold more than - /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES, the function shall use the reduce_size() method in the event it is supporting - /// less than CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENES clusters + /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE. The function shall use the reduce_size() method in the event it is supporting + + /// less than CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE clusters. + virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) = 0; /// @brief Returns whether or not a cluster for scenes is supported on an endpoint @@ -69,7 +78,8 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @return true if supported, false if not supported virtual bool SupportsCluster(EndpointId endpoint, ClusterId cluster) = 0; - /// @brief From command AddScene, allows handler to filter through clusters in command to serialize only the supported ones. + /// @brief Called when handling AddScene. Allows the handler to filter through the clusters in the command to serialize only the supported ones. + /// @param endpoint[in] Endpoint ID /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized /// @param cluster[out] Cluster in the Extension field set, filled by the function @@ -79,10 +89,10 @@ class SceneHandler : public IntrusiveListNodeBase<> const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, ClusterId & cluster, MutableByteSpan & serialisedBytes) = 0; - /// @brief From command StoreScene, retrieves ExtensionField from currently active values, it is the function's responsibility - /// to + /// @brief Called when handling StoreScene, and only if the handler supports the given endpoint and cluster. + /// + /// The implementation must write the actual scene data to store to serializedBytes as described below. - /// place the serialized data in serializedBytes as described below. /// @param endpoint[in] Target Endpoint /// @param cluster[in] Target Cluster @@ -92,7 +102,8 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serializedBytes) = 0; - /// @brief From stored scene (e.g. ViewScene), deserialize ExtensionFieldSet into a cluster object + /// @brief Deserialize an ExtensionFieldSet into a cluster object (e.g. when handling ViewScene). + /// @param endpoint[in] Endpoint ID /// @param cluster[in] Cluster ID to save /// @param serializedBytes[in] ExtensionFieldSet stored in NVM @@ -103,7 +114,8 @@ class SceneHandler : public IntrusiveListNodeBase<> app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; - /// @brief From stored scene (e.g RecallScene), applies EFS values to cluster at transition time + /// @brief Restore a stored scene for the given cluster instance, over timeMs milliseconds (e.g. when handling RecallScene) + /// @param endpoint[in] Endpoint ID /// @param cluster[in] Cluster ID /// @param serializedBytes[in] ExtensionFieldSet stored in NVM @@ -141,7 +153,8 @@ class SceneTable bool operator==(const SceneStorageId & other) { - return (this->mEndpointId == other.mEndpointId && this->mGroupId == other.mGroupId && this->mSceneId == other.mSceneId); + return (mEndpointId == other.mEndpointId && mGroupId == other.mGroupId && mSceneId == other.mSceneId); + } }; @@ -162,17 +175,20 @@ class SceneTable SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0) : mSceneTransitionTimeMs(time) { - this->SetName(sceneName); + SetName(sceneName); + } SceneData(EFStype fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0) : mSceneTransitionTimeMs(time) { - this->SetName(sceneName); + SetName(sceneName); + mExtensionFieldSets = fields; } SceneData(const SceneData & other) : mSceneTransitionTimeMs(other.mSceneTransitionTimeMs) { - this->SetName(CharSpan(other.mName, other.mNameLength)); + SetName(CharSpan(other.mName, other.mNameLength)); + mExtensionFieldSets = other.mExtensionFieldSets; } ~SceneData(){}; @@ -194,7 +210,8 @@ class SceneTable void Clear() { - this->SetName(CharSpan()); + SetName(CharSpan()); + mSceneTransitionTimeMs = 0; mExtensionFieldSets.Clear(); } @@ -229,13 +246,15 @@ class SceneTable bool operator==(const SceneTableEntry & other) { - return (this->mStorageId == other.mStorageId && this->mStorageData == other.mStorageData); + return (mStorageId == other.mStorageId && mStorageData == other.mStorageData); + } void operator=(const SceneTableEntry & other) { - this->mStorageId = other.mStorageId; - this->mStorageData = other.mStorageData; + mStorageId = other.mStorageId; + mStorageData = other.mStorageData; + } }; @@ -275,12 +294,11 @@ class SceneTable virtual SceneEntryIterator * IterateSceneEntries(FabricIndex fabric_index) = 0; // Handlers - virtual bool HandlerListEmpty() { return (mNumHandlers == 0); } - virtual uint8_t GetHandlerNum() { return this->mNumHandlers; } + virtual bool HandlerListEmpty() { return mHandlerList.Empty(); } + // SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; IntrusiveList mHandlerList; - uint8_t mNumHandlers = 0; }; } // namespace scenes diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 98276b3c17d995..9a7a69c8492f3a 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -167,7 +167,7 @@ struct FabricSceneData : public PersistentData TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kSceneCount), (scene_count))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kSceneCount), scene_count)); // Storing the scene map for (uint8_t i = 0; i < kMaxScenePerFabric; i++) { @@ -387,7 +387,7 @@ void DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) void DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) { // Verify list is populated and handler is not null - VerifyOrReturn(!this->HandlerListEmpty() && !(handler == nullptr)); + VerifyOrReturn(!HandlerListEmpty() && !(handler == nullptr)); mHandlerList.Remove(handler); mNumHandlers--; } @@ -398,7 +398,7 @@ void DefaultSceneTableImpl::UnregisterAllHandlers() { IntrusiveList::Iterator foo = mHandlerList.begin(); SceneHandler * handle = &(*foo); - mHandlerList.Remove((handle)); + mHandlerList.Remove(handle); mNumHandlers--; } } @@ -409,7 +409,7 @@ void DefaultSceneTableImpl::UnregisterAllHandlers() CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) { - if (!this->HandlerListEmpty()) + if (!HandlerListEmpty()) { uint8_t clusterCount = 0; clusterId cArray[kMaxClusterPerScenes]; @@ -422,10 +422,9 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) MutableByteSpan EFSSpan = MutableByteSpan(EFS.mBytesBuffer, kMaxFieldBytesPerCluster); EFS.mID = cluster; - IntrusiveList::Iterator iter = mHandlerList.begin(); - while (iter != mHandlerList.end()) + for (auto & handler : mHandlerList) { - if (iter->SupportsCluster(scene.mStorageId.mEndpointId, cluster)) + if (handler.SupportsCluster(scene.mStorageId.mEndpointId, cluster)) { ReturnErrorOnFailure(iter->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); EFS.mUsedBytes = static_cast(EFSSpan.size()); @@ -495,7 +494,7 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) return fabric.Delete(mStorage); } -/// @brief wrapper function around emberAfGetClustersFromEndpoint to allow testing, shimed in test configuration because +/// @brief wrapper function around emberAfGetClustersFromEndpoint to allow testing, shimmed in test configuration because /// emberAfGetClusterFromEndpoint relies on , which relies on zap generated files uint8_t DefaultSceneTableImpl::GetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen) { diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index 4e760b8c01c6d5..a1bef6d8cea299 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -188,7 +188,7 @@ chip::Optional emberAfGetNthClusterId(chip::EndpointId endpoint // for the given endpoint and client/server polarity uint8_t emberAfGetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterList, uint8_t listLen, bool server) { - uint8_t cluster_Count = emberAfClusterCount(endpoint, server); + uint8_t cluster_count = emberAfClusterCount(endpoint, server); uint8_t i; if (cluster_Count > listLen) From 7d3e7c571acc01ac7bc07dd9e89795219afc6386 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Mon, 20 Mar 2023 11:13:35 -0400 Subject: [PATCH 66/79] Refactor of variable, members and functions according to suggestions --- .../scenes/ExtensionFieldSetsImpl.cpp | 28 ++++++------- .../clusters/scenes/ExtensionFieldSetsImpl.h | 9 ++--- src/app/clusters/scenes/SceneTable.h | 39 ++++++++----------- src/app/clusters/scenes/SceneTableImpl.cpp | 34 +++++++--------- src/app/tests/TestSceneTable.cpp | 23 ++++++----- src/app/util/mock/attribute-storage.cpp | 28 ++++++------- 6 files changed, 73 insertions(+), 88 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 1bd09ea64eea62..95900c167dc424 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -32,9 +32,9 @@ CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const { for (uint8_t i = 0; i < mFieldSetsCount; i++) { - if (!mEFS[i].IsEmpty()) + if (!mFieldSets[i].IsEmpty()) { - ReturnErrorOnFailure(mEFS[i].Serialize(writer)); + ReturnErrorOnFailure(mFieldSets[i].Serialize(writer)); } } } @@ -55,7 +55,7 @@ CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader) { for (uint8_t i = 0; i < mFieldSetsCount; i++) { - ReturnErrorOnFailure(mEFS[i].Deserialize(reader)); + ReturnErrorOnFailure(mFieldSets[i].Deserialize(reader)); } } @@ -68,7 +68,7 @@ void ExtensionFieldSetsImpl::Clear() { for (uint8_t i = 0; i < mFieldSetsCount; i++) { - mEFS[i].Clear(); + mFieldSets[i].Clear(); } } mFieldSetsCount = 0; @@ -85,24 +85,24 @@ CHIP_ERROR ExtensionFieldSetsImpl::InsertFieldSet(const ExtensionFieldSet & fiel VerifyOrReturnError(fieldSet.mID != kInvalidClusterId, CHIP_ERROR_INVALID_ARGUMENT); VerifyOrReturnError(!fieldSet.IsEmpty(), CHIP_ERROR_INVALID_ARGUMENT); - for (uint8_t i = 0; i < kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < kMaxClustersPerScene; i++) { - if (mEFS[i].mID == fieldSet.mID) + if (mFieldSets[i].mID == fieldSet.mID) { - mEFS[i] = fieldSet; + mFieldSets[i] = fieldSet; return CHIP_NO_ERROR; } - if (mEFS[i].IsEmpty() && firstEmptyPosition == kInvalidPosition) + if (mFieldSets[i].IsEmpty() && firstEmptyPosition == kInvalidPosition) { firstEmptyPosition = i; } } // if found, replace at found position, otherwise insert at first free position, otherwise return error - if (firstEmptyPosition < kMaxClusterPerScenes) + if (firstEmptyPosition < kMaxClustersPerScene) { - mEFS[firstEmptyPosition] = fieldSet; + mFieldSets[firstEmptyPosition] = fieldSet; mFieldSetsCount++; return CHIP_NO_ERROR; } @@ -114,7 +114,7 @@ CHIP_ERROR ExtensionFieldSetsImpl::GetFieldSetAtPosition(ExtensionFieldSet & fie { VerifyOrReturnError(position < mFieldSetsCount, CHIP_ERROR_BUFFER_TOO_SMALL); - fieldSet = mEFS[position]; + fieldSet = mFieldSets[position]; return CHIP_NO_ERROR; } @@ -124,18 +124,18 @@ CHIP_ERROR ExtensionFieldSetsImpl::RemoveFieldAtPosition(uint8_t position) VerifyOrReturnValue(position < mFieldSetsCount, CHIP_NO_ERROR); uint8_t nextPos = static_cast(position + 1); - uint8_t moveNum = static_cast(kMaxClusterPerScenes - nextPos); + uint8_t moveNum = static_cast(kMaxClustersPerScene - nextPos); // TODO: Implement general array management methods // Compress array after removal, if the removed position is not the last if (moveNum) { - memmove(&mEFS[position], &mEFS[nextPos], sizeof(ExtensionFieldSet) * moveNum); + memmove(&mFieldSets[position], &mFieldSets[nextPos], sizeof(ExtensionFieldSet) * moveNum); } mFieldSetsCount--; // Clear last occupied position - mEFS[mFieldSetsCount].Clear(); // + mFieldSets[mFieldSetsCount].Clear(); // return CHIP_NO_ERROR; } diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 7a5996502a0d28..9c544b4893fbe5 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -117,8 +117,7 @@ struct ExtensionFieldSet bool operator==(const ExtensionFieldSet & other) const { - return (mID == other.mID && mUsedBytes == other.mUsedBytes && - !memcmp(mBytesBuffer, other.mBytesBuffer, mUsedBytes)); + return (mID == other.mID && mUsedBytes == other.mUsedBytes && !memcmp(mBytesBuffer, other.mBytesBuffer, mUsedBytes)); } }; @@ -144,7 +143,7 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets { for (uint8_t i = 0; i < mFieldSetsCount; i++) { - if (!(this->mEFS[i] == other.mEFS[i])) + if (!(this->mFieldSets[i] == other.mFieldSets[i])) { return false; } @@ -156,7 +155,7 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets { for (uint8_t i = 0; i < other.mFieldSetsCount; i++) { - this->mEFS[i] = other.mEFS[i]; + this->mFieldSets[i] = other.mFieldSets[i]; } mFieldSetsCount = other.mFieldSetsCount; @@ -164,7 +163,7 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets } protected: - ExtensionFieldSet mFieldSets[kMaxClusterPerScenes]; + ExtensionFieldSet mFieldSets[kMaxClustersPerScene]; uint8_t mFieldSetsCount = 0; }; } // namespace scenes diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index cf7e4fcf4caa2c..e0c25bcf0ee60c 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -33,16 +33,15 @@ typedef uint8_t SceneIndex; typedef uint32_t TransitionTimeMs; typedef uint32_t SceneTransitionTime; -constexpr GroupId kGlobalGroupSceneId = 0x0000; -constexpr SceneIndex kUndefinedSceneIndex = 0xff; -constexpr SceneId kUndefinedSceneId = 0xff; +constexpr GroupId kGlobalGroupSceneId = 0x0000; +constexpr SceneIndex kUndefinedSceneIndex = 0xff; +constexpr SceneId kUndefinedSceneId = 0xff; static constexpr uint8_t kMaxScenesPerFabric = CHIP_CONFIG_SCENES_MAX_PER_FABRIC; static constexpr size_t kIteratorsMax = CHIP_CONFIG_MAX_SCENES_CONCURRENT_ITERATORS; static constexpr size_t kSceneNameMaxLength = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM_NAME_LENGTH; - -/// @brief SceneHandlers are meant as interface between various clusters and the Scene table. +/// @brief SceneHandlers are meant as interface between various clusters and the Scene table. /// When a scene command involving extension field sets is received, the Scene Table will go through /// the list of handlers to either retrieve, populate or apply those extension field sets. /// @@ -51,7 +50,7 @@ static constexpr size_t kSceneNameMaxLength = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM /// /// A SceneHandler can handle a single pair, or many such pairs. /// -/// @note If more than one handler claims to handl a specific pair, only one of +/// @note If more than one handler claims to handl a specific pair, only one of /// those handlers will get called when executing actions related to extension field sets on the scene /// table. It is not defined which handler will be selected. @@ -66,20 +65,20 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @param endpoint target endpoint /// @param clusterBuffer Buffer to hold the supported cluster IDs, cannot hold more than /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE. The function shall use the reduce_size() method in the event it is supporting - /// less than CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE clusters. virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) = 0; /// @brief Returns whether or not a cluster for scenes is supported on an endpoint - + /// /// @param endpoint Target Endpoint ID /// @param cluster Target Cluster ID /// @return true if supported, false if not supported virtual bool SupportsCluster(EndpointId endpoint, ClusterId cluster) = 0; - /// @brief Called when handling AddScene. Allows the handler to filter through the clusters in the command to serialize only the supported ones. - + /// @brief Called when handling AddScene. Allows the handler to filter through the clusters in the command to serialize only + /// the supported ones. + /// /// @param endpoint[in] Endpoint ID /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized /// @param cluster[out] Cluster in the Extension field set, filled by the function @@ -92,8 +91,7 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @brief Called when handling StoreScene, and only if the handler supports the given endpoint and cluster. /// /// The implementation must write the actual scene data to store to serializedBytes as described below. - - + /// /// @param endpoint[in] Target Endpoint /// @param cluster[in] Target Cluster /// @param serializedBytes[out] Output buffer, data needs to be writen in there and size adjusted to the size of the data @@ -103,11 +101,11 @@ class SceneHandler : public IntrusiveListNodeBase<> virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serializedBytes) = 0; /// @brief Deserialize an ExtensionFieldSet into a cluster object (e.g. when handling ViewScene). - + /// /// @param endpoint[in] Endpoint ID /// @param cluster[in] Cluster ID to save /// @param serializedBytes[in] ExtensionFieldSet stored in NVM - + /// /// @param extensionFieldSet[out] ExtensionFieldSet in command format /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, @@ -115,11 +113,11 @@ class SceneHandler : public IntrusiveListNodeBase<> app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; /// @brief Restore a stored scene for the given cluster instance, over timeMs milliseconds (e.g. when handling RecallScene) - + /// /// @param endpoint[in] Endpoint ID /// @param cluster[in] Cluster ID /// @param serializedBytes[in] ExtensionFieldSet stored in NVM - + /// /// @param timeMs[in] Transition time in ms to apply the scene /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, @@ -154,7 +152,6 @@ class SceneTable bool operator==(const SceneStorageId & other) { return (mEndpointId == other.mEndpointId && mGroupId == other.mGroupId && mSceneId == other.mSceneId); - } }; @@ -168,7 +165,7 @@ class SceneTable /// mSceneTransitionTimeSeconds in enhanced scene commands struct SceneData { - char mName[kSceneNameMax] = { 0 }; + char mName[kSceneNameMaxLength] = { 0 }; size_t mNameLength = 0; SceneTransitionTime mSceneTransitionTimeMs = 0; EFStype mExtensionFieldSets; @@ -176,7 +173,6 @@ class SceneTable SceneData(const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0) : mSceneTransitionTimeMs(time) { SetName(sceneName); - } SceneData(EFStype fields, const CharSpan & sceneName = CharSpan(), SceneTransitionTime time = 0) : mSceneTransitionTimeMs(time) @@ -202,7 +198,7 @@ class SceneTable } else { - size_t maxChars = std::min(sceneName.size(), kSceneNameMax); + size_t maxChars = std::min(sceneName.size(), kSceneNameMaxLength); memcpy(mName, sceneName.data(), maxChars); mNameLength = maxChars; } @@ -247,14 +243,12 @@ class SceneTable bool operator==(const SceneTableEntry & other) { return (mStorageId == other.mStorageId && mStorageData == other.mStorageData); - } void operator=(const SceneTableEntry & other) { mStorageId = other.mStorageId; mStorageData = other.mStorageData; - } }; @@ -296,7 +290,6 @@ class SceneTable // Handlers virtual bool HandlerListEmpty() { return mHandlerList.Empty(); } - // SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; IntrusiveList mHandlerList; }; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 9a7a69c8492f3a..835c3a9fcc06f3 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -90,7 +90,7 @@ struct SceneTableData : public SceneTableEntry, PersistentData { FabricIndex fabric_index = kUndefinedFabricIndex; uint8_t scene_count = 0; - SceneStorageId scene_map[kMaxScenePerFabric]; + SceneStorageId scene_map[kMaxScenesPerFabric]; FabricSceneData() = default; FabricSceneData(FabricIndex fabric) : fabric_index(fabric) {} @@ -156,7 +156,7 @@ struct FabricSceneData : public PersistentData void Clear() override { scene_count = 0; - for (uint8_t i = 0; i < kMaxScenePerFabric; i++) + for (uint8_t i = 0; i < kMaxScenesPerFabric; i++) { scene_map[i].Clear(); } @@ -169,7 +169,7 @@ struct FabricSceneData : public PersistentData ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kSceneCount), scene_count)); // Storing the scene map - for (uint8_t i = 0; i < kMaxScenePerFabric; i++) + for (uint8_t i = 0; i < kMaxScenesPerFabric; i++) { ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), (scene_map[i].mEndpointId))); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), (scene_map[i].mGroupId))); @@ -215,7 +215,7 @@ struct FabricSceneData : public PersistentData SceneIndex firstFreeIdx = kUndefinedSceneIndex; // storage index if scene not found uint8_t index = 0; - while (index < kMaxScenePerFabric) + while (index < kMaxScenesPerFabric) { if (scene_map[index] == target_scene) { @@ -229,7 +229,7 @@ struct FabricSceneData : public PersistentData index++; } - if (firstFreeIdx < kMaxScenePerFabric) + if (firstFreeIdx < kMaxScenesPerFabric) { idx = firstFreeIdx; return CHIP_ERROR_NOT_FOUND; @@ -379,9 +379,7 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveSceneTableEntryAtPosition(FabricIndex fa /// @param handler Cluster specific handler for extension field sets interaction void DefaultSceneTableImpl::RegisterHandler(SceneHandler * handler) { - mHandlerList.PushFront(handler); - mNumHandlers++; } void DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) @@ -389,7 +387,6 @@ void DefaultSceneTableImpl::UnregisterHandler(SceneHandler * handler) // Verify list is populated and handler is not null VerifyOrReturn(!HandlerListEmpty() && !(handler == nullptr)); mHandlerList.Remove(handler); - mNumHandlers--; } void DefaultSceneTableImpl::UnregisterAllHandlers() @@ -399,7 +396,6 @@ void DefaultSceneTableImpl::UnregisterAllHandlers() IntrusiveList::Iterator foo = mHandlerList.begin(); SceneHandler * handle = &(*foo); mHandlerList.Remove(handle); - mNumHandlers--; } } @@ -408,13 +404,12 @@ void DefaultSceneTableImpl::UnregisterAllHandlers() /// @param scene Scene in which the EFS gets populated CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) { - if (!HandlerListEmpty()) { uint8_t clusterCount = 0; - clusterId cArray[kMaxClusterPerScenes]; + clusterId cArray[kMaxClustersPerScene]; Span cSpan(cArray); - clusterCount = GetClustersFromEndpoint(scene.mStorageId.mEndpointId, cArray, kMaxClusterPerScenes); + clusterCount = GetClustersFromEndpoint(scene.mStorageId.mEndpointId, cArray, kMaxClustersPerScene); cSpan.reduce_size(clusterCount); for (clusterId cluster : cSpan) { @@ -426,12 +421,11 @@ CHIP_ERROR DefaultSceneTableImpl::SceneSaveEFS(SceneTableEntry & scene) { if (handler.SupportsCluster(scene.mStorageId.mEndpointId, cluster)) { - ReturnErrorOnFailure(iter->SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); + ReturnErrorOnFailure(handler.SerializeSave(scene.mStorageId.mEndpointId, EFS.mID, EFSSpan)); EFS.mUsedBytes = static_cast(EFSSpan.size()); ReturnErrorOnFailure(scene.mStorageData.mExtensionFieldSets.InsertFieldSet(EFS)); break; } - iter++; } } } @@ -461,11 +455,11 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(const SceneTableEntry & scene) if (!EFS.IsEmpty()) { IntrusiveList::Iterator iter = mHandlerList.begin(); - while (iter != mHandlerList.end()) + for (auto & handler : mHandlerList) { - if (iter->SupportsCluster(scene.mStorageId.mEndpointId, cluster)) + if (handler.SupportsCluster(scene.mStorageId.mEndpointId, cluster)) { - ReturnErrorOnFailure(iter->ApplyScene(scene.mStorageId.mEndpointId, cluster, EFSSpan, time)); + ReturnErrorOnFailure(handler.ApplyScene(scene.mStorageId.mEndpointId, cluster, EFSSpan, time)); break; } } @@ -483,7 +477,7 @@ CHIP_ERROR DefaultSceneTableImpl::RemoveFabric(FabricIndex fabric_index) CHIP_ERROR err = fabric.Load(mStorage); VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_NOT_FOUND == err, err); - while (idx < kMaxScenePerFabric) + while (idx < kMaxScenesPerFabric) { err = RemoveSceneTableEntryAtPosition(fabric_index, idx); VerifyOrReturnError(CHIP_NO_ERROR == err || CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND == err, err); @@ -529,7 +523,7 @@ bool DefaultSceneTableImpl::SceneEntryIteratorImpl::Next(SceneTableEntry & outpu VerifyOrReturnError(fabric.Load(mProvider.mStorage) == CHIP_NO_ERROR, false); // looks for next available scene - while (mSceneIndex < kMaxScenePerFabric) + while (mSceneIndex < kMaxScenesPerFabric) { if (fabric.scene_map[mSceneIndex].mEndpointId != kInvalidEndpointId) { diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 27abf69b7659b6..6bcc8f496bf67f 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -399,41 +399,40 @@ void ResetSceneTable(SceneTable * sceneTable) void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) { SceneTable * sceneTable = &sSceneTable; - TestSceneHandler tmpHandler[scenes::kMaxClusterPerScenes]; + TestSceneHandler tmpHandler[scenes::kMaxClustersPerScene]; - for (uint8_t i = 0; i < scenes::kMaxClusterPerScenes; i++) + for (uint8_t i = 0; i < scenes::kMaxClustersPerScene; i++) { - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == i); sceneTable->RegisterHandler(&tmpHandler[i]); } // Hanlder order in table : [H0, H1, H2] - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == scenes::kMaxClusterPerScenes); + NL_TEST_ASSERT(aSuite, !sceneTable->HandlerListEmpty()); // Removal at beginning sceneTable->UnregisterHandler(&tmpHandler[0]); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); + NL_TEST_ASSERT(aSuite, !sceneTable->HandlerListEmpty()); // Re-insert sceneTable->RegisterHandler(&tmpHandler[0]); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes)); + NL_TEST_ASSERT(aSuite, !sceneTable->HandlerListEmpty()); // Hanlder order in table : [H0, H1, H2] // Removal at the middle sceneTable->UnregisterHandler(&tmpHandler[2]); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); + NL_TEST_ASSERT(aSuite, !sceneTable->HandlerListEmpty()); // Re-insert sceneTable->RegisterHandler(&tmpHandler[2]); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes)); + NL_TEST_ASSERT(aSuite, !sceneTable->HandlerListEmpty()); // Hanlder order in table : [H1, H0, H2] // Removal at the end sceneTable->UnregisterHandler(&tmpHandler[2]); - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == static_cast(scenes::kMaxClusterPerScenes - 1)); + NL_TEST_ASSERT(aSuite, !sceneTable->HandlerListEmpty()); // Emptying Handler array sceneTable->UnregisterAllHandlers(); // Verify the handler num has been updated properly - NL_TEST_ASSERT(aSuite, sceneTable->mNumHandlers == 0); + NL_TEST_ASSERT(aSuite, sceneTable->HandlerListEmpty()); } void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) @@ -535,7 +534,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) // Test Registering SceneHandler sceneTable->RegisterHandler(&sHandler); - NL_TEST_ASSERT(aSuite, sceneTable->GetHandlerNum() == 1); + NL_TEST_ASSERT(aSuite, !sceneTable->HandlerListEmpty()); // Setup the On Off Extension field set in the expected state from a command reader.Init(OO_list); @@ -853,7 +852,7 @@ void TestRemoveScenes(nlTestSuite * aSuite, void * aContext) // Remove at empty position, shouldn't trigger error NL_TEST_ASSERT(aSuite, - CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntryAtPosition(kFabric1, chip::scenes::kMaxScenePerFabric - 1)); + CHIP_NO_ERROR == sceneTable->RemoveSceneTableEntryAtPosition(kFabric1, chip::scenes::kMaxScenesPerFabric - 1)); iterator = sceneTable->IterateSceneEntries(kFabric1); NL_TEST_ASSERT(aSuite, iterator->Count() == 0); diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index a1bef6d8cea299..cd7f7c15888629 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -61,11 +61,11 @@ EndpointId endpoints[] = { kMockEndpoint1, kMockEndpoint2, kMockEndpoint3 }; uint16_t clusterIndex[] = { 0, 2, 5 }; uint8_t clusterCount[] = { 2, 3, 4 }; ClusterId clusters[] = { MockClusterId(1), MockClusterId(2), MockClusterId(1), MockClusterId(2), MockClusterId(3), - MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; + MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; uint16_t attributeIndex[] = { 0, 2, 5, 7, 11, 16, 19, 25, 27 }; uint16_t attributeCount[] = { 2, 3, 2, 4, 5, 3, 6, 2, 2 }; AttributeId attributes[] = { - // clang-format off + // clang-format off Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, MockAttributeId(1), Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, @@ -84,14 +84,14 @@ bool mockAttribute1 = true; int16_t mockAttribute2 = 42; uint64_t mockAttribute3 = 0xdeadbeef0000cafe; uint8_t mockAttribute4[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, }; } // namespace @@ -191,15 +191,15 @@ uint8_t emberAfGetClustersFromEndpoint(EndpointId endpoint, ClusterId * clusterL uint8_t cluster_count = emberAfClusterCount(endpoint, server); uint8_t i; - if (cluster_Count > listLen) + if (cluster_count > listLen) { - cluster_Count = listLen; + cluster_count = listLen; } - for (i = 0; i < cluster_Count; i++) + for (i = 0; i < cluster_count; i++) { clusterList[i] = emberAfGetNthClusterId(endpoint, i, server).Value(); } - return cluster_Count; + return cluster_count; } chip::Optional emberAfGetServerAttributeIdByIndex(chip::EndpointId endpoint, chip::ClusterId cluster, From c4400e9470eb369a4cb933c77df670b6ee5257f7 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Mon, 20 Mar 2023 18:19:31 -0400 Subject: [PATCH 67/79] Addressed comments, fixed TLV structures, removed redundant checks --- src/app/clusters/scenes/ExtensionFieldSets.h | 12 +-- .../scenes/ExtensionFieldSetsImpl.cpp | 39 +++++---- .../clusters/scenes/ExtensionFieldSetsImpl.h | 26 +++--- src/app/clusters/scenes/SceneTable.h | 8 +- src/app/clusters/scenes/SceneTableImpl.cpp | 70 ++++++++++------ src/app/clusters/scenes/SceneTableImpl.h | 42 ++++------ src/app/tests/TestExtensionFieldSets.cpp | 81 ++++++++++++++----- src/app/tests/TestSceneTable.cpp | 1 + src/lib/core/CHIPConfig.h | 3 +- 9 files changed, 171 insertions(+), 111 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSets.h b/src/app/clusters/scenes/ExtensionFieldSets.h index 4753995d9421e3..e05525e0586f02 100644 --- a/src/app/clusters/scenes/ExtensionFieldSets.h +++ b/src/app/clusters/scenes/ExtensionFieldSets.h @@ -34,12 +34,14 @@ class ExtensionFieldSets ExtensionFieldSets(){}; virtual ~ExtensionFieldSets() = default; - virtual CHIP_ERROR Serialize(TLV::TLVWriter & writer) const = 0; - virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader) = 0; - virtual void Clear() = 0; - virtual bool IsEmpty() const = 0; + virtual CHIP_ERROR Serialize(TLV::TLVWriter & writer, TLV::Tag structTa) const = 0; + virtual CHIP_ERROR Deserialize(TLV::TLVReader & reader, TLV::Tag structTa) = 0; + virtual void Clear() = 0; + virtual bool IsEmpty() const = 0; /// @brief Gets a count of how many initialized fields sets are in the object - /// @return The number of initialized field sets in the object + /// @return The number of initialized field sets the object + /// @note Field set refers to extension field sets, from the scene cluster (see 1.4.6.2 ExtensionFieldSet in Matter Application + /// Clusters) virtual uint8_t GetFieldSetCount() const = 0; }; } // namespace scenes diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 95900c167dc424..8c9c2870a7ed3c 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -22,43 +22,40 @@ namespace scenes { // ExtensionFieldSetsImpl::ExtensionFieldSetsImpl() : ExtensionFieldSets() {} -CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer) const +CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer, TLV::Tag structTag) const { TLV::TLVType container; - ReturnErrorOnFailure( - writer.StartContainer(TLV::ContextTag(TagEFS::kFieldSetArrayContainer), TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kFieldSetsCount), static_cast(mFieldSetsCount))); - if (!IsEmpty()) + ReturnErrorOnFailure(writer.StartContainer(structTag, TLV::kTLVType_Structure, container)); + // ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kFieldSetsCount), static_cast(mFieldSetsCount))); + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(TagEFS::kFieldSetArrayContainer), TLV::kTLVType_Array, container)); + for (uint8_t i = 0; i < mFieldSetsCount; i++) { - for (uint8_t i = 0; i < mFieldSetsCount; i++) - { - if (!mFieldSets[i].IsEmpty()) - { - ReturnErrorOnFailure(mFieldSets[i].Serialize(writer)); - } - } + ReturnErrorOnFailure(mFieldSets[i].Serialize(writer)); } return writer.EndContainer(container); + return writer.EndContainer(container); } -CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader) +CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader, TLV::Tag structTag) { TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(TagEFS::kFieldSetArrayContainer))); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, structTag)); ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagEFS::kFieldSetsCount))); - ReturnErrorOnFailure(reader.Get(mFieldSetsCount)); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Array, TLV::ContextTag(TagEFS::kFieldSetArrayContainer))); + ReturnErrorOnFailure(reader.EnterContainer(container)); - if (!this->IsEmpty()) + uint8_t i = 0; + CHIP_ERROR err; + while ((err = reader.Next(TLV::AnonymousTag())) == CHIP_NO_ERROR && i < kMaxClustersPerScene) { - for (uint8_t i = 0; i < mFieldSetsCount; i++) - { - ReturnErrorOnFailure(mFieldSets[i].Deserialize(reader)); - } + ReturnErrorOnFailure(mFieldSets[i].Deserialize(reader)); + i++; } + mFieldSetsCount = i; + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); return reader.ExitContainer(container); } diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h index 9c544b4893fbe5..2525546e0cdb7a 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.h +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.h @@ -24,16 +24,12 @@ namespace chip { namespace scenes { /// @brief Tags Used to serialize Extension Field Sets struct as well as individual field sets. -/// kArrayContainer: Tag for the container of the Struct with the EFS array -/// kFieldSetsCount: Tag representing the number of individual field sets -/// kIndividualContainer: Tag for the container of single EFS struct +/// kFieldSetArrayContainer: Tag for the container of the EFS array /// kClusterID: Tag for the ClusterID of a field set -/// kBufferBytes: Tag for the serialized field set data +/// kClusterFieldSetData: Tag for the serialized field set data enum class TagEFS : uint8_t { kFieldSetArrayContainer = 1, - kFieldSetsCount, - kIndividualContainer, kClusterID, kClusterFieldSetData, }; @@ -78,8 +74,7 @@ struct ExtensionFieldSet CHIP_ERROR Serialize(TLV::TLVWriter & writer) const { TLV::TLVType container; - ReturnErrorOnFailure( - writer.StartContainer(TLV::ContextTag(TagEFS::kIndividualContainer), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kClusterID), mID)); ReturnErrorOnFailure(writer.PutBytes(TLV::ContextTag(TagEFS::kClusterFieldSetData), mBytesBuffer, mUsedBytes)); @@ -91,7 +86,6 @@ struct ExtensionFieldSet { ByteSpan buffer; TLV::TLVType container; - ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::ContextTag(TagEFS::kIndividualContainer))); ReturnErrorOnFailure(reader.EnterContainer(container)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagEFS::kClusterID))); @@ -128,8 +122,8 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets ~ExtensionFieldSetsImpl() override{}; // overrides - CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override; - CHIP_ERROR Deserialize(TLV::TLVReader & reader) override; + CHIP_ERROR Serialize(TLV::TLVWriter & writer, TLV::Tag structTag) const override; + CHIP_ERROR Deserialize(TLV::TLVReader & reader, TLV::Tag structTag) override; void Clear() override; bool IsEmpty() const override { return (mFieldSetsCount == 0); } uint8_t GetFieldSetCount() const override { return mFieldSetsCount; }; @@ -141,6 +135,11 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets // implementation bool operator==(const ExtensionFieldSetsImpl & other) const { + if (this->mFieldSetsCount != other.mFieldSetsCount) + { + return false; + } + for (uint8_t i = 0; i < mFieldSetsCount; i++) { if (!(this->mFieldSets[i] == other.mFieldSets[i])) @@ -159,6 +158,11 @@ class ExtensionFieldSetsImpl : public ExtensionFieldSets } mFieldSetsCount = other.mFieldSetsCount; + for (uint8_t i = mFieldSetsCount; i < kMaxClustersPerScene; i++) + { + this->mFieldSets[i].Clear(); + } + return *this; } diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index e0c25bcf0ee60c..5288deb537de80 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -84,6 +84,8 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @param cluster[out] Cluster in the Extension field set, filled by the function /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + /// @note Only gets called after the scene-cluster has previously verified that the endpoint,cluster valuer pair is supported by + /// the handler. It is therefore the implementation's reponsibility to also implement the SupportsCluster method. virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, ClusterId & cluster, MutableByteSpan & serialisedBytes) = 0; @@ -103,11 +105,13 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @brief Deserialize an ExtensionFieldSet into a cluster object (e.g. when handling ViewScene). /// /// @param endpoint[in] Endpoint ID - /// @param cluster[in] Cluster ID to save + /// @param cluster[in] Cluster ID /// @param serializedBytes[in] ExtensionFieldSet stored in NVM /// /// @param extensionFieldSet[out] ExtensionFieldSet in command format /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + /// @note Only gets called after the scene-cluster has previously verified that the endpoint,cluster valuer pair is supported by + /// the handler. It is therefore the implementation's reponsibility to also implement the SupportsCluster method. virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; @@ -149,6 +153,8 @@ class SceneTable mSceneId = kUndefinedSceneId; } + bool IsValid() { return (mEndpointId != kInvalidEndpointId) && (mSceneId != kUndefinedSceneId); } + bool operator==(const SceneStorageId & other) { return (mEndpointId == other.mEndpointId && mGroupId == other.mGroupId && mSceneId == other.mSceneId); diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 835c3a9fcc06f3..fc6a7dc1233ee5 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -23,12 +23,24 @@ namespace chip { namespace scenes { -/// @brief Tags Used to serialize Scene specific Fabric data -/// kSceneCount: Tag for the number of scenes in Fabric -/// kGroupID: Tag for the next Fabric -enum class TagSceneImpl : uint8_t +/// @brief Tags Used to serialize Scenes so they can be stored in flash memory. +/// kSceneCount: Number of scene in a Fabric +/// kStorageIDArray: Array of StorageID struct +/// kEndpointID: Tag for the Endpoint ID to which this scene applies to +/// kGroupID: Tag for GroupID if the Scene is a Group Scene +/// kSceneID: Tag for the scene ID together with the two previous tag, forms the SceneStorageID +/// kName: Tag for the name of the scene +/// kTransitionTime: Tag for the transition time of the scene in miliseconds +enum class TagScene : uint8_t { kSceneCount = 1, + kStorageIDArray, + kEndpointID, + kGroupID, + kSceneID, + kName, + kTransitionTimeMs, + kExtensionFieldSetsContainer, }; using SceneTableEntry = DefaultSceneTableImpl::SceneTableEntry; @@ -68,12 +80,12 @@ struct SceneTableData : public SceneTableEntry, PersistentData { TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kSceneCount), scene_count)); + ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(TagScene::kStorageIDArray), TLV::kTLVType_Array, container)); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagSceneImpl::kSceneCount), scene_count)); // Storing the scene map for (uint8_t i = 0; i < kMaxScenesPerFabric; i++) { + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), (scene_map[i].mEndpointId))); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), (scene_map[i].mGroupId))); - ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kID), (scene_map[i].mSceneId))); + ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kSceneID), (scene_map[i].mSceneId))); + ReturnErrorOnFailure(writer.EndContainer(container)); } - + ReturnErrorOnFailure(writer.EndContainer(container)); return writer.EndContainer(container); } @@ -186,21 +201,29 @@ struct FabricSceneData : public PersistentData TLV::TLVType container; ReturnErrorOnFailure(reader.EnterContainer(container)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagSceneImpl::kSceneCount))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kSceneCount))); ReturnErrorOnFailure(reader.Get(scene_count)); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Array, TLV::ContextTag(TagScene::kStorageIDArray))); + ReturnErrorOnFailure(reader.EnterContainer(container)); uint8_t i = 0; - while (reader.Next(TLV::ContextTag(TagScene::kEndpointID)) != CHIP_END_OF_TLV) + CHIP_ERROR err; + while ((err = reader.Next(TLV::AnonymousTag())) == CHIP_NO_ERROR && i < kMaxScenesPerFabric) { + ReturnErrorOnFailure(reader.EnterContainer(container)); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kEndpointID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mEndpointId)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kGroupID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mGroupId)); - ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kID))); + ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kSceneID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mSceneId)); + ReturnErrorOnFailure(reader.ExitContainer(container)); i++; } + VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + ReturnErrorOnFailure(reader.ExitContainer(container)); return reader.ExitContainer(container); } @@ -222,7 +245,7 @@ struct FabricSceneData : public PersistentData idx = index; return CHIP_NO_ERROR; // return scene at current index if scene found } - if (scene_map[index].mEndpointId == kInvalidEndpointId && firstFreeIdx == kUndefinedSceneIndex) + if (!scene_map[index].IsValid() && firstFreeIdx == kUndefinedSceneIndex) { firstFreeIdx = index; } @@ -454,7 +477,6 @@ CHIP_ERROR DefaultSceneTableImpl::SceneApplyEFS(const SceneTableEntry & scene) if (!EFS.IsEmpty()) { - IntrusiveList::Iterator iter = mHandlerList.begin(); for (auto & handler : mHandlerList) { if (handler.SupportsCluster(scene.mStorageId.mEndpointId, cluster)) @@ -525,7 +547,7 @@ bool DefaultSceneTableImpl::SceneEntryIteratorImpl::Next(SceneTableEntry & outpu // looks for next available scene while (mSceneIndex < kMaxScenesPerFabric) { - if (fabric.scene_map[mSceneIndex].mEndpointId != kInvalidEndpointId) + if (fabric.scene_map[mSceneIndex].IsValid()) { scene.index = mSceneIndex; VerifyOrReturnError(scene.Load(mProvider.mStorage) == CHIP_NO_ERROR, false); diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 87edee4bb425a1..f10b89953e4375 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -26,21 +26,6 @@ namespace chip { namespace scenes { -/// @brief Tags Used to serialize Scenes so they can be stored in flash memory. -/// kEndpointID: Tag for the Endpoint ID to which this scene applies to -/// kGroupID: Tag for GroupID if the Scene is a Group Scene -/// kID: Tag for the scene ID together with the two previous tag, forms the SceneStorageID -/// kName: Tag for the name of the scene -/// kTransitionTime: Tag for the transition time of the scene in miliseconds -enum class TagScene : uint8_t -{ - kEndpointID = 1, - kGroupID, - kID, - kName, - kTransitionTimeMs, -}; - using clusterId = chip::ClusterId; /// @brief Default implementation of handler, handle EFS from add scene and view scene commands for any cluster @@ -62,12 +47,11 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized /// @param cluster[out] Cluster in the Extension field set, filled by the function /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command - /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + /// @return CHIP_NO_ERROR if successful, CHIP_ERROR_INVALID_ARGUMENT if the cluster is not supported, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, ClusterId & cluster, MutableByteSpan & serialisedBytes) override { - app::DataModel::List attributeValueList; app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; TLV::TLVWriter writer; TLV::TLVType outer; @@ -93,15 +77,16 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler valueBytes++; } // Check we could go through all bytes of the value - VerifyOrReturnError(value_iterator.Next() == false, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(value_iterator.GetStatus()); + mAVPairs[pairCount].attributeValue = mValueBuffer[pairCount]; mAVPairs[pairCount].attributeValue.reduce_size(valueBytes); pairCount++; } - // Check we could go through all pairs in incomming command - VerifyOrReturnError(pair_iterator.Next() == false, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(pair_iterator.GetStatus()); + app::DataModel::List attributeValueList; attributeValueList = mAVPairs; attributeValueList.reduce_size(pairCount); @@ -119,7 +104,8 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @param endpoint target endpoint /// @param cluster target cluster /// @param serialisedBytes data to deserialize into EFS - /// @return CHIP_NO_ERROR if Extension Field Set was successfully populated, specific CHIP_ERROR otherwise + /// @return CHIP_NO_ERROR if Extension Field Set was successfully populated, CHIP_ERROR_INVALID_ARGUMENT if the cluster is not + /// supported, specific CHIP_ERROR otherwise virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serialisedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) override { @@ -135,9 +121,11 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler extensionFieldSet.clusterID = cluster; reader.Init(serialisedBytes); - ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); ReturnErrorOnFailure(reader.EnterContainer(outer)); - ReturnErrorOnFailure(reader.Next()); + ReturnErrorOnFailure(reader.Next( + TLV::kTLVType_Array, + TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)))); attributeValueList.Decode(reader); auto pair_iterator = attributeValueList.begin(); @@ -154,16 +142,16 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler valueBytes++; } // Check we could go through all bytes of the value - VerifyOrReturnError(value_iterator.Next() == false, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(value_iterator.GetStatus()); + mAVPairs[pairCount].attributeValue = mValueBuffer[pairCount]; mAVPairs[pairCount].attributeValue.reduce_size(valueBytes); pairCount++; }; - // Check we could go through all pairs stored in memory - VerifyOrReturnError(pair_iterator.Next() == false, CHIP_ERROR_BUFFER_TOO_SMALL); - ReturnErrorOnFailure(reader.ExitContainer(outer)); + ReturnErrorOnFailure(pair_iterator.GetStatus()); + ReturnErrorOnFailure(reader.ExitContainer(outer)); extensionFieldSet.attributeValueList = mAVPairs; extensionFieldSet.attributeValueList.reduce_size(pairCount); diff --git a/src/app/tests/TestExtensionFieldSets.cpp b/src/app/tests/TestExtensionFieldSets.cpp index 718e151acb6d21..8d7ea232c9bca1 100644 --- a/src/app/tests/TestExtensionFieldSets.cpp +++ b/src/app/tests/TestExtensionFieldSets.cpp @@ -26,6 +26,12 @@ using namespace chip; namespace { +enum class TagTestEFS : uint8_t +{ + kEFS = 1, + kTestArray, +}; + static constexpr size_t kPersistentSceneBufferMax = 256; // Test Cluster ID @@ -50,6 +56,10 @@ static scenes::ExtensionFieldSetsImpl sEFSets; void TestInsertExtensionFieldSet(nlTestSuite * aSuite, void * aContext) { scenes::ExtensionFieldSetsImpl * EFS = &sEFSets; + scenes::ExtensionFieldSetsImpl testEFS1; + scenes::ExtensionFieldSetsImpl testEFS2; + scenes::ExtensionFieldSetsImpl testEFS3; + scenes::ExtensionFieldSetsImpl tempTestEFS; scenes::ExtensionFieldSet tempEFS; uint8_t empty_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; @@ -73,6 +83,21 @@ void TestInsertExtensionFieldSet(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, EFS3.mUsedBytes == kColorControlSize); NL_TEST_ASSERT(aSuite, !memcmp(colorControlBuffer, EFS3.mBytesBuffer, EFS3.mUsedBytes)); + // operator tests single EFS + tempEFS = EFS1; + NL_TEST_ASSERT(aSuite, tempEFS == EFS1); + tempEFS = EFS2; + NL_TEST_ASSERT(aSuite, tempEFS == EFS2); + tempEFS = EFS3; + NL_TEST_ASSERT(aSuite, tempEFS == EFS3); + + // Test clear EFS + tempEFS.Clear(); + NL_TEST_ASSERT(aSuite, tempEFS.IsEmpty()); + NL_TEST_ASSERT(aSuite, tempEFS.mID == kInvalidClusterId); + NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == 0); + NL_TEST_ASSERT(aSuite, !memcmp(empty_buffer, tempEFS.mBytesBuffer, sizeof(tempEFS.mBytesBuffer))); + // Test creation of EFS from Array and ByteSpan that are to big tempEFS = scenes::ExtensionFieldSet(kOnOffClusterId, double_size_buffer, sizeof(double_size_buffer)); NL_TEST_ASSERT(aSuite, tempEFS.mID == kOnOffClusterId); @@ -93,11 +118,8 @@ void TestInsertExtensionFieldSet(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == static_cast(sizeof(tempEFS.mBytesBuffer))); NL_TEST_ASSERT(aSuite, !memcmp(double_size_buffer, tempEFS.mBytesBuffer, sizeof(tempEFS.mBytesBuffer))); - // Test clear EFS tempEFS.Clear(); - NL_TEST_ASSERT(aSuite, tempEFS.mID == kInvalidClusterId); - NL_TEST_ASSERT(aSuite, tempEFS.mUsedBytes == 0); - NL_TEST_ASSERT(aSuite, !memcmp(empty_buffer, tempEFS.mBytesBuffer, sizeof(tempEFS.mBytesBuffer))); + NL_TEST_ASSERT(aSuite, tempEFS.IsEmpty()); // Test insertion of uninitialized EFS NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == EFS->InsertFieldSet(tempEFS)); @@ -108,6 +130,34 @@ void TestInsertExtensionFieldSet(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_ERROR_INVALID_ARGUMENT == EFS->InsertFieldSet(tempEFS)); NL_TEST_ASSERT(aSuite, 0 == EFS->GetFieldSetCount()); + // test operators on multiple EFS struct + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testEFS1.InsertFieldSet(EFS1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testEFS1.InsertFieldSet(EFS2)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testEFS1.InsertFieldSet(EFS3)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testEFS2.InsertFieldSet(EFS3)); + + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testEFS3.InsertFieldSet(EFS1)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testEFS3.InsertFieldSet(EFS2)); + + tempTestEFS = testEFS1; + NL_TEST_ASSERT(aSuite, tempTestEFS == testEFS1); + NL_TEST_ASSERT(aSuite, !(tempTestEFS == testEFS2)); + NL_TEST_ASSERT(aSuite, !(tempTestEFS == testEFS3)); + tempTestEFS = testEFS2; + NL_TEST_ASSERT(aSuite, tempTestEFS == testEFS2); + NL_TEST_ASSERT(aSuite, !(tempTestEFS == testEFS1)); + NL_TEST_ASSERT(aSuite, !(tempTestEFS == testEFS3)); + tempTestEFS = testEFS3; + NL_TEST_ASSERT(aSuite, tempTestEFS == testEFS3); + NL_TEST_ASSERT(aSuite, !(tempTestEFS == testEFS1)); + NL_TEST_ASSERT(aSuite, !(tempTestEFS == testEFS2)); + + // test clear multipler efs struct + tempTestEFS.Clear(); + NL_TEST_ASSERT(aSuite, tempTestEFS.IsEmpty()); + NL_TEST_ASSERT(aSuite, 0 == tempTestEFS.GetFieldSetCount()); + // Test insert NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->InsertFieldSet(EFS1)); NL_TEST_ASSERT(aSuite, 1 == EFS->GetFieldSetCount()); @@ -153,51 +203,39 @@ void TestSerializeDerializeExtensionFieldSet(nlTestSuite * aSuite, void * aConte // Individual Field Sets serialize / deserialize writer.Init(EFS1Buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS1.Serialize(writer)); - writer.EndContainer(outer); EFS1_serialized_length = writer.GetLengthWritten(); NL_TEST_ASSERT(aSuite, EFS1_serialized_length <= scenes::kMaxFieldBytesPerCluster); writer.Init(EFS2Buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS2.Serialize(writer)); - writer.EndContainer(outer); EFS2_serialized_length = writer.GetLengthWritten(); NL_TEST_ASSERT(aSuite, EFS2_serialized_length <= scenes::kMaxFieldBytesPerCluster); writer.Init(EFS3Buffer); - writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS3.Serialize(writer)); - writer.EndContainer(outer); EFS3_serialized_length = writer.GetLengthWritten(); NL_TEST_ASSERT(aSuite, EFS3_serialized_length <= scenes::kMaxFieldBytesPerCluster); reader.Init(EFS1Buffer); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + reader.Next(TLV::AnonymousTag()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == tempEFS.Deserialize(reader)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); NL_TEST_ASSERT(aSuite, EFS1 == tempEFS); reader.Init(EFS2Buffer); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + reader.Next(TLV::AnonymousTag()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == tempEFS.Deserialize(reader)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); NL_TEST_ASSERT(aSuite, EFS2 == tempEFS); reader.Init(EFS3Buffer); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); + reader.Next(TLV::AnonymousTag()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == tempEFS.Deserialize(reader)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); NL_TEST_ASSERT(aSuite, EFS3 == tempEFS); // All ExtensionFieldSets serialize / deserialize writer.Init(sceneEFSBuffer); writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->Serialize(writer)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == EFS->Serialize(writer, TLV::ContextTag(TagTestEFS::kEFS))); writer.EndContainer(outer); sceneEFS_serialized_length = writer.GetLengthWritten(); NL_TEST_ASSERT(aSuite, sceneEFS_serialized_length <= kPersistentSceneBufferMax); @@ -205,7 +243,8 @@ void TestSerializeDerializeExtensionFieldSet(nlTestSuite * aSuite, void * aConte reader.Init(sceneEFSBuffer); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testSceneEFS.Deserialize(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == testSceneEFS.Deserialize(reader, TLV::ContextTag(TagTestEFS::kEFS))); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); NL_TEST_ASSERT(aSuite, *EFS == testSceneEFS); } diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 6bcc8f496bf67f..a2846dd8043d7f 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -661,6 +661,7 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) SceneTableEntry scene; // Set test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); + LogErrorOnFailure(sceneTable->SetSceneTableEntry(kFabric1, scene2)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene3)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene4)); diff --git a/src/lib/core/CHIPConfig.h b/src/lib/core/CHIPConfig.h index 96de94294d1df4..4052c17a446bfa 100644 --- a/src/lib/core/CHIPConfig.h +++ b/src/lib/core/CHIPConfig.h @@ -1387,7 +1387,8 @@ extern const char CHIP_NON_PRODUCTION_MARKER[]; #endif /** - * @brief The maximum number of clusters per scene + * @brief The maximum number of clusters per scene, defaults to 3 for a typical usecase (onOff + level control + color control + * cluster). Needs to be changed in case a greater number of clusters is chosen. */ #ifndef CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE #define CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE 3 From e6ce4fe3dfa5b6f776a7d94b8a86c71948e2be47 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Tue, 21 Mar 2023 01:13:07 +0000 Subject: [PATCH 68/79] Restyled by clang-format --- src/app/util/mock/attribute-storage.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/app/util/mock/attribute-storage.cpp b/src/app/util/mock/attribute-storage.cpp index cd7f7c15888629..3c206ffcbd2d03 100644 --- a/src/app/util/mock/attribute-storage.cpp +++ b/src/app/util/mock/attribute-storage.cpp @@ -61,11 +61,11 @@ EndpointId endpoints[] = { kMockEndpoint1, kMockEndpoint2, kMockEndpoint3 }; uint16_t clusterIndex[] = { 0, 2, 5 }; uint8_t clusterCount[] = { 2, 3, 4 }; ClusterId clusters[] = { MockClusterId(1), MockClusterId(2), MockClusterId(1), MockClusterId(2), MockClusterId(3), - MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; + MockClusterId(1), MockClusterId(2), MockClusterId(3), MockClusterId(4) }; uint16_t attributeIndex[] = { 0, 2, 5, 7, 11, 16, 19, 25, 27 }; uint16_t attributeCount[] = { 2, 3, 2, 4, 5, 3, 6, 2, 2 }; AttributeId attributes[] = { - // clang-format off + // clang-format off Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, MockAttributeId(1), Clusters::Globals::Attributes::ClusterRevision::Id, Clusters::Globals::Attributes::FeatureMap::Id, @@ -84,14 +84,14 @@ bool mockAttribute1 = true; int16_t mockAttribute2 = 42; uint64_t mockAttribute3 = 0xdeadbeef0000cafe; uint8_t mockAttribute4[256] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, }; } // namespace From 89ae06316bd13f838f89b8397e6c195264e41f14 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Tue, 21 Mar 2023 09:29:14 -0400 Subject: [PATCH 69/79] Fix overflow error for CI --- src/app/tests/TestExtensionFieldSets.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tests/TestExtensionFieldSets.cpp b/src/app/tests/TestExtensionFieldSets.cpp index 8d7ea232c9bca1..3181a5410ff216 100644 --- a/src/app/tests/TestExtensionFieldSets.cpp +++ b/src/app/tests/TestExtensionFieldSets.cpp @@ -63,7 +63,7 @@ void TestInsertExtensionFieldSet(nlTestSuite * aSuite, void * aContext) scenes::ExtensionFieldSet tempEFS; uint8_t empty_buffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; - uint8_t double_size_buffer[scenes::kMaxFieldBytesPerCluster * 2]; + uint8_t double_size_buffer[scenes::kMaxFieldBytesPerCluster + 1]; ByteSpan bufferSpan(double_size_buffer); memset(double_size_buffer, static_cast(1), sizeof(double_size_buffer)); From 18151d6ad99d7d52a2b6e036ce3aadbb861e10ab Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 22 Mar 2023 10:41:59 -0400 Subject: [PATCH 70/79] Cleanup of logErrors, added missing break in case --- src/app/clusters/scenes/SceneTable.h | 1 - src/app/clusters/scenes/SceneTableImpl.cpp | 2 +- src/app/clusters/scenes/scenes-server.cpp | 606 +++++++++++++++++++++ src/app/tests/TestSceneTable.cpp | 2 +- 4 files changed, 608 insertions(+), 3 deletions(-) create mode 100644 src/app/clusters/scenes/scenes-server.cpp diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 5288deb537de80..8333416b86f286 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -296,7 +296,6 @@ class SceneTable // Handlers virtual bool HandlerListEmpty() { return mHandlerList.Empty(); } - // SceneHandler * mHandlers[kMaxSceneHandlers] = { nullptr }; IntrusiveList mHandlerList; }; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index fc6a7dc1233ee5..e439f5b9721374 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -80,7 +80,7 @@ struct SceneTableData : public SceneTableEntry, PersistentData +#include +#include +#include +#include + +namespace chip { +namespace app { +namespace Clusters { +namespace Scenes { + +CHIP_ERROR ScenesServer::Init() {} +void ScenesServer::Shutdown() {} + +template +void AddSceneParse(HandlerContext & ctx, const CommandData & commandData) +{ + ResponseType response; + CHIP_ERROR err; + + scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); + chip::Credentials::GroupDataProvider * groupProvider = GetGroupDataProvider(); + + // Command data + GroupId & groupId = commandData.groupID; + SceneId & sceneId = commandData.sceneID; + EndpointId & endpoint = commandPath.mEndpointId; + FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + auto & transitionTime = commandData.transitionTime; + auto & sceneName = commandData.sceneName; + auto & extensionFieldSets = commandData.extensionFieldSets; + uint32_t transitionTimeMs = 0; + + // Verify Endpoint in group + VerifyOrReturn(nullptr != groupProvider, false); + if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) + { + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + if (transitionTime.HasValue()) + { + if (commandData.GetCommandId() == Commands::AddScene::Id) + { + transitionTimeMs = static_cast(transitionTime.Value() * 1000); + } + else if (commandData.GetCommandId() == Commands::EnhancedAddScene::Id) + { + transitionTimeMs = static_cast(transitionTime.Value() * 10000); + } + } + + auto fieldSetIter = extensionFieldSets.begin(); + + ClusterId tempCluster = 0; + uint8_t buffer[kMaxFieldsPerCluster]; + uint8_t EFSCount = 0; + + scenes::SceneStorageId StorageId(endpoint, sceneId, groupId); + scenes::SceneStorageData StorageData(sceneName, sceneId, transitionTimeMs, 0); + + // Goes through all EFS in command + while (fieldSetIter.Next() && EFSCount < kMaxClusterPerScenes) + { + Structs::ExtensionFieldSet::DecodableType EFS = fieldSetIter.GetValue(); + chip::scene::ExtensionFieldsSet tempEFS; + + MutableByteSpan buff_span(tempEFS.mBytesBuffer); + + // Check if a handler is registered for the EFS's cluster + for (uint8_t i = 0; i < sceneTable.handlerNum; i++) + { + sceneTable.mHandlers[i].SerializeAdd(endpoint, tempEFS.mID, tempEFS.mBytesBuffer, EFS); + } + tempEFS.mUsedBytes = buff_span.size(); + + if (!tempEFS.IsEmpty()) + { + StorageData.mExtensionFieldSet.InsertFieldSet(tempEFS); + } + } + + // Create scene from data and ID + scenes::SceneTableEntry scene(StorageId, StorageData); + + // Insert in table + err = sceneTable.SetSceneTableEntry(fabricIndex, scene); + + if (err != CHIP_NO_ERROR) + { + if (err == CHIP_ERROR_INVALID_LIST_LENGTH) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ResourceExhausted); + } + else + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + } + return; + } + + // Write response + response.status = Protocols::InteractionModel::Status::Success; + reponse.groupID = groupId; + response.sceneID = sceneId; + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); +} + +template +void ViewSceneParse(HandlerContext & ctx, const CommandData & commandData) +{ + ResponseType response; + CHIP_ERROR err; + + scenes::SceneTable * sceneTable = chip::server::GetInstance->GetSceneTable(); + Credentials::GroupDataProvider * groupProvider = Credentials::GetGroupDataProvider(); + + // Command data + GroupId & groupId = commandData.groupID; + SceneId & sceneId = commandData.sceneID; + EndpointId & endpoint = commandPath.mEndpointId; + FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + + // Verify Endpoint in group + VerifyOrReturn(nullptr != groupProvider, false); + if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + scenes::SceneStorageId StorageId(endpoint, sceneId, groupId); + scenes::SceneTableEntry scene(); + + // Gets the scene form the table + err = sceneTable->GetSceneTableEntry(fabricIndex, StorageId, scene); + if (err != CHIP_NO_ERROR) + { + if (err == CHIP_ERROR_NOT_FOUND) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::NotFound); + } + else + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + } + return; + } + + // Write response + response.status = Protocols::InteractionModel::Status::Success; + reponse.groupID = groupId; + response.sceneID = sceneId; + if (scene.mStorageData.mSceneTransitionTimeMs) + { + if (commandData.GetCommandId() == Commands::AddScene::Id) + { + response.transitionTime.SetValue(static_cast(scene.mStorageData.mSceneTransitionTimeMs / 1000)); + } + else if (commandData.GetCommandId() == Commands::AddScene::Id) + { + response.transitionTime.SetValue(static_cast(scene.mStorageData.mSceneTransitionTimeMs / 10000)); + } + } + if (!scene.mNameSpan.empty()) + { + response.sceneName.SetValue(scene.mNameSpan); + } + if (!scene.mExtensionFieldSets.IsEmpty()) + { + for (uint8_t i = 0; i < scene.mExtensionFieldSets.GetFieldNum(); i++) + { + // gets data from the field in the scene + ExtensionFieldsSet tempField; + scene.mExtensionFieldSets.GetFieldSetAtPosition(tempField, i); + ByteSpan efsSpan(tempField.mBytesBuffer, tempField.mUsedBytes); + + // This should only find one handle per cluster + for (uint8_t j = 0; j < sceneTable.mNumHandlers; j++) + { + CHIP_ERROR found; + found = sceneTable->mHandlers[j].Deserialize(endpoint, tempField.mID, efsSpan, mResponseEFSBuffer[i]); + + // Leaves loop once the handler has deserialized its cluster + if (found == CHIP_NO_ERROR) + { + break; + } + } + } + + response.extensionFieldSets.SetValue(mResponseEFSBuffer); + response.extensionFieldSets.reduce_size(scene.mExtensionFieldSets.GetFieldNum()); + } + + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); +} + +// CommandHanlerInterface +void ScenesServer::InvokeCommand(HandlerContext & ctx) +{ + if (mAsyncCommandHandle.Get() != nullptr) + { + // We have a command processing in the backend, reject all incoming commands. + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Busy); + ctx.SetCommandHandled(); + return; + } + + // Since mPath is used for building the response command, and we have checked that we are not pending the response of another + // command above. So it is safe to set the mPath here and not clear it when return. + mPath = ctx.mRequestPath; + + switch (ctx.mRequestPath.mCommandId) + { + case Commands::AddScene::Id: + HandleCommand(ctx, [this](HandlerContext & ctx, const auto & req) { + HandleAddScene(ctx, req); + }); + return; + case Commands::ViewScene::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleViewScene(ctx, req); }); + return; + case Commands::RemoveScene::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleRemoveScene(ctx, req); }); + return; + case Commands::RemoveAllScenes::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleRemoveAllScenese(ctx, req); }); + return; + case Commands::StoreScene::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleStoreScene(ctx, req); }); + return; + case Commands::RecallScene::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleRecallScene(ctx, req); }); + return; + case Commands::GetSceneMembership::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleGetSceneMembership(ctx, req); }); + return; + case Commands::EnhancedAddScene::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleAddScene(ctx, req); }); + return; + case Commands::EnhancedViewScene::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleEnhancedAddScene(ctx, req); }); + return; + case Commands::CopyScene::Id: + HandleCommand( + ctx, [this](HandlerContext & ctx, const auto & req) { HandleCopyScene(ctx, req); }); + return; + } +} + +CHIP_ERROR ScenesServer::EnumerateAcceptedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) +{} +CHIP_ERROR ScenesServer::EnumerateGeneratedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) +{} + +void ScenesServer::HandleAddScene(HandlerContext & ctx, const Commands::EnhancedAddSceneResponse::Type & commandData) +{ + AddSceneParse(ctx, commandData); +} + +void ScenesServer::HandleViewScene(HandlerContext & ctx, const CommandData & commandData) +{ + ViewSceneParse(ctx, commandData); +} + +void ScenesServer::HandleRemoveScene(HandlerContext & ctx, const Commands::RemoveScene::DecodableType & req) +{ + Commands::RemoveSceneResponse::Type response; + CHIP_ERROR err; + + scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); + Credentials::GroupDataProvider * groupProvider = Credentials::GetGroupDataProvider(); + + // Command data + GroupId & groupId = commandData.groupID; + SceneId & sceneId = commandData.sceneID; + EndpointId & endpoint = commandPath.mEndpointId; + FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + + // Scene Table interface data + scenes::SceneStorageId sceneStorageId(endpoint, sceneId, groupId); + scenes::SceneTableEntry scene(sceneStorageId); + + // Verify Endpoint in group + VerifyOrReturn(nullptr != groupProvider, false); + if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + // TODO : confirm that either using get is ok or refactor remove scene table entry to return error on removal of unexisting + // scene + // Gets the scene form the table + err = sceneTable->GetSceneTableEntry(fabricIndex, sceneStorageId, scene); + if (err != CHIP_NO_ERROR) + { + if (err == CHIP_ERROR_NOT_FOUND) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::NotFound); + } + else + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + } + return; + } + // Remove the scene from the scene table + err = sceneTable->RemoveSceneTableEntry(fabricIndex, sceneStorageId); + if (err != CHIP_NO_ERROR) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + return; + } + + // Write response + response.status = Protocols::InteractionModel::Status::Success; + reponse.groupID = groupId; + response.sceneID = sceneId; + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); +} +void ScenesServer::HandleRemoveAllScenes(HandlerContext & ctx, const Commands::RemoveAllScenes::DecodableType & req) +{ + Commands::RemoveAllScenesResponse::Type response; + CHIP_ERROR err; + + scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); + Credentials::GroupDataProvider * groupProvider = Credentials::GetGroupDataProvider(); + + // Command data + GroupId & groupId = commandData.groupID; + EndpointId & endpoint = commandPath.mEndpointId; + FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + scenes::SceneTableEntry scene(); + + // TODO: Add removal all group scene to Scene Table + + // Write response + response.status = Protocols::InteractionModel::Status::Success; + reponse.groupID = groupId; + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); +} + +void ScenesServer::HandleStoreScene(HandlerContext & ctx, const Commands::StoreScene::DecodableType & req) +{ + Commands::StoreSceneResponse::Type response; + CHIP_ERROR err; + + scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); + Credentials::GroupDataProvider * groupProvider = Credentials::GetGroupDataProvider(); + + // Command data + GroupId & groupId = commandData.groupID; + SceneId & sceneId = commandData.sceneID; + EndpointId & endpoint = commandPath.mEndpointId; + FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + + // Scene Table interface data + scenes::SceneStorageId sceneStorageId(endpoint, sceneId, groupId); + scenes::SceneTableEntry scene(sceneStorageId); + + // Verify Endpoint in group + VerifyOrReturn(nullptr != groupProvider, false); + if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + // TODO: Add get available scene space left function and return RESOURCE_EXHAUSTED on check failure + + err = sceneTable->GetSceneTableEntry(fabricIndex, sceneStorageId, scene); + if (err != CHIP_NO_ERROR || err != CHIP_ERROR_NOT_FOUND) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + return; + } + + if (err == CHIP_ERROR_NOT_FOUND) + { + scene.mStorageData.SetName(CharSpan()); + scene.mStorageData.mSceneTransitionTimeMs = 0; + } + else + { + scene.mStorageData.mExtensionFieldSets.Clear(); + } + + // Gets the EFS + err = SceneSaveEFS(scene); + if (err != CHIP_NO_ERROR) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + return; + } + + // Write response + response.status = Protocols::InteractionModel::Status::Success; + reponse.groupID = groupId; + response.sceneID = sceneId; + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); +} + +void ScenesServer::HandleRecallScene(HandlerContext & ctx, const Commands::RecallScene::DecodableType & req) +{ + Commands::RecallSceneResponse::Type response; + CHIP_ERROR err; + + scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); + chip::Credentials::GroupDataProvider * groupProvider = GetGroupDataProvider(); + + // Command data + GroupId & groupId = commandData.groupID; + SceneId & sceneId = commandData.sceneID; + EndpointId & endpoint = commandPath.mEndpointId; + FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + auto & transitionTime = commandData.transitionTime; + + // Scene Table interface data + scenes::SceneStorageId sceneStorageId(endpoint, sceneId, groupId); + scenes::SceneTableEntry scene(sceneStorageId); + + // Verify Endpoint in group + VerifyOrReturn(nullptr != groupProvider, false); + if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + err = sceneTable->GetSceneTableEntry(fabricIndex, sceneStorageId, scene); + if (err != CHIP_NO_ERROR) + { + if (err == CHIP_ERROR_NOT_FOUND) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::NotFound); + } + else + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + } + return; + } + + if (transitionTime.HasValue()) + { + scene.mStorageData.mTransitionTimeMs += transitionTime.Value() * 100; + } + + err = SceneApplyEFS(scene); + if (err != CHIP_NO_ERROR) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + return; + } + + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Success); + return; +} + +void ScenesServer::HandleGetSceneMembership(HandlerContext & ctx, const Commands::GetSceneMembership::DecodableType & req) +{ + Commands::GetSceneMembershipResponse::Type response; + CHIP_ERROR err; + uint8_t capacity = 0; + uint8_t sceneGroupCount = 0; + + scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); + chip::Credentials::GroupDataProvider * groupProvider = GetGroupDataProvider(); + + // Command data + GroupId & groupId = commandData.groupID; + EndpointId & endpoint = commandPath.mEndpointId; + FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + + // Scene Table interface data + SceneId scenesInGroup[kMaxScenePerFabric]; + ByteSpan sceneList(scenesInGroup); + scenes::SceneTableEntry scene; + + // Verify Endpoint in group + VerifyOrReturn(nullptr != groupProvider, false); + if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + // TODO: implement a get space left in Fabric and in Scene Table + // Get Capacity + + // Iterate through fabrics scene to populate scene list + auto iterator = sceneTable->IterateSceneEntries(fabricIndex); + + while (iterator->Next(scene)) + { + if (scene.mGroupId == groupId) + { + scenesInGroup[sceneGroupCount] = scene.mStorageId.mSceneId; + sceneGroupCount++; + } + } + sceneList.reduce_size(sceneGroupCount); + + // Write response + response.status = Protocols::InteractionModel::Status::Success; + response.Capacity.SetValue(capacity); + response.groupID = groupId; + response.sceneList = sceneList; + ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); +} + +void ScenesServer::HandleEnhancedAddScene(HandlerContext & ctx, const Commands::EnhancedAddScene::DecodableType & req) +{ + AddSceneParse(ctx, commandData); +} + +void ScenesServer::HandleEnhancedViewScene(HandlerContext & ctx, const Commands::EnhancedViewScene::DecodableType & req) +{ + ViewSceneParse(ctx, commandData); +} +void ScenesServer::HandleCopyScene(HandlerContext & ctx, const Commands::CopyScene::DecodableType & req) +{ + Commands::CopySceneResponse::Type response; + CHIP_ERROR err; + + scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); + chip::Credentials::GroupDataProvider * groupProvider = GetGroupDataProvider(); + + // Command data + GroupId & groupFrom = commandData.groupIdentifierFrom; + GroupId & groupTo = commandData.groupIdentifierTo; + SceneId & sceneFrom = commandData.sceneIdentifierFrom; + SceneId & sceneTo = commandData.sceneIdentifierTo; + EndpointId & endpoint = commandPath.mEndpointId; + FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); + chip::BitMask & mode = commandPath.mode; + + // Verify Endpoint in group + VerifyOrReturn(nullptr != groupProvider, false); + if ((!groupProvider->HasEndpoint(fabricIndex, groupFrom, endpoint) && groupFrom != 0) || + (!groupProvider->HasEndpoint(fabricIndex, groupTo, endpoint) && groupTo != 0)) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); + return; + } + + // Scene Table interface data + scenes::SceneStorageId sceneStorageFrom(endpoint, sceneFrom, groupFrom); + scenes::SceneStorageId sceneStorageTo(endpoint, sceneTo, groupTo); + scenes::SceneTableEntry sceneFrom(); + scenes::SceneTableEntry sceneTo(); + + err = sceneTable->GetSceneTableEntry(fabricIndex, sceneStorageFrom, scene); + if (err != CHIP_NO_ERROR || err != CHIP_ERROR_NOT_FOUND) + { + if (err == CHIP_ERROR_NOT_FOUND) + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::NotFound); + } + else + { + ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); + } + + return; + } + + // TODO: Add get available scene space left function and return RESOURCE_EXHAUSTED on check failure + // TODO: Implement a get scene num in group methodu (or check with groupd data provider?) +} + +} // namespace Scenes +} // namespace Clusters +} // namespace app +} // namespace chip \ No newline at end of file diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index a2846dd8043d7f..54a3c22db4644b 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -353,6 +353,7 @@ class TestSceneHandler : public scenes::DefaultSceneHandlerImpl { err = CHIP_NO_ERROR; } + break; case kColorControlClusterId: if (!memcmp(serialisedBytes.data(), CC_buffer, serialisedBytes.size())) { @@ -661,7 +662,6 @@ void TestStoreScenes(nlTestSuite * aSuite, void * aContext) SceneTableEntry scene; // Set test NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene1)); - LogErrorOnFailure(sceneTable->SetSceneTableEntry(kFabric1, scene2)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene2)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene3)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sceneTable->SetSceneTableEntry(kFabric1, scene4)); From b97d19ae85f3ad090d6516ed95f288a209cd794c Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Wed, 22 Mar 2023 14:42:26 +0000 Subject: [PATCH 71/79] Restyled by whitespace --- src/app/clusters/scenes/scenes-server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/scenes-server.cpp b/src/app/clusters/scenes/scenes-server.cpp index 63fdb423836bb0..e470f647dc55b1 100644 --- a/src/app/clusters/scenes/scenes-server.cpp +++ b/src/app/clusters/scenes/scenes-server.cpp @@ -603,4 +603,4 @@ void ScenesServer::HandleCopyScene(HandlerContext & ctx, const Commands::CopySce } // namespace Scenes } // namespace Clusters } // namespace app -} // namespace chip \ No newline at end of file +} // namespace chip From 307a617c41ecf365e7e9a210f83bbb632d507cc4 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 22 Mar 2023 12:05:08 -0400 Subject: [PATCH 72/79] removed files that got added by mistake --- src/app/clusters/scenes/scenes-server.cpp | 606 ---------------------- 1 file changed, 606 deletions(-) delete mode 100644 src/app/clusters/scenes/scenes-server.cpp diff --git a/src/app/clusters/scenes/scenes-server.cpp b/src/app/clusters/scenes/scenes-server.cpp deleted file mode 100644 index e470f647dc55b1..00000000000000 --- a/src/app/clusters/scenes/scenes-server.cpp +++ /dev/null @@ -1,606 +0,0 @@ -/* - * - * Copyright (c) 2021 Project CHIP Authors - * All rights reserved. - * - * 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. - */ - -#include "scenes-server.h" -#include -#include -#include -#include -#include - -namespace chip { -namespace app { -namespace Clusters { -namespace Scenes { - -CHIP_ERROR ScenesServer::Init() {} -void ScenesServer::Shutdown() {} - -template -void AddSceneParse(HandlerContext & ctx, const CommandData & commandData) -{ - ResponseType response; - CHIP_ERROR err; - - scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); - chip::Credentials::GroupDataProvider * groupProvider = GetGroupDataProvider(); - - // Command data - GroupId & groupId = commandData.groupID; - SceneId & sceneId = commandData.sceneID; - EndpointId & endpoint = commandPath.mEndpointId; - FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - auto & transitionTime = commandData.transitionTime; - auto & sceneName = commandData.sceneName; - auto & extensionFieldSets = commandData.extensionFieldSets; - uint32_t transitionTimeMs = 0; - - // Verify Endpoint in group - VerifyOrReturn(nullptr != groupProvider, false); - if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) - { - - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); - return; - } - - if (transitionTime.HasValue()) - { - if (commandData.GetCommandId() == Commands::AddScene::Id) - { - transitionTimeMs = static_cast(transitionTime.Value() * 1000); - } - else if (commandData.GetCommandId() == Commands::EnhancedAddScene::Id) - { - transitionTimeMs = static_cast(transitionTime.Value() * 10000); - } - } - - auto fieldSetIter = extensionFieldSets.begin(); - - ClusterId tempCluster = 0; - uint8_t buffer[kMaxFieldsPerCluster]; - uint8_t EFSCount = 0; - - scenes::SceneStorageId StorageId(endpoint, sceneId, groupId); - scenes::SceneStorageData StorageData(sceneName, sceneId, transitionTimeMs, 0); - - // Goes through all EFS in command - while (fieldSetIter.Next() && EFSCount < kMaxClusterPerScenes) - { - Structs::ExtensionFieldSet::DecodableType EFS = fieldSetIter.GetValue(); - chip::scene::ExtensionFieldsSet tempEFS; - - MutableByteSpan buff_span(tempEFS.mBytesBuffer); - - // Check if a handler is registered for the EFS's cluster - for (uint8_t i = 0; i < sceneTable.handlerNum; i++) - { - sceneTable.mHandlers[i].SerializeAdd(endpoint, tempEFS.mID, tempEFS.mBytesBuffer, EFS); - } - tempEFS.mUsedBytes = buff_span.size(); - - if (!tempEFS.IsEmpty()) - { - StorageData.mExtensionFieldSet.InsertFieldSet(tempEFS); - } - } - - // Create scene from data and ID - scenes::SceneTableEntry scene(StorageId, StorageData); - - // Insert in table - err = sceneTable.SetSceneTableEntry(fabricIndex, scene); - - if (err != CHIP_NO_ERROR) - { - if (err == CHIP_ERROR_INVALID_LIST_LENGTH) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::ResourceExhausted); - } - else - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - } - return; - } - - // Write response - response.status = Protocols::InteractionModel::Status::Success; - reponse.groupID = groupId; - response.sceneID = sceneId; - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); -} - -template -void ViewSceneParse(HandlerContext & ctx, const CommandData & commandData) -{ - ResponseType response; - CHIP_ERROR err; - - scenes::SceneTable * sceneTable = chip::server::GetInstance->GetSceneTable(); - Credentials::GroupDataProvider * groupProvider = Credentials::GetGroupDataProvider(); - - // Command data - GroupId & groupId = commandData.groupID; - SceneId & sceneId = commandData.sceneID; - EndpointId & endpoint = commandPath.mEndpointId; - FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - - // Verify Endpoint in group - VerifyOrReturn(nullptr != groupProvider, false); - if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); - return; - } - - scenes::SceneStorageId StorageId(endpoint, sceneId, groupId); - scenes::SceneTableEntry scene(); - - // Gets the scene form the table - err = sceneTable->GetSceneTableEntry(fabricIndex, StorageId, scene); - if (err != CHIP_NO_ERROR) - { - if (err == CHIP_ERROR_NOT_FOUND) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::NotFound); - } - else - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - } - return; - } - - // Write response - response.status = Protocols::InteractionModel::Status::Success; - reponse.groupID = groupId; - response.sceneID = sceneId; - if (scene.mStorageData.mSceneTransitionTimeMs) - { - if (commandData.GetCommandId() == Commands::AddScene::Id) - { - response.transitionTime.SetValue(static_cast(scene.mStorageData.mSceneTransitionTimeMs / 1000)); - } - else if (commandData.GetCommandId() == Commands::AddScene::Id) - { - response.transitionTime.SetValue(static_cast(scene.mStorageData.mSceneTransitionTimeMs / 10000)); - } - } - if (!scene.mNameSpan.empty()) - { - response.sceneName.SetValue(scene.mNameSpan); - } - if (!scene.mExtensionFieldSets.IsEmpty()) - { - for (uint8_t i = 0; i < scene.mExtensionFieldSets.GetFieldNum(); i++) - { - // gets data from the field in the scene - ExtensionFieldsSet tempField; - scene.mExtensionFieldSets.GetFieldSetAtPosition(tempField, i); - ByteSpan efsSpan(tempField.mBytesBuffer, tempField.mUsedBytes); - - // This should only find one handle per cluster - for (uint8_t j = 0; j < sceneTable.mNumHandlers; j++) - { - CHIP_ERROR found; - found = sceneTable->mHandlers[j].Deserialize(endpoint, tempField.mID, efsSpan, mResponseEFSBuffer[i]); - - // Leaves loop once the handler has deserialized its cluster - if (found == CHIP_NO_ERROR) - { - break; - } - } - } - - response.extensionFieldSets.SetValue(mResponseEFSBuffer); - response.extensionFieldSets.reduce_size(scene.mExtensionFieldSets.GetFieldNum()); - } - - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); -} - -// CommandHanlerInterface -void ScenesServer::InvokeCommand(HandlerContext & ctx) -{ - if (mAsyncCommandHandle.Get() != nullptr) - { - // We have a command processing in the backend, reject all incoming commands. - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Busy); - ctx.SetCommandHandled(); - return; - } - - // Since mPath is used for building the response command, and we have checked that we are not pending the response of another - // command above. So it is safe to set the mPath here and not clear it when return. - mPath = ctx.mRequestPath; - - switch (ctx.mRequestPath.mCommandId) - { - case Commands::AddScene::Id: - HandleCommand(ctx, [this](HandlerContext & ctx, const auto & req) { - HandleAddScene(ctx, req); - }); - return; - case Commands::ViewScene::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleViewScene(ctx, req); }); - return; - case Commands::RemoveScene::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleRemoveScene(ctx, req); }); - return; - case Commands::RemoveAllScenes::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleRemoveAllScenese(ctx, req); }); - return; - case Commands::StoreScene::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleStoreScene(ctx, req); }); - return; - case Commands::RecallScene::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleRecallScene(ctx, req); }); - return; - case Commands::GetSceneMembership::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleGetSceneMembership(ctx, req); }); - return; - case Commands::EnhancedAddScene::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleAddScene(ctx, req); }); - return; - case Commands::EnhancedViewScene::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleEnhancedAddScene(ctx, req); }); - return; - case Commands::CopyScene::Id: - HandleCommand( - ctx, [this](HandlerContext & ctx, const auto & req) { HandleCopyScene(ctx, req); }); - return; - } -} - -CHIP_ERROR ScenesServer::EnumerateAcceptedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) -{} -CHIP_ERROR ScenesServer::EnumerateGeneratedCommands(const ConcreteClusterPath & cluster, CommandIdCallback callback, void * context) -{} - -void ScenesServer::HandleAddScene(HandlerContext & ctx, const Commands::EnhancedAddSceneResponse::Type & commandData) -{ - AddSceneParse(ctx, commandData); -} - -void ScenesServer::HandleViewScene(HandlerContext & ctx, const CommandData & commandData) -{ - ViewSceneParse(ctx, commandData); -} - -void ScenesServer::HandleRemoveScene(HandlerContext & ctx, const Commands::RemoveScene::DecodableType & req) -{ - Commands::RemoveSceneResponse::Type response; - CHIP_ERROR err; - - scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); - Credentials::GroupDataProvider * groupProvider = Credentials::GetGroupDataProvider(); - - // Command data - GroupId & groupId = commandData.groupID; - SceneId & sceneId = commandData.sceneID; - EndpointId & endpoint = commandPath.mEndpointId; - FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - - // Scene Table interface data - scenes::SceneStorageId sceneStorageId(endpoint, sceneId, groupId); - scenes::SceneTableEntry scene(sceneStorageId); - - // Verify Endpoint in group - VerifyOrReturn(nullptr != groupProvider, false); - if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); - return; - } - - // TODO : confirm that either using get is ok or refactor remove scene table entry to return error on removal of unexisting - // scene - // Gets the scene form the table - err = sceneTable->GetSceneTableEntry(fabricIndex, sceneStorageId, scene); - if (err != CHIP_NO_ERROR) - { - if (err == CHIP_ERROR_NOT_FOUND) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::NotFound); - } - else - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - } - return; - } - // Remove the scene from the scene table - err = sceneTable->RemoveSceneTableEntry(fabricIndex, sceneStorageId); - if (err != CHIP_NO_ERROR) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - return; - } - - // Write response - response.status = Protocols::InteractionModel::Status::Success; - reponse.groupID = groupId; - response.sceneID = sceneId; - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); -} -void ScenesServer::HandleRemoveAllScenes(HandlerContext & ctx, const Commands::RemoveAllScenes::DecodableType & req) -{ - Commands::RemoveAllScenesResponse::Type response; - CHIP_ERROR err; - - scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); - Credentials::GroupDataProvider * groupProvider = Credentials::GetGroupDataProvider(); - - // Command data - GroupId & groupId = commandData.groupID; - EndpointId & endpoint = commandPath.mEndpointId; - FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - scenes::SceneTableEntry scene(); - - // TODO: Add removal all group scene to Scene Table - - // Write response - response.status = Protocols::InteractionModel::Status::Success; - reponse.groupID = groupId; - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); -} - -void ScenesServer::HandleStoreScene(HandlerContext & ctx, const Commands::StoreScene::DecodableType & req) -{ - Commands::StoreSceneResponse::Type response; - CHIP_ERROR err; - - scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); - Credentials::GroupDataProvider * groupProvider = Credentials::GetGroupDataProvider(); - - // Command data - GroupId & groupId = commandData.groupID; - SceneId & sceneId = commandData.sceneID; - EndpointId & endpoint = commandPath.mEndpointId; - FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - - // Scene Table interface data - scenes::SceneStorageId sceneStorageId(endpoint, sceneId, groupId); - scenes::SceneTableEntry scene(sceneStorageId); - - // Verify Endpoint in group - VerifyOrReturn(nullptr != groupProvider, false); - if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); - return; - } - - // TODO: Add get available scene space left function and return RESOURCE_EXHAUSTED on check failure - - err = sceneTable->GetSceneTableEntry(fabricIndex, sceneStorageId, scene); - if (err != CHIP_NO_ERROR || err != CHIP_ERROR_NOT_FOUND) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - return; - } - - if (err == CHIP_ERROR_NOT_FOUND) - { - scene.mStorageData.SetName(CharSpan()); - scene.mStorageData.mSceneTransitionTimeMs = 0; - } - else - { - scene.mStorageData.mExtensionFieldSets.Clear(); - } - - // Gets the EFS - err = SceneSaveEFS(scene); - if (err != CHIP_NO_ERROR) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - return; - } - - // Write response - response.status = Protocols::InteractionModel::Status::Success; - reponse.groupID = groupId; - response.sceneID = sceneId; - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); -} - -void ScenesServer::HandleRecallScene(HandlerContext & ctx, const Commands::RecallScene::DecodableType & req) -{ - Commands::RecallSceneResponse::Type response; - CHIP_ERROR err; - - scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); - chip::Credentials::GroupDataProvider * groupProvider = GetGroupDataProvider(); - - // Command data - GroupId & groupId = commandData.groupID; - SceneId & sceneId = commandData.sceneID; - EndpointId & endpoint = commandPath.mEndpointId; - FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - auto & transitionTime = commandData.transitionTime; - - // Scene Table interface data - scenes::SceneStorageId sceneStorageId(endpoint, sceneId, groupId); - scenes::SceneTableEntry scene(sceneStorageId); - - // Verify Endpoint in group - VerifyOrReturn(nullptr != groupProvider, false); - if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); - return; - } - - err = sceneTable->GetSceneTableEntry(fabricIndex, sceneStorageId, scene); - if (err != CHIP_NO_ERROR) - { - if (err == CHIP_ERROR_NOT_FOUND) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::NotFound); - } - else - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - } - return; - } - - if (transitionTime.HasValue()) - { - scene.mStorageData.mTransitionTimeMs += transitionTime.Value() * 100; - } - - err = SceneApplyEFS(scene); - if (err != CHIP_NO_ERROR) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - return; - } - - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Success); - return; -} - -void ScenesServer::HandleGetSceneMembership(HandlerContext & ctx, const Commands::GetSceneMembership::DecodableType & req) -{ - Commands::GetSceneMembershipResponse::Type response; - CHIP_ERROR err; - uint8_t capacity = 0; - uint8_t sceneGroupCount = 0; - - scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); - chip::Credentials::GroupDataProvider * groupProvider = GetGroupDataProvider(); - - // Command data - GroupId & groupId = commandData.groupID; - EndpointId & endpoint = commandPath.mEndpointId; - FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - - // Scene Table interface data - SceneId scenesInGroup[kMaxScenePerFabric]; - ByteSpan sceneList(scenesInGroup); - scenes::SceneTableEntry scene; - - // Verify Endpoint in group - VerifyOrReturn(nullptr != groupProvider, false); - if (!groupProvider->HasEndpoint(fabricIndex, groupId, endpoint) && groupId != 0) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); - return; - } - - // TODO: implement a get space left in Fabric and in Scene Table - // Get Capacity - - // Iterate through fabrics scene to populate scene list - auto iterator = sceneTable->IterateSceneEntries(fabricIndex); - - while (iterator->Next(scene)) - { - if (scene.mGroupId == groupId) - { - scenesInGroup[sceneGroupCount] = scene.mStorageId.mSceneId; - sceneGroupCount++; - } - } - sceneList.reduce_size(sceneGroupCount); - - // Write response - response.status = Protocols::InteractionModel::Status::Success; - response.Capacity.SetValue(capacity); - response.groupID = groupId; - response.sceneList = sceneList; - ctx.mCommandHandler.AddResponse(ctx.mRequestPath, response); -} - -void ScenesServer::HandleEnhancedAddScene(HandlerContext & ctx, const Commands::EnhancedAddScene::DecodableType & req) -{ - AddSceneParse(ctx, commandData); -} - -void ScenesServer::HandleEnhancedViewScene(HandlerContext & ctx, const Commands::EnhancedViewScene::DecodableType & req) -{ - ViewSceneParse(ctx, commandData); -} -void ScenesServer::HandleCopyScene(HandlerContext & ctx, const Commands::CopyScene::DecodableType & req) -{ - Commands::CopySceneResponse::Type response; - CHIP_ERROR err; - - scenes::DefaultSceneTableImpl * sceneTable = chip::server::GetInstance->GetSceneTable(); - chip::Credentials::GroupDataProvider * groupProvider = GetGroupDataProvider(); - - // Command data - GroupId & groupFrom = commandData.groupIdentifierFrom; - GroupId & groupTo = commandData.groupIdentifierTo; - SceneId & sceneFrom = commandData.sceneIdentifierFrom; - SceneId & sceneTo = commandData.sceneIdentifierTo; - EndpointId & endpoint = commandPath.mEndpointId; - FabricIndex fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex(); - chip::BitMask & mode = commandPath.mode; - - // Verify Endpoint in group - VerifyOrReturn(nullptr != groupProvider, false); - if ((!groupProvider->HasEndpoint(fabricIndex, groupFrom, endpoint) && groupFrom != 0) || - (!groupProvider->HasEndpoint(fabricIndex, groupTo, endpoint) && groupTo != 0)) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::InvalidCommand); - return; - } - - // Scene Table interface data - scenes::SceneStorageId sceneStorageFrom(endpoint, sceneFrom, groupFrom); - scenes::SceneStorageId sceneStorageTo(endpoint, sceneTo, groupTo); - scenes::SceneTableEntry sceneFrom(); - scenes::SceneTableEntry sceneTo(); - - err = sceneTable->GetSceneTableEntry(fabricIndex, sceneStorageFrom, scene); - if (err != CHIP_NO_ERROR || err != CHIP_ERROR_NOT_FOUND) - { - if (err == CHIP_ERROR_NOT_FOUND) - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::NotFound); - } - else - { - ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Protocols::InteractionModel::Status::Failure); - } - - return; - } - - // TODO: Add get available scene space left function and return RESOURCE_EXHAUSTED on check failure - // TODO: Implement a get scene num in group methodu (or check with groupd data provider?) -} - -} // namespace Scenes -} // namespace Clusters -} // namespace app -} // namespace chip From 1618b5880d1aac3c4f2b8a7c96f24097fd9919cc Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 22 Mar 2023 14:35:33 -0400 Subject: [PATCH 73/79] Fix test namespace conflicts in TestSetup and TestTeardown --- src/app/tests/TestExtensionFieldSets.cpp | 11 +++++----- src/app/tests/TestSceneTable.cpp | 26 ++++++++++-------------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/src/app/tests/TestExtensionFieldSets.cpp b/src/app/tests/TestExtensionFieldSets.cpp index 3181a5410ff216..ce363462cb6fee 100644 --- a/src/app/tests/TestExtensionFieldSets.cpp +++ b/src/app/tests/TestExtensionFieldSets.cpp @@ -24,7 +24,7 @@ using namespace chip; -namespace { +namespace TestEFS { enum class TagTestEFS : uint8_t { @@ -304,7 +304,7 @@ void TestRemoveExtensionFieldSet(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, true == EFS->IsEmpty()); } -} // namespace +} // namespace TestEFS /** * Tear down the test suite. */ @@ -327,9 +327,10 @@ int TestTeardown(void * inContext) int TestExtensionFieldSets() { - static nlTest sTests[] = { NL_TEST_DEF("TestInsertExtensionFieldSet", TestInsertExtensionFieldSet), - NL_TEST_DEF("TestSerializeDerializeExtensionFieldSet", TestSerializeDerializeExtensionFieldSet), - NL_TEST_DEF("TestRemoveExtensionFieldSet", TestRemoveExtensionFieldSet), + static nlTest sTests[] = { NL_TEST_DEF("TestInsertExtensionFieldSet", TestEFS::TestInsertExtensionFieldSet), + NL_TEST_DEF("TestSerializeDerializeExtensionFieldSet", + TestEFS::TestSerializeDerializeExtensionFieldSet), + NL_TEST_DEF("TestRemoveExtensionFieldSet", TestEFS::TestRemoveExtensionFieldSet), NL_TEST_SENTINEL() }; diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 54a3c22db4644b..607152b1aea4be 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -34,11 +34,7 @@ using SceneData = scenes::DefaultSceneTableImpl::SceneData; using ExtensionFieldSet = scenes::ExtensionFieldSet; using TransitionTimeMs = scenes::TransitionTimeMs; -namespace { - -// Group constants -constexpr uint16_t kMaxGroupsPerFabric = 5; -constexpr uint16_t kMaxGroupKeysPerFabric = 4; +namespace TestScenes { // Test Cluster ID constexpr chip::ClusterId kOnOffClusterId = 0x0006; @@ -918,7 +914,7 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_ERROR_NOT_FOUND == sceneTable->GetSceneTableEntry(kFabric2, sceneId3, scene)); } -} // namespace +} // namespace TestScenes /** * Tear down the test suite. @@ -928,7 +924,7 @@ int TestSetup(void * inContext) VerifyOrReturnError(CHIP_NO_ERROR == chip::Platform::MemoryInit(), FAILURE); // Initialize Scene Table - VerifyOrReturnError(CHIP_NO_ERROR == sSceneTable.Init(&testStorage), FAILURE); + VerifyOrReturnError(CHIP_NO_ERROR == TestScenes::sSceneTable.Init(&TestScenes::testStorage), FAILURE); return SUCCESS; } @@ -938,7 +934,7 @@ int TestSetup(void * inContext) */ int TestTeardown(void * inContext) { - sSceneTable.Finish(); + TestScenes::sSceneTable.Finish(); chip::Platform::MemoryShutdown(); return SUCCESS; @@ -946,13 +942,13 @@ int TestTeardown(void * inContext) int TestSceneTable() { - static nlTest sTests[] = { NL_TEST_DEF("TestHandlerRegistration", TestHandlerRegistration), - NL_TEST_DEF("TestHandlerFunctions", TestHandlerFunctions), - NL_TEST_DEF("TestStoreScenes", TestStoreScenes), - NL_TEST_DEF("TestOverwriteScenes", TestOverwriteScenes), - NL_TEST_DEF("TestIterateScenes", TestIterateScenes), - NL_TEST_DEF("TestRemoveScenes", TestRemoveScenes), - NL_TEST_DEF("TestFabricScenes", TestFabricScenes), + static nlTest sTests[] = { NL_TEST_DEF("TestHandlerRegistration", TestScenes::TestHandlerRegistration), + NL_TEST_DEF("TestHandlerFunctions", TestScenes::TestHandlerFunctions), + NL_TEST_DEF("TestStoreScenes", TestScenes::TestStoreScenes), + NL_TEST_DEF("TestOverwriteScenes", TestScenes::TestOverwriteScenes), + NL_TEST_DEF("TestIterateScenes", TestScenes::TestIterateScenes), + NL_TEST_DEF("TestRemoveScenes", TestScenes::TestRemoveScenes), + NL_TEST_DEF("TestFabricScenes", TestScenes::TestFabricScenes), NL_TEST_SENTINEL() }; From f7484471c8a06ae047d1d63da97c3d7f29130b09 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 22 Mar 2023 15:33:03 -0400 Subject: [PATCH 74/79] Separating namespaces in tests --- src/app/tests/TestExtensionFieldSets.cpp | 4 +++- src/app/tests/TestSceneTable.cpp | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/tests/TestExtensionFieldSets.cpp b/src/app/tests/TestExtensionFieldSets.cpp index ce363462cb6fee..3f9400fe109e03 100644 --- a/src/app/tests/TestExtensionFieldSets.cpp +++ b/src/app/tests/TestExtensionFieldSets.cpp @@ -315,8 +315,9 @@ int TestSetup(void * inContext) return SUCCESS; } +namespace { /** - * Tear down the test suite. + * Setup the test suite. */ int TestTeardown(void * inContext) { @@ -324,6 +325,7 @@ int TestTeardown(void * inContext) return SUCCESS; } +} // namespace int TestExtensionFieldSets() { diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index 607152b1aea4be..cb1833312fa1f9 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -916,8 +916,9 @@ void TestFabricScenes(nlTestSuite * aSuite, void * aContext) } // namespace TestScenes +namespace { /** - * Tear down the test suite. + * Setup the test suite. */ int TestSetup(void * inContext) { @@ -939,6 +940,7 @@ int TestTeardown(void * inContext) return SUCCESS; } +} // namespace int TestSceneTable() { From 9e4f83be27b6f9f96b5412f6d5429a559b05b559 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Thu, 23 Mar 2023 17:00:32 -0400 Subject: [PATCH 75/79] Apply suggestions from code review Co-authored-by: Boris Zbarsky --- .../clusters/scenes/ExtensionFieldSetsImpl.cpp | 3 +-- src/app/clusters/scenes/SceneTable.h | 17 ++++++++--------- src/app/clusters/scenes/SceneTableImpl.cpp | 2 +- src/app/clusters/scenes/SceneTableImpl.h | 6 +++--- 4 files changed, 13 insertions(+), 15 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 8c9c2870a7ed3c..d45f0bdd2eb3ed 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -26,7 +26,6 @@ CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer, TLV::Tag s { TLV::TLVType container; ReturnErrorOnFailure(writer.StartContainer(structTag, TLV::kTLVType_Structure, container)); - // ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagEFS::kFieldSetsCount), static_cast(mFieldSetsCount))); ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(TagEFS::kFieldSetArrayContainer), TLV::kTLVType_Array, container)); for (uint8_t i = 0; i < mFieldSetsCount; i++) { @@ -132,7 +131,7 @@ CHIP_ERROR ExtensionFieldSetsImpl::RemoveFieldAtPosition(uint8_t position) mFieldSetsCount--; // Clear last occupied position - mFieldSets[mFieldSetsCount].Clear(); // + mFieldSets[mFieldSetsCount].Clear(); return CHIP_NO_ERROR; } diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 8333416b86f286..5736077c69e471 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -50,7 +50,7 @@ static constexpr size_t kSceneNameMaxLength = CHIP_CONFIG_SCENES_CLUSTER_MAXIMUM /// /// A SceneHandler can handle a single pair, or many such pairs. /// -/// @note If more than one handler claims to handl a specific pair, only one of +/// @note If more than one handler claims to handle a specific pair, only one of /// those handlers will get called when executing actions related to extension field sets on the scene /// table. It is not defined which handler will be selected. @@ -110,8 +110,7 @@ class SceneHandler : public IntrusiveListNodeBase<> /// /// @param extensionFieldSet[out] ExtensionFieldSet in command format /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - /// @note Only gets called after the scene-cluster has previously verified that the endpoint,cluster valuer pair is supported by - /// the handler. It is therefore the implementation's reponsibility to also implement the SupportsCluster method. + /// @note Only gets called for handlers for which SupportsCluster() is true for the given endpoint and cluster. virtual CHIP_ERROR Deserialize(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, app::Clusters::Scenes::Structs::ExtensionFieldSet::Type & extensionFieldSet) = 0; @@ -220,16 +219,16 @@ class SceneTable bool operator==(const SceneData & other) { - return (this->mNameLength == other.mNameLength && !memcmp(this->mName, other.mName, this->mNameLength) && - (this->mSceneTransitionTimeMs == other.mSceneTransitionTimeMs) && - (this->mExtensionFieldSets == other.mExtensionFieldSets)); + return (mNameLength == other.mNameLength && !memcmp(mName, other.mName,mNameLength) && + (mSceneTransitionTimeMs == other.mSceneTransitionTimeMs) && + (mExtensionFieldSets == other.mExtensionFieldSets)); } void operator=(const SceneData & other) { - this->SetName(CharSpan(other.mName, other.mNameLength)); - this->mExtensionFieldSets = other.mExtensionFieldSets; - this->mSceneTransitionTimeMs = other.mSceneTransitionTimeMs; + SetName(CharSpan(other.mName, other.mNameLength)); + mExtensionFieldSets = other.mExtensionFieldSets; + mSceneTransitionTimeMs = other.mSceneTransitionTimeMs; } }; diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index e439f5b9721374..6e183a93cf93c5 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -24,7 +24,7 @@ namespace chip { namespace scenes { /// @brief Tags Used to serialize Scenes so they can be stored in flash memory. -/// kSceneCount: Number of scene in a Fabric +/// kSceneCount: Number of scenes in a Fabric /// kStorageIDArray: Array of StorageID struct /// kEndpointID: Tag for the Endpoint ID to which this scene applies to /// kGroupID: Tag for GroupID if the Scene is a Group Scene diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index f10b89953e4375..c566dcf5a05294 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -50,7 +50,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @return CHIP_NO_ERROR if successful, CHIP_ERROR_INVALID_ARGUMENT if the cluster is not supported, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, - ClusterId & cluster, MutableByteSpan & serialisedBytes) override + ClusterId & cluster, MutableByteSpan & serializedBytes) override { app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; TLV::TLVWriter writer; @@ -93,7 +93,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler writer.Init(serialisedBytes); ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); ReturnErrorOnFailure(app::DataModel::Encode( - writer, TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + writer, TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList), attributeValueList)); ReturnErrorOnFailure(writer.EndContainer(outer)); @@ -125,7 +125,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler ReturnErrorOnFailure(reader.EnterContainer(outer)); ReturnErrorOnFailure(reader.Next( TLV::kTLVType_Array, - TLV::ContextTag(to_underlying(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)))); + TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList))); attributeValueList.Decode(reader); auto pair_iterator = attributeValueList.begin(); From b1131725f201d486044ec11dc03cd7a2512631ad Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Thu, 23 Mar 2023 19:14:44 -0400 Subject: [PATCH 76/79] Added check for Size ahead of loop in handler SerializeAdd/Deserialize (default) fized TLV containers and Deserialize error ocndition for extension field sets and scene map --- .../scenes/ExtensionFieldSetsImpl.cpp | 40 ++++--- src/app/clusters/scenes/SceneTable.h | 12 +- src/app/clusters/scenes/SceneTableImpl.cpp | 35 +++--- src/app/clusters/scenes/SceneTableImpl.h | 64 ++++++----- src/app/tests/TestSceneTable.cpp | 104 ++++++++++++++++-- 5 files changed, 183 insertions(+), 72 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index d45f0bdd2eb3ed..6e2817ba6b6709 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -24,26 +24,29 @@ namespace scenes { CHIP_ERROR ExtensionFieldSetsImpl::Serialize(TLV::TLVWriter & writer, TLV::Tag structTag) const { - TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(structTag, TLV::kTLVType_Structure, container)); - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(TagEFS::kFieldSetArrayContainer), TLV::kTLVType_Array, container)); + TLV::TLVType structureContainer; + ReturnErrorOnFailure(writer.StartContainer(structTag, TLV::kTLVType_Structure, structureContainer)); + TLV::TLVType arrayContainer; + ReturnErrorOnFailure( + writer.StartContainer(TLV::ContextTag(TagEFS::kFieldSetArrayContainer), TLV::kTLVType_Array, arrayContainer)); for (uint8_t i = 0; i < mFieldSetsCount; i++) { ReturnErrorOnFailure(mFieldSets[i].Serialize(writer)); } - return writer.EndContainer(container); - return writer.EndContainer(container); + ReturnErrorOnFailure(writer.EndContainer(arrayContainer)); + return writer.EndContainer(structureContainer); } CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader, TLV::Tag structTag) { - TLV::TLVType container; + TLV::TLVType structureContainer; ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, structTag)); - ReturnErrorOnFailure(reader.EnterContainer(container)); + ReturnErrorOnFailure(reader.EnterContainer(structureContainer)); + TLV::TLVType arrayContainer; ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Array, TLV::ContextTag(TagEFS::kFieldSetArrayContainer))); - ReturnErrorOnFailure(reader.EnterContainer(container)); + ReturnErrorOnFailure(reader.EnterContainer(arrayContainer)); uint8_t i = 0; CHIP_ERROR err; @@ -54,19 +57,26 @@ CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader, TLV::Tag } mFieldSetsCount = i; - VerifyOrReturnError(err == CHIP_END_OF_TLV, err); - return reader.ExitContainer(container); + if (err != CHIP_END_OF_TLV) + { + if (err == CHIP_NO_ERROR) + return CHIP_ERROR_BUFFER_TOO_SMALL; + + return err; + } + + ReturnErrorOnFailure(reader.ExitContainer(arrayContainer)); + return reader.ExitContainer(structureContainer); } void ExtensionFieldSetsImpl::Clear() { - if (!this->IsEmpty()) + + for (uint8_t i = 0; i < mFieldSetsCount; i++) { - for (uint8_t i = 0; i < mFieldSetsCount; i++) - { - mFieldSets[i].Clear(); - } + mFieldSets[i].Clear(); } + mFieldSetsCount = 0; } diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 5736077c69e471..6b38add6948ea7 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -66,7 +66,6 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @param clusterBuffer Buffer to hold the supported cluster IDs, cannot hold more than /// CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE. The function shall use the reduce_size() method in the event it is supporting /// less than CHIP_CONFIG_SCENES_MAX_CLUSTERS_PER_SCENE clusters. - virtual void GetSupportedClusters(EndpointId endpoint, Span & clusterBuffer) = 0; /// @brief Returns whether or not a cluster for scenes is supported on an endpoint @@ -81,14 +80,13 @@ class SceneHandler : public IntrusiveListNodeBase<> /// /// @param endpoint[in] Endpoint ID /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized - /// @param cluster[out] Cluster in the Extension field set, filled by the function /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise /// @note Only gets called after the scene-cluster has previously verified that the endpoint,cluster valuer pair is supported by /// the handler. It is therefore the implementation's reponsibility to also implement the SupportsCluster method. virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, - ClusterId & cluster, MutableByteSpan & serialisedBytes) = 0; + MutableByteSpan & serialisedBytes) = 0; /// @brief Called when handling StoreScene, and only if the handler supports the given endpoint and cluster. /// @@ -98,7 +96,7 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @param cluster[in] Target Cluster /// @param serializedBytes[out] Output buffer, data needs to be writen in there and size adjusted to the size of the data /// written. - + /// /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeSave(EndpointId endpoint, ClusterId cluster, MutableByteSpan & serializedBytes) = 0; @@ -123,6 +121,7 @@ class SceneHandler : public IntrusiveListNodeBase<> /// /// @param timeMs[in] Transition time in ms to apply the scene /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise + /// @note Only gets called for handlers for which SupportsCluster() is true for the given endpoint and cluster. virtual CHIP_ERROR ApplyScene(EndpointId endpoint, ClusterId cluster, const ByteSpan & serializedBytes, TransitionTimeMs timeMs) = 0; }; @@ -219,9 +218,8 @@ class SceneTable bool operator==(const SceneData & other) { - return (mNameLength == other.mNameLength && !memcmp(mName, other.mName,mNameLength) && - (mSceneTransitionTimeMs == other.mSceneTransitionTimeMs) && - (mExtensionFieldSets == other.mExtensionFieldSets)); + return (mNameLength == other.mNameLength && !memcmp(mName, other.mName, mNameLength) && + (mSceneTransitionTimeMs == other.mSceneTransitionTimeMs) && (mExtensionFieldSets == other.mExtensionFieldSets)); } void operator=(const SceneData & other) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index 6e183a93cf93c5..a919283ff9a08b 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -176,55 +176,60 @@ struct FabricSceneData : public PersistentData CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override { - TLV::TLVType container; - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); + TLV::TLVType fabricSceneContainer; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, fabricSceneContainer)); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kSceneCount), scene_count)); - ReturnErrorOnFailure(writer.StartContainer(TLV::ContextTag(TagScene::kStorageIDArray), TLV::kTLVType_Array, container)); + TLV::TLVType sceneMapContainer; + ReturnErrorOnFailure( + writer.StartContainer(TLV::ContextTag(TagScene::kStorageIDArray), TLV::kTLVType_Array, sceneMapContainer)); // Storing the scene map for (uint8_t i = 0; i < kMaxScenesPerFabric; i++) { - ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, container)); + TLV::TLVType sceneIdContainer; + ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, sceneIdContainer)); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kEndpointID), (scene_map[i].mEndpointId))); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kGroupID), (scene_map[i].mGroupId))); ReturnErrorOnFailure(writer.Put(TLV::ContextTag(TagScene::kSceneID), (scene_map[i].mSceneId))); - ReturnErrorOnFailure(writer.EndContainer(container)); + ReturnErrorOnFailure(writer.EndContainer(sceneIdContainer)); } - ReturnErrorOnFailure(writer.EndContainer(container)); - return writer.EndContainer(container); + ReturnErrorOnFailure(writer.EndContainer(sceneMapContainer)); + return writer.EndContainer(fabricSceneContainer); } CHIP_ERROR Deserialize(TLV::TLVReader & reader) override { ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); - TLV::TLVType container; - ReturnErrorOnFailure(reader.EnterContainer(container)); + TLV::TLVType fabricSceneContainer; + ReturnErrorOnFailure(reader.EnterContainer(fabricSceneContainer)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kSceneCount))); ReturnErrorOnFailure(reader.Get(scene_count)); ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Array, TLV::ContextTag(TagScene::kStorageIDArray))); - ReturnErrorOnFailure(reader.EnterContainer(container)); + TLV::TLVType sceneMapContainer; + ReturnErrorOnFailure(reader.EnterContainer(sceneMapContainer)); uint8_t i = 0; CHIP_ERROR err; while ((err = reader.Next(TLV::AnonymousTag())) == CHIP_NO_ERROR && i < kMaxScenesPerFabric) { - ReturnErrorOnFailure(reader.EnterContainer(container)); + TLV::TLVType sceneIdContainer; + ReturnErrorOnFailure(reader.EnterContainer(sceneIdContainer)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kEndpointID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mEndpointId)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kGroupID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mGroupId)); ReturnErrorOnFailure(reader.Next(TLV::ContextTag(TagScene::kSceneID))); ReturnErrorOnFailure(reader.Get(scene_map[i].mSceneId)); - ReturnErrorOnFailure(reader.ExitContainer(container)); + ReturnErrorOnFailure(reader.ExitContainer(sceneIdContainer)); i++; } - VerifyOrReturnError(err == CHIP_END_OF_TLV, err); + VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_NO_ERROR, err); - ReturnErrorOnFailure(reader.ExitContainer(container)); - return reader.ExitContainer(container); + ReturnErrorOnFailure(reader.ExitContainer(sceneMapContainer)); + return reader.ExitContainer(fabricSceneContainer); } /// @brief Finds the index where to insert current scene by going through the whole table and looking if the scene is already in diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index c566dcf5a05294..734cc122dfda16 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -45,42 +45,44 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler /// @brief From command AddScene, allows handler to filter through clusters in command to serialize only the supported ones. /// @param endpoint[in] Endpoint ID /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized - /// @param cluster[out] Cluster in the Extension field set, filled by the function /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command /// @return CHIP_NO_ERROR if successful, CHIP_ERROR_INVALID_ARGUMENT if the cluster is not supported, CHIP_ERROR value otherwise virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, - ClusterId & cluster, MutableByteSpan & serializedBytes) override + MutableByteSpan & serializedBytes) override { app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; TLV::TLVWriter writer; TLV::TLVType outer; + size_t pairTotal = 0; + uint8_t pairCount = 0; - uint8_t pairCount = 0; - uint8_t valueBytes = 0; - - VerifyOrReturnError(SupportsCluster(endpoint, extensionFieldSet.clusterID), CHIP_ERROR_INVALID_ARGUMENT); - - cluster = extensionFieldSet.clusterID; + // Verify size of list + extensionFieldSet.attributeValueList.ComputeSize(&pairTotal); + VerifyOrReturnError(pairTotal <= kMaxAvPair, CHIP_ERROR_BUFFER_TOO_SMALL); auto pair_iterator = extensionFieldSet.attributeValueList.begin(); while (pair_iterator.Next() && pairCount < kMaxAvPair) { aVPair = pair_iterator.GetValue(); mAVPairs[pairCount].attributeID = aVPair.attributeID; - auto value_iterator = aVPair.attributeValue.begin(); + size_t valueBytesTotal = 0; + uint8_t valueBytesCount = 0; - valueBytes = 0; - while (value_iterator.Next() && valueBytes < kMaxValueSize) + aVPair.attributeValue.ComputeSize(&valueBytesTotal); + VerifyOrReturnError(valueBytesTotal <= kMaxValueSize, CHIP_ERROR_BUFFER_TOO_SMALL); + + auto value_iterator = aVPair.attributeValue.begin(); + while (value_iterator.Next()) { - mValueBuffer[pairCount][valueBytes] = value_iterator.GetValue(); - valueBytes++; + mValueBuffer[pairCount][valueBytesCount] = value_iterator.GetValue(); + valueBytesCount++; } // Check we could go through all bytes of the value ReturnErrorOnFailure(value_iterator.GetStatus()); mAVPairs[pairCount].attributeValue = mValueBuffer[pairCount]; - mAVPairs[pairCount].attributeValue.reduce_size(valueBytes); + mAVPairs[pairCount].attributeValue.reduce_size(valueBytesCount); pairCount++; } // Check we could go through all pairs in incomming command @@ -90,7 +92,7 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler attributeValueList = mAVPairs; attributeValueList.reduce_size(pairCount); - writer.Init(serialisedBytes); + writer.Init(serializedBytes); ReturnErrorOnFailure(writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outer)); ReturnErrorOnFailure(app::DataModel::Encode( writer, TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList), @@ -114,38 +116,44 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler TLV::TLVReader reader; TLV::TLVType outer; - uint8_t pairCount = 0; - uint8_t valueBytes = 0; - - VerifyOrReturnError(SupportsCluster(endpoint, cluster), CHIP_ERROR_INVALID_ARGUMENT); + size_t pairTotal = 0; + uint8_t pairCount = 0; extensionFieldSet.clusterID = cluster; reader.Init(serialisedBytes); ReturnErrorOnFailure(reader.Next(TLV::kTLVType_Structure, TLV::AnonymousTag())); ReturnErrorOnFailure(reader.EnterContainer(outer)); ReturnErrorOnFailure(reader.Next( - TLV::kTLVType_Array, - TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList))); + TLV::kTLVType_Array, TLV::ContextTag(app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList))); attributeValueList.Decode(reader); + // Verify size of list + attributeValueList.ComputeSize(&pairTotal); + VerifyOrReturnError(pairTotal <= kMaxAvPair, CHIP_ERROR_BUFFER_TOO_SMALL); + auto pair_iterator = attributeValueList.begin(); - while (pair_iterator.Next() && pairCount < kMaxAvPair) + while (pair_iterator.Next()) { decodePair = pair_iterator.GetValue(); mAVPairs[pairCount].attributeID = decodePair.attributeID; - auto value_iterator = decodePair.attributeValue.begin(); - valueBytes = 0; + size_t valueBytesTotal = 0; + uint8_t valueBytesCount = 0; + + // Verify size of attribute value + decodePair.attributeValue.ComputeSize(&valueBytesTotal); + VerifyOrReturnError(valueBytesTotal <= kMaxValueSize, CHIP_ERROR_BUFFER_TOO_SMALL); - while (value_iterator.Next() && valueBytes < kMaxValueSize) + auto value_iterator = decodePair.attributeValue.begin(); + while (value_iterator.Next() && valueBytesCount < kMaxValueSize) { - mValueBuffer[pairCount][valueBytes] = value_iterator.GetValue(); - valueBytes++; + mValueBuffer[pairCount][valueBytesCount] = value_iterator.GetValue(); + valueBytesCount++; } // Check we could go through all bytes of the value ReturnErrorOnFailure(value_iterator.GetStatus()); mAVPairs[pairCount].attributeValue = mValueBuffer[pairCount]; - mAVPairs[pairCount].attributeValue.reduce_size(valueBytes); + mAVPairs[pairCount].attributeValue.reduce_size(valueBytesCount); pairCount++; }; // Check we could go through all pairs stored in memory diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index cb1833312fa1f9..cb054418295457 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -439,7 +439,6 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldSetIn; - app::Clusters::Scenes::Structs::AttributeValuePair::DecodableType aVPair; TLV::TLVReader reader; TLV::TLVWriter writer; @@ -542,11 +541,11 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldSetIn, tempCluster, buff_span)); + NL_TEST_ASSERT(aSuite, sHandler.SupportsCluster(kTestEndpoint1, extensionFieldSetIn.clusterID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldSetIn, buff_span)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(OO_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == kOnOffClusterId); memset(buffer, 0, buff_span.size()); // Setup the Level Control Extension field set in the expected state from a command @@ -558,11 +557,11 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldSetIn, tempCluster, buff_span)); + NL_TEST_ASSERT(aSuite, sHandler.SupportsCluster(kTestEndpoint1, extensionFieldSetIn.clusterID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldSetIn, buff_span)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(LC_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == kLevelControlClusterId); memset(buffer, 0, buff_span.size()); // Setup the Color control Extension field set in the expected state from a command @@ -574,14 +573,15 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldSetIn.attributeValueList.Decode(reader)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(outerRead)); - NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint2, extensionFieldSetIn, tempCluster, buff_span)); + NL_TEST_ASSERT(aSuite, sHandler.SupportsCluster(kTestEndpoint2, extensionFieldSetIn.clusterID)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.SerializeAdd(kTestEndpoint2, extensionFieldSetIn, buff_span)); // Verify the handler extracted buffer matches the initial field sets NL_TEST_ASSERT(aSuite, 0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size())); - NL_TEST_ASSERT(aSuite, tempCluster == kColorControlClusterId); memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for on off + NL_TEST_ASSERT(aSuite, sHandler.SupportsCluster(kTestEndpoint1, kOnOffClusterId)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint1, kOnOffClusterId, OO_list, extensionFieldSetOut)); // Verify Encoding the Extension field set returns the same data as the one serialized for on off previously @@ -598,6 +598,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for level control + NL_TEST_ASSERT(aSuite, sHandler.SupportsCluster(kTestEndpoint1, kLevelControlClusterId)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint1, kLevelControlClusterId, LC_list, extensionFieldSetOut)); @@ -615,6 +616,7 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) memset(buffer, 0, buff_span.size()); // Verify Deserializing is properly filling out output extension field set for color control + NL_TEST_ASSERT(aSuite, sHandler.SupportsCluster(kTestEndpoint2, kColorControlClusterId)); NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == sHandler.Deserialize(kTestEndpoint2, kColorControlClusterId, CC_list, extensionFieldSetOut)); @@ -630,6 +632,94 @@ void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == writer.EndContainer(outer)); NL_TEST_ASSERT(aSuite, 0 == memcmp(CC_list.data(), buff_span.data(), buff_span.size())); memset(buffer, 0, buff_span.size()); + + // To test failure on serialize and deserialize when too many pairs are in the field sets + app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldFailTestOut; + app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldFailTestIn; + app::Clusters::Scenes::Structs::AttributeValuePair::Type TooManyPairs[16]; + app::Clusters::Scenes::Structs::AttributeValuePair::Type TooManyBytesPairs[1]; + + TLV::TLVType failWrite; + TLV::TLVType failRead; + + uint8_t payloadOk[1] = { 0 }; + uint8_t payloadTooBig[5] = { 0 }; + + for (uint8_t i = 0; i < 16; i++) + { + TooManyPairs[i].attributeValue = payloadOk; + } + + TooManyBytesPairs[0].attributeValue = payloadTooBig; + + extensionFieldFailTestOut.clusterID = kColorControlClusterId; + extensionFieldFailTestOut.attributeValueList = TooManyPairs; + + uint8_t failBuffer[scenes::kMaxFieldBytesPerCluster] = { 0 }; + ByteSpan fail_list(failBuffer); + + // Serialize Extension Field sets as if they were recovered from memory + writer.Init(failBuffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, failWrite); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + app::DataModel::Encode(writer, + TLV::ContextTag(to_underlying( + app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + extensionFieldFailTestOut.attributeValueList)); + writer.EndContainer(failWrite); + + // Setup the On Off Extension field set in the expected state from a command + reader.Init(fail_list); + extensionFieldFailTestIn.clusterID = kColorControlClusterId; + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(failRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldFailTestIn.attributeValueList.Decode(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(failRead)); + + // Verify failure on both serialize and deserialize + NL_TEST_ASSERT(aSuite, + CHIP_ERROR_BUFFER_TOO_SMALL == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldFailTestIn, buff_span)); + NL_TEST_ASSERT(aSuite, + CHIP_ERROR_BUFFER_TOO_SMALL == + sHandler.Deserialize(kTestEndpoint1, kColorControlClusterId, fail_list, extensionFieldFailTestOut)); + + memset(failBuffer, 0, fail_list.size()); + memset(buffer, 0, buff_span.size()); + + extensionFieldFailTestOut.clusterID = kColorControlClusterId; + extensionFieldFailTestOut.attributeValueList = TooManyBytesPairs; + + // Serialize Extension Field sets as if they were recovered from memory + writer.Init(failBuffer); + writer.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, failWrite); + NL_TEST_ASSERT(aSuite, + CHIP_NO_ERROR == + app::DataModel::Encode(writer, + TLV::ContextTag(to_underlying( + app::Clusters::Scenes::Structs::ExtensionFieldSet::Fields::kAttributeValueList)), + extensionFieldFailTestOut.attributeValueList)); + writer.EndContainer(failWrite); + + // Setup the On Off Extension field set in the expected state from a command + reader.Init(fail_list); + extensionFieldFailTestIn.clusterID = kColorControlClusterId; + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.EnterContainer(failRead)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.Next()); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == extensionFieldFailTestIn.attributeValueList.Decode(reader)); + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == reader.ExitContainer(failRead)); + + // Verify failure on both serialize and deserialize + NL_TEST_ASSERT(aSuite, + CHIP_ERROR_BUFFER_TOO_SMALL == sHandler.SerializeAdd(kTestEndpoint1, extensionFieldFailTestIn, buff_span)); + NL_TEST_ASSERT(aSuite, + CHIP_ERROR_BUFFER_TOO_SMALL == + sHandler.Deserialize(kTestEndpoint1, kColorControlClusterId, fail_list, extensionFieldFailTestOut)); + + memset(failBuffer, 0, fail_list.size()); + memset(buffer, 0, buff_span.size()); }; void TestStoreScenes(nlTestSuite * aSuite, void * aContext) From 5cce38cfdf9e2ded4aadd80c8438b474ccafb7bc Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Fri, 24 Mar 2023 11:14:32 -0400 Subject: [PATCH 77/79] Added comment for behavior in case of changes in kMaxScenePerFabric and kMaxClustersPerScene --- src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp | 4 ++++ src/app/clusters/scenes/SceneTableImpl.cpp | 3 +++ src/app/tests/TestSceneTable.cpp | 1 - 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index 6e2817ba6b6709..f50bf4f58f257d 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -57,6 +57,10 @@ CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader, TLV::Tag } mFieldSetsCount = i; + // In the event of an OTA where the maximum number of cluster per scene has been reduced, the extension field set will be + // considered "corrupted" if we don't manage to load it all (if err == CHIP_NO_ERROR after the loop). We therefore return an + // error and this scene will have to be deleted. This is done because truncating an EFS doesn't garrantee the order of the + // clusters loaded, which might allow to load clusters that are no longer supported and loosing supported ones. if (err != CHIP_END_OF_TLV) { if (err == CHIP_NO_ERROR) diff --git a/src/app/clusters/scenes/SceneTableImpl.cpp b/src/app/clusters/scenes/SceneTableImpl.cpp index a919283ff9a08b..19b9a2994151f3 100644 --- a/src/app/clusters/scenes/SceneTableImpl.cpp +++ b/src/app/clusters/scenes/SceneTableImpl.cpp @@ -226,6 +226,9 @@ struct FabricSceneData : public PersistentData i++; } + // In the event of an OTA, is kMaxScenesPerFabric was reduced, err will be equal to CHIP_NO_ERROR. We close the TLV with + // only the acceptable number of scenes and the next save will take care of reducing the memory usage of the map. This + // allows the user to preserve their scenes in between OTA updates. VerifyOrReturnError(err == CHIP_END_OF_TLV || err == CHIP_NO_ERROR, err); ReturnErrorOnFailure(reader.ExitContainer(sceneMapContainer)); diff --git a/src/app/tests/TestSceneTable.cpp b/src/app/tests/TestSceneTable.cpp index cb054418295457..45d0ca7c840171 100644 --- a/src/app/tests/TestSceneTable.cpp +++ b/src/app/tests/TestSceneTable.cpp @@ -435,7 +435,6 @@ void TestHandlerRegistration(nlTestSuite * aSuite, void * aContext) void TestHandlerFunctions(nlTestSuite * aSuite, void * aContext) { SceneTable * sceneTable = &sSceneTable; - ClusterId tempCluster = 0; app::Clusters::Scenes::Structs::ExtensionFieldSet::Type extensionFieldSetOut; app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType extensionFieldSetIn; From d63a895563022ca0e85e72ec780eb710e0953af1 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs <112982107+lpbeliveau-silabs@users.noreply.github.com> Date: Fri, 24 Mar 2023 13:46:01 -0400 Subject: [PATCH 78/79] Apply suggestions from code review Co-authored-by: Boris Zbarsky --- src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp | 7 +++---- src/app/clusters/scenes/SceneTable.h | 3 ++- src/app/clusters/scenes/SceneTableImpl.h | 4 ---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp index f50bf4f58f257d..03f2581a0e443f 100644 --- a/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp +++ b/src/app/clusters/scenes/ExtensionFieldSetsImpl.cpp @@ -57,10 +57,10 @@ CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader, TLV::Tag } mFieldSetsCount = i; - // In the event of an OTA where the maximum number of cluster per scene has been reduced, the extension field set will be + // In the event of an OTA where the maximum number of clusters per scene has been reduced, the extension field set will be // considered "corrupted" if we don't manage to load it all (if err == CHIP_NO_ERROR after the loop). We therefore return an - // error and this scene will have to be deleted. This is done because truncating an EFS doesn't garrantee the order of the - // clusters loaded, which might allow to load clusters that are no longer supported and loosing supported ones. + // error and this scene will have to be deleted. This is done because truncating an EFS doesn't guarantee the order of the + // clusters loaded, which might lead to loading clusters that are no longer supported and losing supported ones. if (err != CHIP_END_OF_TLV) { if (err == CHIP_NO_ERROR) @@ -75,7 +75,6 @@ CHIP_ERROR ExtensionFieldSetsImpl::Deserialize(TLV::TLVReader & reader, TLV::Tag void ExtensionFieldSetsImpl::Clear() { - for (uint8_t i = 0; i < mFieldSetsCount; i++) { mFieldSets[i].Clear(); diff --git a/src/app/clusters/scenes/SceneTable.h b/src/app/clusters/scenes/SceneTable.h index 6b38add6948ea7..bdb1f261cd9067 100644 --- a/src/app/clusters/scenes/SceneTable.h +++ b/src/app/clusters/scenes/SceneTable.h @@ -82,7 +82,8 @@ class SceneHandler : public IntrusiveListNodeBase<> /// @param extensionFieldSet[in] ExtensionFieldSets provided by the AddScene Command, pre initialized /// @param serialisedBytes[out] Buffer to fill from the ExtensionFieldSet in command /// @return CHIP_NO_ERROR if successful, CHIP_ERROR value otherwise - /// @note Only gets called after the scene-cluster has previously verified that the endpoint,cluster valuer pair is supported by + /// @note Only gets called after the scene-cluster has previously verified that the endpoint,cluster pair is supported by + /// the handler. It is therefore the implementation's reponsibility to also implement the SupportsCluster method. virtual CHIP_ERROR SerializeAdd(EndpointId endpoint, const app::Clusters::Scenes::Structs::ExtensionFieldSet::DecodableType & extensionFieldSet, diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 734cc122dfda16..00247c179945a8 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -78,14 +78,12 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler mValueBuffer[pairCount][valueBytesCount] = value_iterator.GetValue(); valueBytesCount++; } - // Check we could go through all bytes of the value ReturnErrorOnFailure(value_iterator.GetStatus()); mAVPairs[pairCount].attributeValue = mValueBuffer[pairCount]; mAVPairs[pairCount].attributeValue.reduce_size(valueBytesCount); pairCount++; } - // Check we could go through all pairs in incomming command ReturnErrorOnFailure(pair_iterator.GetStatus()); app::DataModel::List attributeValueList; @@ -149,14 +147,12 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler mValueBuffer[pairCount][valueBytesCount] = value_iterator.GetValue(); valueBytesCount++; } - // Check we could go through all bytes of the value ReturnErrorOnFailure(value_iterator.GetStatus()); mAVPairs[pairCount].attributeValue = mValueBuffer[pairCount]; mAVPairs[pairCount].attributeValue.reduce_size(valueBytesCount); pairCount++; }; - // Check we could go through all pairs stored in memory ReturnErrorOnFailure(pair_iterator.GetStatus()); ReturnErrorOnFailure(reader.ExitContainer(outer)); From 9f6b7920d8b232ae33182405aa8908c533840674 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Fri, 24 Mar 2023 14:23:43 -0400 Subject: [PATCH 79/79] Added missing checks, removed redundant ones in scene default handlers --- src/app/clusters/scenes/SceneTableImpl.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/app/clusters/scenes/SceneTableImpl.h b/src/app/clusters/scenes/SceneTableImpl.h index 00247c179945a8..11d83b14a5239d 100644 --- a/src/app/clusters/scenes/SceneTableImpl.h +++ b/src/app/clusters/scenes/SceneTableImpl.h @@ -58,19 +58,20 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler uint8_t pairCount = 0; // Verify size of list - extensionFieldSet.attributeValueList.ComputeSize(&pairTotal); - VerifyOrReturnError(pairTotal <= kMaxAvPair, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(extensionFieldSet.attributeValueList.ComputeSize(&pairTotal)); + VerifyOrReturnError(pairTotal <= Span(mAVPairs).size(), + CHIP_ERROR_BUFFER_TOO_SMALL); auto pair_iterator = extensionFieldSet.attributeValueList.begin(); - while (pair_iterator.Next() && pairCount < kMaxAvPair) + while (pair_iterator.Next()) { aVPair = pair_iterator.GetValue(); mAVPairs[pairCount].attributeID = aVPair.attributeID; size_t valueBytesTotal = 0; uint8_t valueBytesCount = 0; - aVPair.attributeValue.ComputeSize(&valueBytesTotal); - VerifyOrReturnError(valueBytesTotal <= kMaxValueSize, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(aVPair.attributeValue.ComputeSize(&valueBytesTotal)); + VerifyOrReturnError(valueBytesTotal <= Span(mValueBuffer[0]).size(), CHIP_ERROR_BUFFER_TOO_SMALL); auto value_iterator = aVPair.attributeValue.begin(); while (value_iterator.Next()) @@ -126,8 +127,9 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler attributeValueList.Decode(reader); // Verify size of list - attributeValueList.ComputeSize(&pairTotal); - VerifyOrReturnError(pairTotal <= kMaxAvPair, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(attributeValueList.ComputeSize(&pairTotal)); + VerifyOrReturnError(pairTotal <= Span(mAVPairs).size(), + CHIP_ERROR_BUFFER_TOO_SMALL); auto pair_iterator = attributeValueList.begin(); while (pair_iterator.Next()) @@ -138,11 +140,11 @@ class DefaultSceneHandlerImpl : public scenes::SceneHandler uint8_t valueBytesCount = 0; // Verify size of attribute value - decodePair.attributeValue.ComputeSize(&valueBytesTotal); - VerifyOrReturnError(valueBytesTotal <= kMaxValueSize, CHIP_ERROR_BUFFER_TOO_SMALL); + ReturnErrorOnFailure(decodePair.attributeValue.ComputeSize(&valueBytesTotal)); + VerifyOrReturnError(valueBytesTotal <= Span(mValueBuffer[0]).size(), CHIP_ERROR_BUFFER_TOO_SMALL); auto value_iterator = decodePair.attributeValue.begin(); - while (value_iterator.Next() && valueBytesCount < kMaxValueSize) + while (value_iterator.Next()) { mValueBuffer[pairCount][valueBytesCount] = value_iterator.GetValue(); valueBytesCount++;