Line data Source code
1 : /* 2 : * Copyright (c) 2021 Project CHIP Authors 3 : * 4 : * Licensed under the Apache License, Version 2.0 (the "License"); 5 : * you may not use this file except in compliance with the License. 6 : * You may obtain a copy of the License at 7 : * 8 : * http://www.apache.org/licenses/LICENSE-2.0 9 : * 10 : * Unless required by applicable law or agreed to in writing, software 11 : * distributed under the License is distributed on an "AS IS" BASIS, 12 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 : * See the License for the specific language governing permissions and 14 : * limitations under the License. 15 : */ 16 : #pragma once 17 : 18 : #include <app/ConcreteAttributePath.h> 19 : #include <app/data-model/Nullable.h> 20 : #include <app/util/attribute-metadata.h> 21 : #include <cstring> 22 : #include <inttypes.h> 23 : #include <lib/support/BufferReader.h> 24 : #include <lib/support/BufferWriter.h> 25 : #include <lib/support/Span.h> 26 : 27 : namespace chip { 28 : namespace app { 29 : 30 : /** 31 : * Interface for persisting attribute values. This will always write attributes in storage as little-endian 32 : * and uses a different key space from AttributePersistenceProvider. 33 : */ 34 : 35 : class SafeAttributePersistenceProvider 36 : { 37 : public: 38 1 : virtual ~SafeAttributePersistenceProvider() = default; 39 1 : SafeAttributePersistenceProvider() = default; 40 : 41 : // The following API provides helper functions to simplify the access of commonly used types. 42 : // The API may not be complete. 43 : // Currently implemented write and read types are: uint8_t, uint16_t, uint32_t, unit64_t and 44 : // their nullable varieties, and bool. 45 : 46 : /** 47 : * Write an attribute value of type intX, uintX or bool to non-volatile memory. 48 : * 49 : * @param [in] aPath the attribute path for the data being written. 50 : * @param [in] aValue the data to write. 51 : */ 52 : template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true> 53 : CHIP_ERROR WriteScalarValue(const ConcreteAttributePath & aPath, T & aValue) 54 : { 55 : uint8_t value[sizeof(T)]; 56 : auto w = Encoding::LittleEndian::BufferWriter(value, sizeof(T)); 57 : if constexpr (std::is_signed_v<T>) 58 : { 59 : w.EndianPutSigned(aValue, sizeof(T)); 60 : } 61 : else 62 : { 63 : w.EndianPut(aValue, sizeof(T)); 64 : } 65 : 66 : return SafeWriteValue(aPath, ByteSpan(value)); 67 : } 68 : 69 : /** 70 : * Read an attribute of type intX, uintX or bool from non-volatile memory. 71 : * 72 : * @param [in] aPath the attribute path for the data being persisted. 73 : * @param [in,out] aValue where to place the data. 74 : */ 75 : template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true> 76 : CHIP_ERROR ReadScalarValue(const ConcreteAttributePath & aPath, T & aValue) 77 : { 78 : uint8_t attrData[sizeof(T)]; 79 : MutableByteSpan tempVal(attrData); 80 : auto err = SafeReadValue(aPath, tempVal); 81 : if (err != CHIP_NO_ERROR) 82 : { 83 : return err; 84 : } 85 : 86 : Encoding::LittleEndian::Reader r(tempVal.data(), tempVal.size()); 87 : r.RawReadLowLevelBeCareful(&aValue); 88 : return r.StatusCode(); 89 : } 90 : 91 : /** 92 : * Write an attribute value of type nullable intX, uintX to non-volatile memory. 93 : * 94 : * @param [in] aPath the attribute path for the data being written. 95 : * @param [in] aValue the data to write. 96 : */ 97 : template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true> 98 : CHIP_ERROR WriteScalarValue(const ConcreteAttributePath & aPath, DataModel::Nullable<T> & aValue) 99 : { 100 : typename NumericAttributeTraits<T>::StorageType storageValue; 101 : if (aValue.IsNull()) 102 : { 103 : NumericAttributeTraits<T>::SetNull(storageValue); 104 : } 105 : else 106 : { 107 : NumericAttributeTraits<T>::WorkingToStorage(aValue.Value(), storageValue); 108 : } 109 : return WriteScalarValue(aPath, storageValue); 110 : } 111 : 112 : /** 113 : * Read an attribute of type nullable intX, uintX from non-volatile memory. 114 : * 115 : * @param [in] aPath the attribute path for the data being persisted. 116 : * @param [in,out] aValue where to place the data. 117 : */ 118 : template <typename T, std::enable_if_t<std::is_integral<T>::value, bool> = true> 119 : CHIP_ERROR ReadScalarValue(const ConcreteAttributePath & aPath, DataModel::Nullable<T> & aValue) 120 : { 121 : typename NumericAttributeTraits<T>::StorageType storageValue; 122 : CHIP_ERROR err = ReadScalarValue(aPath, storageValue); 123 : if (err != CHIP_NO_ERROR) 124 : { 125 : return err; 126 : } 127 : 128 : if (NumericAttributeTraits<T>::IsNullValue(storageValue)) 129 : { 130 : aValue.SetNull(); 131 : return CHIP_NO_ERROR; 132 : } 133 : 134 : // Consider checking CanRepresentValue here, so we don't produce invalid data 135 : // if the storage hands us invalid values. 136 : aValue.SetNonNull(NumericAttributeTraits<T>::StorageToWorking(storageValue)); 137 : return CHIP_NO_ERROR; 138 : } 139 : 140 : protected: 141 : /** 142 : * Write an attribute value from the attribute store (i.e. not a struct or 143 : * list) to non-volatile memory. 144 : * 145 : * @param [in] aPath the attribute path for the data being written. 146 : * @param [in] aValue the data to write. The value should be stored as-is. 147 : */ 148 : virtual CHIP_ERROR SafeWriteValue(const ConcreteAttributePath & aPath, const ByteSpan & aValue) = 0; 149 : 150 : /** 151 : * Read an attribute value from non-volatile memory. 152 : * It can be assumed that this method will never be called upon to read 153 : * an attribute of type string or long-string. 154 : * 155 : * @param [in] aPath the attribute path for the data being persisted. 156 : * @param [in,out] aValue where to place the data. The size of the buffer 157 : * will be equal to `aValue.size()`. The callee is expected to adjust 158 : * aValue's size to the actual number of bytes read. 159 : */ 160 : virtual CHIP_ERROR SafeReadValue(const ConcreteAttributePath & aPath, MutableByteSpan & aValue) = 0; 161 : }; 162 : 163 : /** 164 : * Instance getter for the global SafeAttributePersistenceProvider. 165 : * 166 : * Callers have to externally synchronize usage of this function. 167 : * 168 : * @return The global SafeAttributePersistenceProvider. This must never be null. 169 : */ 170 : SafeAttributePersistenceProvider * GetSafeAttributePersistenceProvider(); 171 : 172 : /** 173 : * Instance setter for the global SafeAttributePersistenceProvider. 174 : * 175 : * Callers have to externally synchronize usage of this function. 176 : * 177 : * If the `provider` is nullptr, the value is not changed. 178 : * 179 : * @param[in] aProvider the SafeAttributePersistenceProvider implementation to use. 180 : */ 181 : void SetSafeAttributePersistenceProvider(SafeAttributePersistenceProvider * aProvider); 182 : 183 : } // namespace app 184 : } // namespace chip