Skip to content

Commit

Permalink
[OTA] Add Linux implementation of OTAImageProcessorInterface (#12493)
Browse files Browse the repository at this point in the history
  • Loading branch information
carol-apple authored Dec 2, 2021
1 parent 7cba51d commit ae57e32
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 47 deletions.
1 change: 1 addition & 0 deletions examples/ota-requestor-app/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import("//build_overrides/chip.gni")

executable("chip-ota-requestor-app") {
sources = [
"LinuxOTAImageProcessor.cpp",
"LinuxOTARequestorDriver.cpp",
"main.cpp",
]
Expand Down
204 changes: 204 additions & 0 deletions examples/ota-requestor-app/linux/LinuxOTAImageProcessor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
/*
*
* 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 <app/clusters/ota-requestor/OTADownloader.h>

#include "LinuxOTAImageProcessor.h"

namespace chip {

// TODO: Dummy function to be removed once BDX downloader is implemented and can return a real instance
OTADownloader * GetDownloaderInstance()
{
return nullptr;
}

CHIP_ERROR LinuxOTAImageProcessor::PrepareDownload()
{
if (mParams.imageFile.empty())
{
ChipLogError(SoftwareUpdate, "Invalid output image file supplied");
return CHIP_ERROR_INTERNAL;
}

DeviceLayer::PlatformMgr().ScheduleWork(HandlePrepareDownload, reinterpret_cast<intptr_t>(this));
return CHIP_NO_ERROR;
}

CHIP_ERROR LinuxOTAImageProcessor::Finalize()
{
DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast<intptr_t>(this));
return CHIP_NO_ERROR;
}

CHIP_ERROR LinuxOTAImageProcessor::Abort()
{
if (mParams.imageFile.empty())
{
ChipLogError(SoftwareUpdate, "Invalid output image file supplied");
return CHIP_ERROR_INTERNAL;
}

DeviceLayer::PlatformMgr().ScheduleWork(HandleAbort, reinterpret_cast<intptr_t>(this));
return CHIP_NO_ERROR;
}

CHIP_ERROR LinuxOTAImageProcessor::ProcessBlock(ByteSpan & block)
{
if (!mOfs.is_open() || !mOfs.good())
{
return CHIP_ERROR_INTERNAL;
}

if ((block.data() == nullptr) || block.empty())
{
return CHIP_ERROR_INVALID_ARGUMENT;
}

// Store block data for HandleProcessBlock to access
CHIP_ERROR err = SetBlock(block);
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Cannot set block data: %" CHIP_ERROR_FORMAT, err.Format());
}

DeviceLayer::PlatformMgr().ScheduleWork(HandleProcessBlock, reinterpret_cast<intptr_t>(this));
return CHIP_NO_ERROR;
}

void LinuxOTAImageProcessor::HandlePrepareDownload(intptr_t context)
{
OTADownloader * downloader = GetDownloaderInstance();
if (downloader == nullptr)
{
ChipLogError(SoftwareUpdate, "No known OTA downloader");
return;
}

auto * imageProcessor = reinterpret_cast<LinuxOTAImageProcessor *>(context);
if (imageProcessor == nullptr)
{
downloader->OnPreparedForDownload(CHIP_ERROR_INVALID_ARGUMENT);
return;
}

imageProcessor->mOfs.open(imageProcessor->mParams.imageFile.data(),
std::ofstream::out | std::ofstream::ate | std::ofstream::app);
if (!imageProcessor->mOfs.good())
{
downloader->OnPreparedForDownload(CHIP_ERROR_OPEN_FAILED);
return;
}

downloader->OnPreparedForDownload(CHIP_NO_ERROR);
}

void LinuxOTAImageProcessor::HandleFinalize(intptr_t context)
{
auto * imageProcessor = reinterpret_cast<LinuxOTAImageProcessor *>(context);
if (imageProcessor == nullptr)
{
return;
}

imageProcessor->mOfs.close();
imageProcessor->ReleaseBlock();
}

void LinuxOTAImageProcessor::HandleAbort(intptr_t context)
{
auto * imageProcessor = reinterpret_cast<LinuxOTAImageProcessor *>(context);
if (imageProcessor == nullptr)
{
return;
}

imageProcessor->mOfs.close();
remove(imageProcessor->mParams.imageFile.data());
imageProcessor->ReleaseBlock();
}

void LinuxOTAImageProcessor::HandleProcessBlock(intptr_t context)
{
OTADownloader * downloader = GetDownloaderInstance();
if (downloader == nullptr)
{
ChipLogError(SoftwareUpdate, "No known OTA downloader");
return;
}

auto * imageProcessor = reinterpret_cast<LinuxOTAImageProcessor *>(context);
if (imageProcessor == nullptr)
{
downloader->OnBlockProcessed(CHIP_ERROR_INVALID_ARGUMENT, OTADownloader::kEnd);
return;
}

// TODO: Process block header if any

if (!imageProcessor->mOfs.write(reinterpret_cast<const char *>(imageProcessor->mBlock.data()),
static_cast<std::streamsize>(imageProcessor->mBlock.size())))
{
downloader->OnBlockProcessed(CHIP_ERROR_WRITE_FAILED, OTADownloader::kEnd);
return;
}

imageProcessor->mParams.downloadedBytes += imageProcessor->mBlock.size();
downloader->OnBlockProcessed(CHIP_NO_ERROR, OTADownloader::kGetNext);
}

CHIP_ERROR LinuxOTAImageProcessor::SetBlock(ByteSpan & block)
{
if ((block.data() == nullptr) || block.empty())
{
return CHIP_NO_ERROR;
}

// Allocate memory for block data if it has not been done yet
if (mBlock.empty())
{
mBlock = MutableByteSpan(static_cast<uint8_t *>(chip::Platform::MemoryAlloc(block.size())), block.size());
if (mBlock.data() == nullptr)
{
return CHIP_ERROR_NO_MEMORY;
}
}

// Store the actual block data
CHIP_ERROR err = CopySpanToMutableSpan(block, mBlock);
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Cannot copy block data: %" CHIP_ERROR_FORMAT, err.Format());
return err;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR LinuxOTAImageProcessor::ReleaseBlock()
{
if (mBlock.data() != nullptr)
{
chip::Platform::MemoryFree(mBlock.data());
}

mBlock = MutableByteSpan();
return CHIP_NO_ERROR;
}

} // namespace chip
57 changes: 35 additions & 22 deletions examples/ota-requestor-app/linux/LinuxOTAImageProcessor.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,43 @@
* limitations under the License.
*/

/* This file contains the decalarions for the Linux implementation of the
* the OTAImageProcessorDriver interface class
*/

#include "app/clusters/ota-requestor/OTAImageProcessor.h"

class LinuxOTAImageProcessor : public OTAImageProcessorDriver
{
#pragma once

// Virtuial functions from OTAImageProcessorDriver -- start
// Open file, find block of space in persistent memory, or allocate a buffer, etc.
CHIP_ERROR PrepareDownload() { return CHIP_NO_ERROR; }
#include <app/clusters/ota-requestor/OTAImageProcessor.h>
#include <platform/CHIPDeviceLayer.h>

// Must not be a blocking call to support cases that require IO to elements such as // external peripherals/radios
CHIP_ERROR ProcessBlock(chip::ByteSpan & data) { return CHIP_NO_ERROR; }
#include <fstream>

// Close file, close persistent storage, etc
CHIP_ERROR Finalize() { return CHIP_NO_ERROR; }
namespace chip {

chip::Optional<uint8_t> PercentComplete() { return chip::Optional<uint8_t>(0); }

// Clean up the download which could mean erasing everything that was written,
// releasing buffers, etc.
CHIP_ERROR Abort() { return CHIP_NO_ERROR; }

// Virtuial functions from OTAImageProcessorDriver -- end
class LinuxOTAImageProcessor : public OTAImageProcessorInterface
{
public:
//////////// OTAImageProcessorInterface Implementation ///////////////
CHIP_ERROR PrepareDownload() override;
CHIP_ERROR Finalize() override;
CHIP_ERROR Abort() override;
CHIP_ERROR ProcessBlock(ByteSpan & block) override;

private:
//////////// Actual handlers for the OTAImageProcessorInterface ///////////////
static void HandlePrepareDownload(intptr_t context);
static void HandleFinalize(intptr_t context);
static void HandleAbort(intptr_t context);
static void HandleProcessBlock(intptr_t context);

/**
* Called to allocate memory for mBlock if necessary and set it to block
*/
CHIP_ERROR SetBlock(ByteSpan & block);

/**
* Called to release allocated memory for mBlock
*/
CHIP_ERROR ReleaseBlock();

std::ofstream mOfs;
MutableByteSpan mBlock;
};

} // namespace chip
2 changes: 2 additions & 0 deletions examples/ota-requestor-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ using chip::CharSpan;
using chip::DeviceProxy;
using chip::EndpointId;
using chip::FabricIndex;
using chip::LinuxOTAImageProcessor;
using chip::NodeId;
using chip::OnDeviceConnected;
using chip::OnDeviceConnectionFailure;
using chip::OTADownloader;
using chip::PeerId;
using chip::Server;
using chip::VendorId;
Expand Down
12 changes: 8 additions & 4 deletions src/app/clusters/ota-requestor/OTADownloader.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

#pragma once

namespace chip {

// A class that abstracts the image download functionality from the particular
// protocol used for that (BDX or possibly HTTPS)
class OTADownloader
Expand All @@ -38,7 +40,7 @@ class OTADownloader
void virtual BeginDownload(){};

// Platform calls this method upon the completion of PrepareDownload() processing
void virtual OnPreparedForDownload(){};
void virtual OnPreparedForDownload(CHIP_ERROR status){};

// Action parameter type for the OnBlockProcessed()
enum BlockActionType
Expand All @@ -48,22 +50,24 @@ class OTADownloader
};

// Platform calls this method upon the completion of ProcessBlock() processing
void virtual OnBlockProcessed(BlockActionType action){};
void virtual OnBlockProcessed(CHIP_ERROR status, BlockActionType action){};

// A setter for the delegate class pointer
void SetImageProcessorDelegate(OTAImageProcessorDriver * delegate) { mImageProcessorDelegate = delegate; }
void SetImageProcessorDelegate(OTAImageProcessorInterface * delegate) { mImageProcessorDelegate = delegate; }

// API declarations end

// Destructor
virtual ~OTADownloader() = default;

private:
OTAImageProcessorDriver * mImageProcessorDelegate;
OTAImageProcessorInterface * mImageProcessorDelegate;
};

// Set the object implementing OTADownloader
void SetDownloaderInstance(OTADownloader * instance);

// Get the object implementing OTADownloaderInterface
OTADownloader * GetDownloaderInstance();

} // namespace chip
Loading

0 comments on commit ae57e32

Please sign in to comment.