Skip to content

Legacy Storage Migration

With Lock SDK version 1.8.0 the storage API was reworked. The old API was pretty static and didn't support features like dynamic number of files and dynamic file sizes. The new API is file-based and therefore more flexible. The SDK also provides an implementation of a flash-based file system (Tapkey File System, TKFS) that corresponds to the updated API. This chapter provides an overview of the steps required to migrate existing locks to the new SDK version, assuming that TKFS is used for implementation of the file system.

The storage API as defined in tkExt.h consists of following parts:

Component Functions (e.g.) Change
Legacy Data Storage tkExt_Storage_ renamed, replaced
Secure Storage API tkExt_Storage_SecureData_GetApi new
File Storage API tkExt_Storage_File_GetFileApi new
FW Storage tkExt_Storage_ unchanged
Log Storage tkExt_Storage_*LogPage unchanged

The legacy data storage is replaced. The write function is removed and the other functions are renamed. They are only used for migration purposes. The firmware and log storage functions are unchanged.

Migration Strategy

For devices deployed in the field using the legacy storage format, the SDK provides functionality for migrating to the new format via the tkIfInit_StorageMigrateLegacy() function. After the lock was upgraded to the version of TlcpLib, tkIfInit_StorageMigrateLegacy() has to be called to perform the data migration. The function must usually be called exactly once. If an error occurs (i.e. due to a power loss), the call must be repeated. Once the call succeeded, tkIfInit_StorageRestore() can be called to continue normal operation, just like before. Once this is done, the migration function must not be called again, because it would erase and overwrite the new data store and might cause inconsistsencies. It's up to the implementing firmware application to ensure, this process is implemented correctly.

During the migration phase, the old and the new data store both need to be acceessible. The old datastore only has to provide read access.

Migrating to a New Memory Space

When migrating to a new memory space, different from where the old data is stored, the migration process is pretty straight forward. The old storage access functions are left almost as they are, while the new access functions are added. Once migration is completed, the old data storage may be deleted and reused.

An example for this kind of migration strategy can be found in the RefBoard_Radino sample project, contained in the SDK. The function tkExtImpl_InitStorageAndProvisioning() implements the migration process.

In-Place Migration

If the same memory space is to be used for the new storage, as for the old one, additional care has to been taken to ensure that no data gets lost, especially in case of power loss during the migration process. The process usually works as follows:

  • Define some temporary persistent storage, where the old data can be moved for use during the migration process.
  • Change tkExt_Legacy_Storage_ReadBlock() such, that it access the old data in the temorary persistent storage.

  • If migration hasn't completed the preparation step before (i.e. no marker has been set), start from scratch:

  • Copy the old data to the temporary persistent storage.
  • Set some persistent marker indicating, that the old data can now be accessed from the temporary storage.

  • If the preparation step completed, but the actual migration hasn't, start the actual migration step:

  • Call tkIfInit_StorageMigrateLegacy().
  • Set some persistent marker indicating, that migration completed.

  • If migration completed, start normally. The temporary storage may be deleted and reused.

An example for in-place migration can be found in the RefBoard_nRF52 project.

Migration Steps Overview

The following gives a coarse overview over the steps to be performed for migrating to the new storage functionality. The overview assumes, that the Tapkey file system component is used.

  • Modify following functions:
  • Rename tkExt_Storage_ReadBlock to tkExt_Legacy_Storage_ReadBlock
  • Remove tkExt_Storage_WriteBlock
  • Rename tkExt_Storage_IsInSecureStorage to tkExt_Legacy_Storage_IsInSecureStorage.

  • Implement tkExt_Storage_File_GetFileApi. If using TKFS, implementation can simply delegate to tkExtImpl_Storage_File_tkfs_GetFileApi.

  • Implement tkExt_Storage_SecureData_GetApi. If file storage stores to secure storage, it can also be used for storing secure data. In this case, simply delegate to tkExtImpl_Storage_SecureData_GetApiForSecureFileSystem.

  • Implement flash storage api functions as defined in tkfs_drv_api:

    typedef struct {
        TKFS_RET (*write)(void* pContext, int pageNo, uint16_t offset, void const* pData, uint16_t dataSize);
        TKFS_RET (*read) (void* pContext, int pageNo, uint16_t offset, void* pData, uint16_t dataSize);
        TKFS_RET (*erase) (void* pContext, int pageNo);
        void (*getConfiguration)(void* pContext, int* pWriteAlignment, uint16_t* pPageSize, uint8_t* pErasedByteValue);
    } tkfs_drv_api;

  • Initialize TKFS by calling tkExtImpl_Storage_File_tkfs_Init and passing the forementioned driver.

  • On first initialization, format the file system (tkExtImpl_Storage_File_tkfs_Format), otherwise mount it (tkExtImpl_Storage_File_tkfs_Mount).

  • Implement data migration as layed out in the previous chapter.