Skip to content

Commit

Permalink
Add Mbed OTA Downloader
Browse files Browse the repository at this point in the history
Add download image service to ota-requestor app
  • Loading branch information
ATmobica committed Dec 6, 2021
1 parent 346e932 commit 0f4cdda
Show file tree
Hide file tree
Showing 11 changed files with 550 additions and 55 deletions.
3 changes: 3 additions & 0 deletions examples/ota-requestor-app/mbed/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ target_sources(${APP_TARGET} PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/main/AppTask.cpp
${MBED_COMMON}/util/LEDWidget.cpp
${CMAKE_CURRENT_SOURCE_DIR}/main/OTARequestorImpl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/main/OTARequestorDriverImpl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/main/OTADownloaderImpl.cpp
${CMAKE_CURRENT_SOURCE_DIR}/main/OTAImageProcessorImpl.cpp

${GEN_DIR}/ota-requestor-app/zap-generated/attribute-size.cpp
${GEN_DIR}/ota-requestor-app/zap-generated/callback-stub.cpp
Expand Down
64 changes: 55 additions & 9 deletions examples/ota-requestor-app/mbed/main/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
#include "events/EventQueue.h"
#include "platform/Callback.h"

#include "OTARequestorImpl.h"
#include <OTADownloaderImpl.h>
#include <OTAImageProcessorImpl.h>

static bool sIsWiFiStationProvisioned = false;
static bool sIsWiFiStationEnabled = false;
Expand All @@ -61,6 +62,9 @@ using namespace ::chip::DeviceLayer;

static LEDWidget sStatusLED(MBED_CONF_APP_SYSTEM_STATE_LED);

static OTARequestorDriverImpl sRequestorDriver;
static OTAImageProcessorImpl sImageProcessor;

AppTask AppTask::sAppTask;

int AppTask::Init()
Expand All @@ -87,7 +91,11 @@ int AppTask::Init()
ConnectivityMgr().SetBLEAdvertisingEnabled(true);
}

OTARequestorImpl::GetInstance().Init(OnConnectProviderCallback);
OTARequestorImpl::GetInstance().Init(OnConnectProviderCallback, OnProviderResponseCallback);
OTARequestorImpl::GetInstance().SetOtaRequestorDriver(&sRequestorDriver);

OTADownloaderImpl::GetInstance().Init(OnDownloadCompletedCallback);
OTADownloaderImpl::GetInstance().SetImageProcessorDelegate(&sImageProcessor);

chip::DeviceLayer::ConnectivityMgrImpl().StartWiFiManagement();

Expand Down Expand Up @@ -163,13 +171,33 @@ int AppTask::StartApp()
}
}

void AppTask::OnConnectProviderHandler(AppEvent * aEvent)
void AppTask::OnOtaEventHandler(AppEvent * aEvent)
{
ChipLogProgress(NotSpecified, "OnConnectProviderHandler");

OTARequestorImpl::GetInstance().ConnectProvider(aEvent->OTAProviderConnectEvent.nodeId,
aEvent->OTAProviderConnectEvent.fabricIndex,
aEvent->OTAProviderConnectEvent.ipAddress);
switch (aEvent->Type)
{
case AppEvent::kEventType_ota_provider_connect:
ChipLogProgress(NotSpecified, "OTA provider connect event");

OTARequestorImpl::GetInstance().ConnectProvider(aEvent->OTAProviderConnectEvent.nodeId,
aEvent->OTAProviderConnectEvent.fabricIndex,
aEvent->OTAProviderConnectEvent.ipAddress);
break;
case AppEvent::kEventType_ota_provider_response: {
ChipLogProgress(NotSpecified, "OTA provider response event");
OTADownloaderImpl::GetInstance().SetDownloadImageInfo(aEvent->OTAProviderResponseEvent.imageDatails->updateFileName);
OTADownloaderImpl::GetInstance().BeginDownload();
break;
}
case AppEvent::kEventType_ota_download_completed:
ChipLogProgress(NotSpecified, "OTA download completed event");
ChipLogProgress(NotSpecified, "Download %.*s image size %ukB",
static_cast<int>(aEvent->OTADownloadCompletedEvent.imageInfo->imageName.size()),
aEvent->OTADownloadCompletedEvent.imageInfo->imageName.data(),
(static_cast<unsigned>(aEvent->OTADownloadCompletedEvent.imageInfo->imageSize) / 1024u));
break;
default:
ChipLogError(NotSpecified, "OTA event unknown");
}
}

void AppTask::OnConnectProviderCallback(NodeId nodeId, FabricIndex fabricIndex, chip::Optional<chip::ByteSpan> ipAddress)
Expand All @@ -179,10 +207,28 @@ void AppTask::OnConnectProviderCallback(NodeId nodeId, FabricIndex fabricIndex,
ota_connect_provider_event.OTAProviderConnectEvent.nodeId = nodeId;
ota_connect_provider_event.OTAProviderConnectEvent.fabricIndex = fabricIndex;
ota_connect_provider_event.OTAProviderConnectEvent.ipAddress = reinterpret_cast<const char *>(ipAddress.Value().data());
ota_connect_provider_event.Handler = OnConnectProviderHandler;
ota_connect_provider_event.Handler = OnOtaEventHandler;
sAppTask.PostEvent(&ota_connect_provider_event);
}

