/* * * 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. */ /** * @file * * @brief * Class declarations for a monotonically-increasing counter that is periodically * saved in the platform's persistent storage. */ #pragma once #include #include #include namespace chip { /** * @class LifetimePersistedCounter * * @brief * A class for managing a counter as an integer value intended to persist * across reboots. * * Counter values are always set to start at a multiple of a bootup value * "epoch". * * Example: * * - Assuming epoch is 100 via LifetimePersistedCounter::Init(_, 100) and GetValue + * AdvanceValue is called, we get the following outputs: * * - Output: 0, 1, 2, 3, 4 * */ template class LifetimePersistedCounter : public MonotonicallyIncreasingCounter { public: LifetimePersistedCounter() : mId(chip::Platform::PersistedStorage::kEmptyKey) {} ~LifetimePersistedCounter() override = default; /** * @brief * Initialize a LifetimePersistedCounter object. * * @param[in] aId The identifier of this LifetimePersistedCounter instance. * * @return CHIP_ERROR_INVALID_ARGUMENT if aId is NULL * CHIP_ERROR_INVALID_STRING_LENGTH if aId is longer than * CHIP_CONFIG_PERSISTED_STORAGE_MAX_KEY_LENGTH. * CHIP_ERROR_INVALID_INTEGER_VALUE if aEpoch is 0. * CHIP_NO_ERROR otherwise */ CHIP_ERROR Init(const chip::Platform::PersistedStorage::Key aId) { mId = aId; T startValue; // Read our previously-stored starting value. ReturnErrorOnFailure(ReadStartValue(startValue)); // This will set the starting value, after which we're ready. return MonotonicallyIncreasingCounter::Init(startValue); } /** * @brief * Increment the counter and write to persisted storage if we've completed * the current epoch. * * @return Any error returned by a write to persisted storage. */ CHIP_ERROR Advance() override { VerifyOrReturnError(mId != chip::Platform::PersistedStorage::kEmptyKey, CHIP_ERROR_INCORRECT_STATE); ReturnErrorOnFailure(MonotonicallyIncreasingCounter::Advance()); return chip::Platform::PersistedStorage::Write(mId, MonotonicallyIncreasingCounter::GetValue()); } private: /** * @brief * Read our starting counter value (if we have one) in from persistent storage. * * @param[in,out] aStartValue The value read out. * * @return Any error returned by a read from persistent storage. */ CHIP_ERROR ReadStartValue(T & aStartValue) { aStartValue = 0; CHIP_ERROR err = chip::Platform::PersistedStorage::Read(mId, aStartValue); if (err == CHIP_ERROR_PERSISTED_STORAGE_VALUE_NOT_FOUND) { // No previously-stored value, no worries, the counter is initialized to zero. // Suppress the error. err = CHIP_NO_ERROR; } return err; } chip::Platform::PersistedStorage::Key mId; // start value is stored here }; } // namespace chip