Skip to content

Commit

Permalink
[nrf toup][nrfconnect] Added module to synchronize DFU processes
Browse files Browse the repository at this point in the history
Introduced a module that can be used to synchronize DFU processes
and make it mutual exclusive (prevent concurrent DFU runs using
different protocols, e.g Matter OTA and DFU over BT SMP).

Signed-off-by: Kamil Kasperczyk <[email protected]>
  • Loading branch information
kkasperczyk-no committed Jul 12, 2024
1 parent fd8e621 commit 8eaa65d
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 1 deletion.
1 change: 1 addition & 0 deletions config/nrfconnect/chip-module/Kconfig.features
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ config CHIP_DFU_OVER_BT_SMP
# Enable custom SMP request to erase settings partition.
select MCUMGR_GRP_ZBASIC
select MCUMGR_GRP_ZBASIC_STORAGE_ERASE
select MCUMGR_GRP_IMG_STATUS_HOOKS
help
Enables Device Firmware Upgrade over Bluetooth LE with SMP and configures
the set of options related to that feature.
Expand Down
2 changes: 2 additions & 0 deletions src/platform/nrfconnect/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ static_library("nrfconnect") {
"ConnectivityManagerImpl.h",
"DiagnosticDataProviderImplNrf.cpp",
"DiagnosticDataProviderImplNrf.h",
"DFUSync.cpp",
"DFUSync.h",
"ExternalFlashManager.h",
"InetPlatformConfig.h",
"KeyValueStoreManagerImpl.h",
Expand Down
33 changes: 33 additions & 0 deletions src/platform/nrfconnect/DFUSync.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#include "DFUSync.h"

CHIP_ERROR DFUSync::Take(uint32_t & id)
{
if (mIsTaken)
{
if (id == mOwnerId)
{
return CHIP_NO_ERROR;
}
return CHIP_ERROR_BUSY;
}

mIsTaken = true;
/* Increment owner id to make sure that every allocation is unique. */
mOwnerId++;
id = mOwnerId;

return CHIP_NO_ERROR;
}

CHIP_ERROR DFUSync::Free(uint32_t id)
{
/* Prevent free operation from the threads that do not own mutex. */
if (id != mOwnerId)
{
return CHIP_ERROR_ACCESS_DENIED;
}

mIsTaken = false;

return CHIP_NO_ERROR;
}
60 changes: 60 additions & 0 deletions src/platform/nrfconnect/DFUSync.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
*
* Copyright (c) 2024 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 <lib/core/CHIPError.h>
#include <atomic>

class DFUSync
{
public:
/**
* @brief Tries to take a mutex allowing to perform the DFU process.
*
* @param id reference to the mutex owner id that is assigned with random id, if the mutex was taken successfully
*
* @return CHIP_NO_ERROR on success, the other error code on failure.
*/
CHIP_ERROR Take(uint32_t & id);

/**
* @brief Tries to free a mutex allowing to perform the DFU process.
*
* @param id mutex owner id that has to be equal to the id assigned by Take method to prevent free attempts from the other
* threads that do not own the mutex.
*
* @return CHIP_NO_ERROR on success, the other error code on failure.
*/
CHIP_ERROR Free(uint32_t id);

/**
* @brief Get the DFUSync instance
*
* @return DFUSync object
*/
static inline DFUSync & GetInstance()
{
static DFUSync sInstance;
return sInstance;
}

private:
/* Mutex to synchronize the DFU operations. */
std::atomic<bool> mIsTaken = false;
uint32_t mOwnerId = 0;
};
19 changes: 18 additions & 1 deletion src/platform/nrfconnect/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
#include <zephyr/settings/settings.h>
#endif

#include "DFUSync.h"

#include <dfu/dfu_multi_image.h>
#include <dfu/dfu_target.h>
#include <dfu/dfu_target_mcuboot.h>
Expand Down Expand Up @@ -66,9 +68,22 @@ CHIP_ERROR OTAImageProcessorImpl::PrepareDownload()
{
VerifyOrReturnError(mDownloader != nullptr, CHIP_ERROR_INCORRECT_STATE);

if (DFUSync::GetInstance().Take(mDfuSyncMutexId) != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Cannot start Matter OTA, another DFU in progress.");
return CHIP_ERROR_BUSY;
}

TriggerFlashAction(ExternalFlashManager::Action::WAKE_UP);

return DeviceLayer::SystemLayer().ScheduleLambda([this] { mDownloader->OnPreparedForDownload(PrepareDownloadImpl()); });
return DeviceLayer::SystemLayer().ScheduleLambda([this] {
CHIP_ERROR err = PrepareDownloadImpl();
if (err != CHIP_NO_ERROR)
{
DFUSync::GetInstance().Free(mDfuSyncMutexId);
}
mDownloader->OnPreparedForDownload(err);
});
}

CHIP_ERROR OTAImageProcessorImpl::PrepareDownloadImpl()
Expand Down Expand Up @@ -112,13 +127,15 @@ CHIP_ERROR OTAImageProcessorImpl::PrepareDownloadImpl()
CHIP_ERROR OTAImageProcessorImpl::Finalize()
{
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadComplete);
DFUSync::GetInstance().Free(mDfuSyncMutexId);
return System::MapErrorZephyr(dfu_multi_image_done(true));
}

CHIP_ERROR OTAImageProcessorImpl::Abort()
{
CHIP_ERROR error = System::MapErrorZephyr(dfu_multi_image_done(false));

DFUSync::GetInstance().Free(mDfuSyncMutexId);
TriggerFlashAction(ExternalFlashManager::Action::SLEEP);
PostOTAStateChangeEvent(DeviceLayer::kOtaDownloadAborted);

Expand Down
1 change: 1 addition & 0 deletions src/platform/nrfconnect/OTAImageProcessorImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class OTAImageProcessorImpl : public OTAImageProcessorInterface

private:
bool mImageConfirmed = false;
uint32_t mDfuSyncMutexId;
};

} // namespace DeviceLayer
Expand Down

0 comments on commit 8eaa65d

Please sign in to comment.