void AppTask::OnProviderResponseCallback(OTARequestorImpl::OTAUpdateDetails * updateDetails)
{
AppEvent ota_provider_response_event;
ota_provider_response_event.Type = AppEvent::kEventType_ota_provider_response;
ota_provider_response_event.Handler = OnOtaEventHandler;
ota_provider_response_event.OTAProviderResponseEvent.imageDatails = updateDetails;
sAppTask.PostEvent(&ota_provider_response_event);
}

void AppTask::OnDownloadCompletedCallback(OTADownloaderImpl::ImageInfo * imageInfo)
{
AppEvent ota_download_completed_event;
ota_download_completed_event.Type = AppEvent::kEventType_ota_download_completed;
ota_download_completed_event.Handler = OnOtaEventHandler;
ota_download_completed_event.OTADownloadCompletedEvent.imageInfo = imageInfo;
sAppTask.PostEvent(&ota_download_completed_event);
}

void AppTask::PostEvent(AppEvent * aEvent)
{
auto handle = sAppEventQueue.call([event = *aEvent, this] { DispatchEvent(&event); });
Expand Down
205 changes: 205 additions & 0 deletions examples/ota-requestor-app/mbed/main/OTADownloaderImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
/*
*
* 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.
*/

#include <OTADownloaderImpl.h>
#include <app/OperationalDeviceProxy.h>
#include <app/server/Server.h>
#include <platform/CHIPDeviceLayer.h>

using namespace ::chip;
using namespace chip::bdx;

OTADownloaderImpl OTADownloaderImpl::sInstance;

OTADownloaderImpl::OTADownloaderImpl() {}

void OTADownloaderImpl::BeginDownload()
{
ChipLogProgress(SoftwareUpdate, "Begin download");

OperationalDeviceProxy * deviceProxy = Server::GetInstance().GetOperationalDeviceProxy();
if (deviceProxy == nullptr)
{
ChipLogError(SoftwareUpdate, "Provider connection not established");
return;
}

Messaging::ExchangeManager * exchangeMgr = deviceProxy->GetExchangeManager();
Optional<SessionHandle> session = deviceProxy->GetSecureSession();
Messaging::ExchangeContext * exchangeCtx = nullptr;

if (exchangeMgr != nullptr && session.HasValue())
{
exchangeCtx = exchangeMgr->NewContext(session.Value(), this);
}

if (exchangeCtx == nullptr)
{
ChipLogError(SoftwareUpdate, "Failed to allocate exchange");
return;
}

mExchangeCtx = exchangeCtx;

TransferSession::TransferInitData initOptions;
initOptions.TransferCtlFlags = TransferControlFlags::kReceiverDrive;
initOptions.MaxBlockSize = mBlockSize;
initOptions.FileDesLength = mImageInfo.imageName.size();
initOptions.FileDesignator = reinterpret_cast<const uint8_t *>(mImageInfo.imageName.data());

CHIP_ERROR error =
InitiateTransfer(&DeviceLayer::SystemLayer(), TransferRole::kReceiver, initOptions, System::Clock::Seconds16(20));

if (error != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Failed to initiate BDX transfer: %" CHIP_ERROR_FORMAT, error.Format());
}
}

void OTADownloaderImpl::OnPreparedForDownload()
{
ChipLogProgress(SoftwareUpdate, "On Prepared For Download");
}

void OTADownloaderImpl::OnBlockProcessed(BlockActionType action)
{
ChipLogProgress(SoftwareUpdate, "On Block Processed");
}

void OTADownloaderImpl::HandleTransferSessionOutput(TransferSession::OutputEvent & event)
{
using OutputEventType = TransferSession::OutputEventType;
using SendMessageFlags = Messaging::SendMessageFlags;

CHIP_ERROR error = CHIP_NO_ERROR;

if (event.EventType != OutputEventType::kNone)
{
ChipLogDetail(BDX, "OutputEvent type: %s", event.ToString(event.EventType));
}

switch (event.EventType)
{
case OutputEventType::kNone:
if (mIsTransferComplete)
{
ChipLogProgress(BDX, "Image file transfer complete");
mTransfer.Reset();
mIsTransferComplete = false;

error = mImageProcessorDelegate->Finalize();
if (error != CHIP_NO_ERROR)
{
ChipLogError(BDX, "Image processing finalize failed: %" CHIP_ERROR_FORMAT, error.Format());
mImageProcessorDelegate->Abort();
return;
}

if (mDownloadCompletedCallback)
{
mDownloadCompletedCallback(&mImageInfo);
}
}
break;
case OutputEventType::kMsgToSend: {
Messaging::SendFlags flags;
flags.Set(SendMessageFlags::kFromInitiator, event.msgTypeData.MessageType == to_underlying(MessageType::ReceiveInit));
flags.Set(SendMessageFlags::kExpectResponse, event.msgTypeData.MessageType != to_underlying(MessageType::BlockAckEOF));

VerifyOrReturn(mExchangeCtx != nullptr, ChipLogError(BDX, "Exchange context is null"));
error =
mExchangeCtx->SendMessage(event.msgTypeData.ProtocolId, event.msgTypeData.MessageType, std::move(event.MsgData), flags);
VerifyOrReturn(error == CHIP_NO_ERROR, ChipLogError(BDX, "SendMessage failed: %" CHIP_ERROR_FORMAT, error.Format()));
break;
}
case TransferSession::OutputEventType::kAcceptReceived:
ChipLogProgress(BDX, "Starting image file transfer size %lldB", static_cast<uint64_t>(event.transferAcceptData.Length));
error = mImageProcessorDelegate->PrepareDownload();
if (error != CHIP_NO_ERROR)
{
ChipLogError(BDX, "Image processing prepare failed: %" CHIP_ERROR_FORMAT, error.Format());
mTransfer.Reset();
mImageProcessorDelegate->Abort();
return;
}

mImageInfo.imageSize = 0;

error = mTransfer.PrepareBlockQuery();
VerifyOrReturn(error == CHIP_NO_ERROR, ChipLogError(BDX, "PrepareBlockQuery failed: %" CHIP_ERROR_FORMAT, error.Format()));

break;
case TransferSession::OutputEventType::kBlockReceived: {
ChipLogProgress(BDX, "Received %uB (total: %ukB)", static_cast<unsigned>(event.blockdata.Length),
static_cast<unsigned>(mTransfer.GetNumBytesProcessed()) / 1024u);

ByteSpan data(event.blockdata.Data, event.blockdata.Length);
mImageProcessorDelegate->ProcessBlock(data);
if (error != CHIP_NO_ERROR)
{
ChipLogError(BDX, "Image processing process block failed: %" CHIP_ERROR_FORMAT, error.Format());
mTransfer.Reset();
;
mImageProcessorDelegate->Abort();
return;
}

mImageInfo.imageSize += event.blockdata.Length;

if (event.blockdata.IsEof)
{
error = mTransfer.PrepareBlockAck();
VerifyOrReturn(error == CHIP_NO_ERROR,
ChipLogError(BDX, "PrepareBlockAck failed: %" CHIP_ERROR_FORMAT, error.Format()));
mIsTransferComplete = true;
}
else
{
error = mTransfer.PrepareBlockQuery();
VerifyOrReturn(error == CHIP_NO_ERROR,
ChipLogError(BDX, "PrepareBlockQuery failed: %" CHIP_ERROR_FORMAT, error.Format()));
}
break;
}
case TransferSession::OutputEventType::kStatusReceived:
ChipLogError(BDX, "Received status %" PRIu16, to_underlying(event.statusData.statusCode));

if (event.statusData.statusCode != bdx::StatusCode::kNone)
{
mTransfer.Reset();
mImageProcessorDelegate->Abort();
}
break;
case TransferSession::OutputEventType::kInternalError:
ChipLogError(BDX, "Transfer stopped due to internal error");
mTransfer.Reset();
mImageProcessorDelegate->Abort();
break;
case TransferSession::OutputEventType::kTransferTimeout:
ChipLogError(BDX, "Transfer timed out");
mTransfer.Reset();
mImageProcessorDelegate->Abort();
break;
case TransferSession::OutputEventType::kInitReceived:
case TransferSession::OutputEventType::kAckReceived:
case TransferSession::OutputEventType::kQueryReceived:
case TransferSession::OutputEventType::kAckEOFReceived:
default:
ChipLogError(BDX, "Unexpected BDX event type: %" PRIu16, to_underlying(event.EventType));
}
}
44 changes: 44 additions & 0 deletions examples/ota-requestor-app/mbed/main/OTAImageProcessorImpl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
*
* 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.
*/

#include <OTAImageProcessorImpl.h>
#include <lib/support/logging/CHIPLogging.h>

CHIP_ERROR OTAImageProcessorImpl::PrepareDownload()
{
ChipLogProgress(SoftwareUpdate, "Prepare download");
return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(chip::ByteSpan & data)
{
ChipLogProgress(SoftwareUpdate, "Process block");
return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::Finalize()
{
ChipLogProgress(SoftwareUpdate, "Finalize");
return CHIP_NO_ERROR;
}

CHIP_ERROR OTAImageProcessorImpl::Abort()
{
ChipLogProgress(SoftwareUpdate, "Abort");
return CHIP_NO_ERROR;
};
Loading

0 comments on commit 0f4cdda

Please sign in to comment.