blob: 1720a58edb5c73389a316081d55d74441cd695a6 [file] [log] [blame]
/*
*
* Copyright (c) 2021 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.
*/
#include "DFUOverSMP.h"
#if !defined(CONFIG_MCUMGR_SMP_BT) || !defined(CONFIG_MCUMGR_CMD_IMG_MGMT) || !defined(CONFIG_MCUMGR_CMD_OS_MGMT)
#error "DFUOverSMP requires MCUMGR module configs enabled"
#endif
#include "OTAUtil.h"
#include <platform/CHIPDeviceLayer.h>
#include <lib/support/logging/CHIPLogging.h>
#include <zephyr/dfu/mcuboot.h>
#include <zephyr/mgmt/mcumgr/mgmt/callbacks.h>
#include <zephyr/mgmt/mcumgr/mgmt/mgmt.h>
using namespace ::chip;
using namespace ::chip::DeviceLayer;
constexpr uint8_t kAdvertisingPriority = UINT8_MAX;
constexpr uint32_t kAdvertisingOptions = BT_LE_ADV_OPT_CONNECTABLE;
constexpr uint16_t kAdvertisingIntervalMin = 400;
constexpr uint16_t kAdvertisingIntervalMax = 500;
constexpr uint8_t kAdvertisingFlags = BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR;
namespace {
int32_t UploadConfirmHandler(uint32_t event, int32_t rc, bool * abort_more, void * data, size_t data_size)
{
const img_mgmt_upload_check & imgData = *static_cast<img_mgmt_upload_check *>(data);
IgnoreUnusedVariable(imgData);
ChipLogProgress(SoftwareUpdate, "DFU over SMP progress: %u/%u B of image %u", static_cast<unsigned>(imgData.req->off),
static_cast<unsigned>(imgData.action->size), static_cast<unsigned>(imgData.req->image));
return MGMT_ERR_EOK;
}
int32_t CommandHandler(uint32_t event, int32_t rc, bool * abort_more, void * data, size_t data_size)
{
if (event == MGMT_EVT_OP_CMD_RECV)
{
GetFlashHandler().DoAction(ExternalFlashManager::Action::WAKE_UP);
}
else if (event == MGMT_EVT_OP_CMD_DONE)
{
GetFlashHandler().DoAction(ExternalFlashManager::Action::SLEEP);
}
return MGMT_ERR_EOK;
}
mgmt_callback sUploadCallback = {
.callback = UploadConfirmHandler,
.event_id = MGMT_EVT_OP_IMG_MGMT_DFU_CHUNK,
};
mgmt_callback sCommandCallback = {
.callback = CommandHandler,
.event_id = (MGMT_EVT_OP_CMD_RECV | MGMT_EVT_OP_CMD_DONE),
};
} // namespace
DFUOverSMP DFUOverSMP::sDFUOverSMP;
void DFUOverSMP::Init()
{
const char * name = bt_get_name();
mAdvertisingItems[0] = BT_DATA(BT_DATA_FLAGS, &kAdvertisingFlags, sizeof(kAdvertisingFlags));
mAdvertisingItems[1] = BT_DATA(BT_DATA_NAME_COMPLETE, name, static_cast<uint8_t>(strlen(name)));
mAdvertisingRequest.priority = kAdvertisingPriority;
mAdvertisingRequest.options = kAdvertisingOptions;
mAdvertisingRequest.minInterval = kAdvertisingIntervalMin;
mAdvertisingRequest.maxInterval = kAdvertisingIntervalMax;
mAdvertisingRequest.advertisingData = Span<bt_data>(mAdvertisingItems);
mAdvertisingRequest.onStarted = [](int rc) {
if (rc == 0)
{
ChipLogProgress(SoftwareUpdate, "SMP BLE advertising started");
}
else
{
ChipLogError(SoftwareUpdate, "Failed to start SMP BLE advertising: %d", rc);
}
};
mgmt_callback_register(&sUploadCallback);
mgmt_callback_register(&sCommandCallback);
}
void DFUOverSMP::ConfirmNewImage()
{
// Check if the image is run in the REVERT mode and eventually
// confirm it to prevent reverting on the next boot.
VerifyOrReturn(mcuboot_swap_type() == BOOT_SWAP_TYPE_REVERT);
if (boot_write_img_confirmed())
{
ChipLogError(SoftwareUpdate, "Confirming firmware image failed, it will be reverted on the next boot");
}
else
{
ChipLogProgress(SoftwareUpdate, "New firmware image confirmed");
}
}
void DFUOverSMP::StartServer()
{
VerifyOrReturn(!mIsStarted, ChipLogProgress(SoftwareUpdate, "DFU over SMP was already started"));
// Synchronize access to the advertising arbiter that normally runs on the CHIP thread.
PlatformMgr().LockChipStack();
BLEAdvertisingArbiter::InsertRequest(mAdvertisingRequest);
PlatformMgr().UnlockChipStack();
mIsStarted = true;
ChipLogProgress(DeviceLayer, "DFU over SMP started");
}