blob: 1baaba879a8147bdd52e1894912866b8fe4ee53a [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2019-2020 Google LLC.
* Copyright (c) 2018 Nest Labs, Inc.
*
* 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
* Utilities for accessing persisted device configuration on
* platforms based on the Nordic nRF5 SDK.
*/
#ifndef NRF5_CONFIG_H
#define NRF5_CONFIG_H
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include "FreeRTOS.h"
#include "fds.h"
#include "semphr.h"
#include <functional>
namespace chip {
namespace DeviceLayer {
namespace Internal {
constexpr inline uint32_t NRF5ConfigKey(uint16_t fileId, uint16_t recordId)
{
return static_cast<uint32_t>(fileId) << 16 | recordId;
}
/**
* Provides functions and definitions for accessing persisted device configuration
* on platforms based on the Nordic nRF5 SDK.
*
* This implementation uses the Nordic Flash Data Storage (FDS) library as the
* underlying storage layer.
*
* NOTE: This class is designed to be mixed-in to the concrete subclass of the
* GenericConfigurationManagerImpl<> template. When used this way, the class
* naturally provides implementations for the delegated members referenced by
* the template class (e.g. the ReadConfigValue() method).
*/
class NRF5Config
{
public:
// *** CAUTION ***: Changing the FDS file or record ids of these values will *break* existing devices.
// Limits/definitions imposed by the Nordic SDK
static constexpr uint16_t kFDSFileIdMin = 0x0000; /**< Minimum value that can be used for a FDS file id (per Nordic SDK) */
static constexpr uint16_t kFDSFileIdMax = 0xBFFF; /**< Maximum value that can be used for a FDS file id (per Nordic SDK) */
static constexpr uint16_t kFDSRecordKeyMin =
0x0001; /**< Minimum value that can be used for a FDS record key (per Nordic SDK) */
static constexpr uint16_t kFDSRecordKeyMax =
0xBFFF; /**< Maximum value that can be used for a FDS record key (per Nordic SDK) */
// FDS file ids used by the CHIP Device Layer
static constexpr uint16_t kFileId_ChipFactory = 0x235A; /**< FDS file containing persistent config values set at manufacturing
* time. Retained during factory reset. */
static constexpr uint16_t kFileId_ChipConfig = 0x235B; /**< FDS file containing dynamic config values set at runtime.
* Cleared during factory reset. */
static constexpr uint16_t kFileId_ChipCounter = 0x235C; /**< FDS file containing dynamic counter values set at runtime.
* Retained during factory reset. */
// API data type used to represent the combination of a FDS file id and record key.
using Key = uint32_t;
// Key definitions for well-known configuration values.
static constexpr Key kConfigKey_SerialNum = NRF5ConfigKey(kFileId_ChipFactory, 0x0001);
static constexpr Key kConfigKey_MfrDeviceId = NRF5ConfigKey(kFileId_ChipFactory, 0x0002);
static constexpr Key kConfigKey_MfrDeviceCert = NRF5ConfigKey(kFileId_ChipFactory, 0x0003);
static constexpr Key kConfigKey_MfrDevicePrivateKey = NRF5ConfigKey(kFileId_ChipFactory, 0x0004);
static constexpr Key kConfigKey_ManufacturingDate = NRF5ConfigKey(kFileId_ChipFactory, 0x0005);
static constexpr Key kConfigKey_SetupPinCode = NRF5ConfigKey(kFileId_ChipFactory, 0x0006);
static constexpr Key kConfigKey_FabricId = NRF5ConfigKey(kFileId_ChipConfig, 0x0007);
static constexpr Key kConfigKey_ServiceConfig = NRF5ConfigKey(kFileId_ChipConfig, 0x0008);
static constexpr Key kConfigKey_PairedAccountId = NRF5ConfigKey(kFileId_ChipConfig, 0x0009);
static constexpr Key kConfigKey_ServiceId = NRF5ConfigKey(kFileId_ChipConfig, 0x000A);
static constexpr Key kConfigKey_FabricSecret = NRF5ConfigKey(kFileId_ChipConfig, 0x000B);
static constexpr Key kConfigKey_LastUsedEpochKeyId = NRF5ConfigKey(kFileId_ChipConfig, 0x000C);
static constexpr Key kConfigKey_FailSafeArmed = NRF5ConfigKey(kFileId_ChipConfig, 0x000D);
static constexpr Key kConfigKey_GroupKey = NRF5ConfigKey(kFileId_ChipConfig, 0x000E);
static constexpr Key kConfigKey_ProductRevision = NRF5ConfigKey(kFileId_ChipFactory, 0x000F);
static constexpr Key kConfigKey_MfrDeviceICACerts = NRF5ConfigKey(kFileId_ChipFactory, 0x0010);
static constexpr Key kConfigKey_OperationalDeviceId = NRF5ConfigKey(kFileId_ChipConfig, 0x0011);
static constexpr Key kConfigKey_OperationalDeviceCert = NRF5ConfigKey(kFileId_ChipConfig, 0x0012);
static constexpr Key kConfigKey_OperationalDeviceICACerts = NRF5ConfigKey(kFileId_ChipConfig, 0x0013);
static constexpr Key kConfigKey_OperationalDevicePrivateKey = NRF5ConfigKey(kFileId_ChipConfig, 0x0014);
static constexpr Key kConfigKey_SetupDiscriminator = NRF5ConfigKey(kFileId_ChipFactory, 0x0015);
// Range of FDS record keys used to store CHIP persisted counter values.
static constexpr uint16_t kPersistedCounterRecordKeyBase = kFDSRecordKeyMin;
/**< Base record key for records containing CHIP persisted counter values.
* The CHIP counter id is added to this value to form the FDS record key.*/
static constexpr uint16_t kPersistedCounterRecordKeyMax = kFDSRecordKeyMax;
/**< Max record key for records containing CHIP persisted counter values. */
static CHIP_ERROR Init(void);
// Configuration methods used by the GenericConfigurationManagerImpl<> template.
static CHIP_ERROR ReadConfigValue(Key key, bool & val);
static CHIP_ERROR ReadConfigValue(Key key, uint32_t & val);
static CHIP_ERROR ReadConfigValue(Key key, uint64_t & val);
static CHIP_ERROR ReadConfigValueStr(Key key, char * buf, size_t bufSize, size_t & outLen);
static CHIP_ERROR ReadConfigValueBin(Key key, uint8_t * buf, size_t bufSize, size_t & outLen);
static CHIP_ERROR WriteConfigValue(Key key, bool val);
static CHIP_ERROR WriteConfigValue(Key key, uint32_t val);
static CHIP_ERROR WriteConfigValue(Key key, uint64_t val);
static CHIP_ERROR WriteConfigValueStr(Key key, const char * str);
static CHIP_ERROR WriteConfigValueStr(Key key, const char * str, size_t strLen);
static CHIP_ERROR WriteConfigValueBin(Key key, const uint8_t * data, size_t dataLen);
static CHIP_ERROR ClearConfigValue(Key key);
static bool ConfigValueExists(Key key);
static CHIP_ERROR FactoryResetConfig(void);
static void RunConfigUnitTest(void);
protected:
struct FDSAsyncOp
{
enum
{
kAddRecord = 0,
kUpdateRecord,
kAddOrUpdateRecord,
kDeleteRecord,
kDeleteRecordByKey,
kDeleteFile,
kGC,
kInit,
kWaitQueueSpaceAvailable
};
fds_record_desc_t RecordDesc;
const uint8_t * RecordData;
uint32_t RecordDataLengthWords;
ret_code_t Result;
uint16_t FileId;
uint16_t RecordKey;
uint8_t OpType;
inline FDSAsyncOp(uint8_t opType) : OpType(opType) {}
};
using ForEachRecordFunct = std::function<CHIP_ERROR(const fds_flash_record_t & rec, bool & deleteRec)>;
static constexpr uint16_t kFDSWordSize = 4;
static FDSAsyncOp * volatile sActiveAsyncOp;
static SemaphoreHandle_t sAsyncOpCompletionSem;
static constexpr uint16_t GetFileId(uint32_t key);
static constexpr uint16_t GetRecordKey(uint32_t key);
static CHIP_ERROR OpenRecord(NRF5Config::Key key, fds_record_desc_t & recDesc, fds_flash_record_t & rec);
static CHIP_ERROR ForEachRecord(uint16_t fileId, uint16_t recordKey, ForEachRecordFunct funct);
static CHIP_ERROR DoAsyncFDSOp(FDSAsyncOp & asyncOp);
static constexpr uint16_t FDSWords(size_t s);
private:
static void HandleFDSEvent(const fds_evt_t * fdsEvent);
static CHIP_ERROR MapFDSError(ret_code_t fdsRes);
};
/**
* Extract an FDS file id from a Key value.
*/
inline constexpr uint16_t NRF5Config::GetFileId(Key key)
{
return static_cast<uint16_t>(key >> 16);
}
/**
* Extract an FDS record key from a Key value.
*/
inline constexpr uint16_t NRF5Config::GetRecordKey(Key key)
{
return static_cast<uint16_t>(key);
}
/**
* Number of FDS words needed to hold a given size object.
*/
inline constexpr uint16_t NRF5Config::FDSWords(size_t s)
{
// TODO: This cast does not seem safe from overflow.
// https://github.com/project-chip/connectedhomeip/issues/2570
return static_cast<uint16_t>((s + (kFDSWordSize - 1)) / kFDSWordSize);
}
} // namespace Internal
} // namespace DeviceLayer
} // namespace chip
#endif // NRF5_CONFIG_H