forked from project-chip/connectedhomeip
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement persistent storage for attributes with "NVM" storage select…
…ed. (project-chip#13172) General changes: 1. Set the CurrentLevel attribute in all-clusters app to be NVM and default to 254. This requires some YAML changes to expect the new value. 2. Remove the hardcoded setting of that attribute to 255 during boot in the ESP32 all-clusters app. 3. Define and implement AttributePersistenceProvider to read/write persistent attributes. 4. Fix bug in ServerStorageDelegate::SyncGetKeyValue: it was not setting the size outparam to the actual size read. 5. Move EmberAfAttributeMetadata and a few functions for working with strings into a new header that can be included in places where generated headers (which af.h and af-types.h include) can't be. 6. Add those functions to out mock attribute-storage to fix linking of some tests. Fix mistyped "darwin" in gn files so the tests get run on Darwin too, not just on Linux. 7. Rearrange the logic in emAfLoadAttributeDefaults a bit: instead of loading the default value into the RAM store and then checking for a persisted value, check for a persisted value first (if the attribute might have one), and only look for a default value if there is no persisted value. This removes the need for a separate emAfLoadAttributesFromStorage pass (which made sense back when that code was all generated, but it's not anymore). 8. Fix emAfSaveAttributeToStorageIfNeeded to actually store the value.
- Loading branch information
1 parent
3527e95
commit aa0a1a1
Showing
23 changed files
with
728 additions
and
275 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* Copyright (c) 2021 Project CHIP Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
#pragma once | ||
|
||
#include <app/ConcreteAttributePath.h> | ||
#include <app/util/attribute-metadata.h> | ||
#include <lib/support/Span.h> | ||
|
||
namespace chip { | ||
namespace app { | ||
|
||
/** | ||
* Interface for persisting attribute values. | ||
*/ | ||
|
||
class AttributePersistenceProvider | ||
{ | ||
public: | ||
virtual ~AttributePersistenceProvider() = default; | ||
AttributePersistenceProvider() = default; | ||
|
||
/** | ||
* Write an attribute value from the attribute store (i.e. not a struct or | ||
* list) to non-volatile memory. | ||
* | ||
* @param [in] aPath the attribute path for the data being written. | ||
* @param [in] aMetadata the attribute metadata, as a convenience. | ||
* @param [in] aValue the data to write. Integers and floats are | ||
* represented in native endianness. Strings are represented | ||
* as Pascal-style strings, as in ZCL, with a length prefix | ||
* whose size depends on the actual string type. The length is | ||
* stored as little-endian. | ||
* | ||
* Integer and float values have a size that matches the `size` | ||
* member of aMetadata. | ||
* | ||
* String values have a size that corresponds to the actual size | ||
* of the data in the string (including the length prefix), | ||
* which is no larger than the `size` member of aMetadata. | ||
*/ | ||
virtual CHIP_ERROR WriteValue(const ConcreteAttributePath & aPath, const EmberAfAttributeMetadata * aMetadata, | ||
const ByteSpan & aValue) = 0; | ||
|
||
/** | ||
* Read an attribute value from non-volatile memory. | ||
* | ||
* @param [in] aPath the attribute path for the data being persisted. | ||
* @param [in] aMetadata the attribute metadata, as a convenience. | ||
* @param [in,out] aValue where to place the data. The size of the buffer | ||
* will be equal to `size` member of aMetadata. | ||
* | ||
* The data is expected to be in native endianness for | ||
* integers and floats. For strings, see the string | ||
* representation description in the WriteValue | ||
* documentation. | ||
*/ | ||
virtual CHIP_ERROR ReadValue(const ConcreteAttributePath & aPath, const EmberAfAttributeMetadata * aMetadata, | ||
MutableByteSpan & aValue) = 0; | ||
}; | ||
|
||
/** | ||
* Instance getter for the global AttributePersistenceProvider. | ||
* | ||
* Callers have to externally synchronize usage of this function. | ||
* | ||
* @return The global AttributePersistenceProvider. This must never be null. | ||
*/ | ||
AttributePersistenceProvider * GetAttributePersistenceProvider(); | ||
|
||
/** | ||
* Instance setter for the global AttributePersistenceProvider. | ||
* | ||
* Callers have to externally synchronize usage of this function. | ||
* | ||
* If the `provider` is nullptr, the value is not changed. | ||
* | ||
* @param[in] provider the AttributePersistenceProvider implementation to use. | ||
*/ | ||
void SetAttributePersistenceProvider(AttributePersistenceProvider * aProvider); | ||
|
||
} // namespace app | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* Copyright (c) 2021 Project CHIP Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
#include <app/DefaultAttributePersistenceProvider.h> | ||
#include <lib/support/CodeUtils.h> | ||
#include <lib/support/DefaultStorageKeyAllocator.h> | ||
#include <lib/support/SafeInt.h> | ||
|
||
namespace chip { | ||
namespace app { | ||
|
||
CHIP_ERROR DefaultAttributePersistenceProvider::WriteValue(const ConcreteAttributePath & aPath, | ||
const EmberAfAttributeMetadata * aMetadata, const ByteSpan & aValue) | ||
{ | ||
// TODO: we may want to have a small cache for values that change a lot, so | ||
// we only write them once a bunch of changes happen or on timer or | ||
// shutdown. | ||
DefaultStorageKeyAllocator key; | ||
if (!CanCastTo<uint16_t>(aValue.size())) | ||
{ | ||
return CHIP_ERROR_BUFFER_TOO_SMALL; | ||
} | ||
return mStorage.SyncSetKeyValue(key.AttributeValue(aPath), aValue.data(), static_cast<uint16_t>(aValue.size())); | ||
} | ||
|
||
CHIP_ERROR DefaultAttributePersistenceProvider::ReadValue(const ConcreteAttributePath & aPath, | ||
const EmberAfAttributeMetadata * aMetadata, MutableByteSpan & aValue) | ||
{ | ||
DefaultStorageKeyAllocator key; | ||
uint16_t size = static_cast<uint16_t>(min(aValue.size(), static_cast<size_t>(UINT16_MAX))); | ||
ReturnErrorOnFailure(mStorage.SyncGetKeyValue(key.AttributeValue(aPath), aValue.data(), size)); | ||
EmberAfAttributeType type = aMetadata->attributeType; | ||
if (emberAfIsStringAttributeType(type)) | ||
{ | ||
// Ensure that we've read enough bytes that we are not ending up with | ||
// un-initialized memory. Should have read length + 1 (for the length | ||
// byte). | ||
VerifyOrReturnError(size >= emberAfStringLength(aValue.data()) + 1, CHIP_ERROR_INCORRECT_STATE); | ||
} | ||
else if (emberAfIsLongStringAttributeType(type)) | ||
{ | ||
// Ensure that we've read enough bytes that we are not ending up with | ||
// un-initialized memory. Should have read length + 2 (for the length | ||
// bytes). | ||
VerifyOrReturnError(size >= emberAfLongStringLength(aValue.data()) + 2, CHIP_ERROR_INCORRECT_STATE); | ||
} | ||
else | ||
{ | ||
// Ensure we got the expected number of bytes for all other types. | ||
VerifyOrReturnError(size == aMetadata->size, CHIP_ERROR_INCORRECT_STATE); | ||
} | ||
aValue.reduce_size(size); | ||
return CHIP_NO_ERROR; | ||
} | ||
|
||
namespace { | ||
|
||
AttributePersistenceProvider * gAttributeSaver = nullptr; | ||
|
||
} // anonymous namespace | ||
|
||
AttributePersistenceProvider * GetAttributePersistenceProvider() | ||
{ | ||
return gAttributeSaver; | ||
} | ||
|
||
void SetAttributePersistenceProvider(AttributePersistenceProvider * aProvider) | ||
{ | ||
if (aProvider != nullptr) | ||
{ | ||
gAttributeSaver = aProvider; | ||
} | ||
} | ||
|
||
} // namespace app | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* | ||
* Copyright (c) 2021 Project CHIP Authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
#pragma once | ||
|
||
#include <app/AttributePersistenceProvider.h> | ||
#include <lib/core/CHIPPersistentStorageDelegate.h> | ||
#include <lib/support/DefaultStorageKeyAllocator.h> | ||
|
||
namespace chip { | ||
namespace app { | ||
|
||
/** | ||
* Default implementation of AttributePersistenceProvider. This uses | ||
* PersistentStorageDelegate to store the attribute values. | ||
* | ||
* NOTE: SetAttributePersistenceProvider must still be called with an instance | ||
* of this class, since it can't be constructed automatically without knowing | ||
* what PersistentStorageDelegate is to be used. | ||
*/ | ||
class DefaultAttributePersistenceProvider : public AttributePersistenceProvider | ||
{ | ||
public: | ||
// aStorage must outlive this object. | ||
DefaultAttributePersistenceProvider(PersistentStorageDelegate & aStorage) : mStorage(aStorage) {} | ||
|
||
// AttributePersistenceProvider implementation. | ||
CHIP_ERROR WriteValue(const ConcreteAttributePath & aPath, const EmberAfAttributeMetadata * aMetadata, | ||
const ByteSpan & aValue) override; | ||
CHIP_ERROR ReadValue(const ConcreteAttributePath & aPath, const EmberAfAttributeMetadata * aMetadata, | ||
MutableByteSpan & aValue) override; | ||
|
||
private: | ||
PersistentStorageDelegate & mStorage; | ||
}; | ||
|
||
} // namespace app | ||
} // namespace chip |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.