From 231912466ecbb56ac6402a9545e4c8e41bbc0359 Mon Sep 17 00:00:00 2001 From: lpbeliveau-silabs Date: Wed, 8 Feb 2023 14:52:15 -0500 Subject: [PATCH] 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); } };