From 220780518f904b699727b70715f4705742147cba Mon Sep 17 00:00:00 2001 From: Wang Qixiang <43193572+wqx6@users.noreply.github.com> Date: Thu, 16 Dec 2021 16:48:40 +0800 Subject: [PATCH] OTA Requestor: Use common codes for ESP OTA-Requestor app & move OTA implements to platform path (#13017) * use common codes of ota-requestor cluster in ESP OTA-Requestor app * move OTAImageProcessor and OTARequestorDriver Implement to /src/platform/ * Add OTA implements for darwin platform --- config/esp32/components/chip/Kconfig | 6 + .../esp32/main/Kconfig.projbuild | 9 - .../esp32/main/BDXDownloader.cpp | 155 --------- .../esp32/main/CMakeLists.txt | 6 +- .../esp32/main/OTARequesterImpl.cpp | 325 ------------------ .../esp32/main/OTAUpdater.cpp | 155 --------- .../esp32/main/include/BDXDownloader.h | 85 ----- .../esp32/main/include/OTAUpdater.h | 105 ------ .../ota-requestor-app/esp32/main/main.cpp | 87 ++--- .../esp32/sdkconfig.defaults | 3 + examples/ota-requestor-app/linux/BUILD.gn | 6 +- examples/ota-requestor-app/linux/args.gni | 4 + examples/ota-requestor-app/linux/main.cpp | 10 +- src/lib/shell/commands/BUILD.gn | 4 +- src/platform/Darwin/BUILD.gn | 10 + src/platform/ESP32/BUILD.gn | 8 + src/platform/ESP32/OTAImageProcessorImpl.cpp | 211 ++++++++++++ src/platform/ESP32/OTAImageProcessorImpl.h | 54 +++ src/platform/ESP32/OTARequestorDriverImpl.cpp | 40 +++ .../platform/ESP32/OTARequestorDriverImpl.h | 25 +- src/platform/Linux/BUILD.gn | 9 + .../platform/Linux/OTAImageProcessorImpl.cpp | 32 +- .../platform/Linux/OTAImageProcessorImpl.h | 2 +- .../platform/Linux/OTARequestorDriverImpl.cpp | 8 +- .../platform/Linux/OTARequestorDriverImpl.h | 2 +- 25 files changed, 411 insertions(+), 950 deletions(-) delete mode 100644 examples/ota-requestor-app/esp32/main/BDXDownloader.cpp delete mode 100644 examples/ota-requestor-app/esp32/main/OTARequesterImpl.cpp delete mode 100644 examples/ota-requestor-app/esp32/main/OTAUpdater.cpp delete mode 100644 examples/ota-requestor-app/esp32/main/include/BDXDownloader.h delete mode 100644 examples/ota-requestor-app/esp32/main/include/OTAUpdater.h create mode 100644 src/platform/ESP32/OTAImageProcessorImpl.cpp create mode 100644 src/platform/ESP32/OTAImageProcessorImpl.h create mode 100644 src/platform/ESP32/OTARequestorDriverImpl.cpp rename examples/ota-requestor-app/esp32/main/include/OTARequesterImpl.h => src/platform/ESP32/OTARequestorDriverImpl.h (61%) rename examples/ota-requestor-app/linux/LinuxOTAImageProcessor.cpp => src/platform/Linux/OTAImageProcessorImpl.cpp (83%) rename examples/ota-requestor-app/linux/LinuxOTAImageProcessor.h => src/platform/Linux/OTAImageProcessorImpl.h (96%) rename examples/ota-requestor-app/linux/LinuxOTARequestorDriver.cpp => src/platform/Linux/OTARequestorDriverImpl.cpp (84%) rename examples/ota-requestor-app/linux/LinuxOTARequestorDriver.h => src/platform/Linux/OTARequestorDriverImpl.h (96%) diff --git a/config/esp32/components/chip/Kconfig b/config/esp32/components/chip/Kconfig index 3e59822a63553b..b7837b42cc9696 100644 --- a/config/esp32/components/chip/Kconfig +++ b/config/esp32/components/chip/Kconfig @@ -149,6 +149,12 @@ menu "CHIP Core" help The maximum number of simultaneously timers in the CHIP System Layer. + config ENABLE_OTA_REQUESTOR + bool "Enable OTA Requestor" + default n + help + Enable this option to enable OTA Requestor for example + endmenu # "System Options" menu "Security Options" diff --git a/examples/all-clusters-app/esp32/main/Kconfig.projbuild b/examples/all-clusters-app/esp32/main/Kconfig.projbuild index e82f04f2ac00e5..0960168aadca4a 100644 --- a/examples/all-clusters-app/esp32/main/Kconfig.projbuild +++ b/examples/all-clusters-app/esp32/main/Kconfig.projbuild @@ -140,12 +140,3 @@ depends on ENABLE_PW_RPC about available pin numbers for UART. endmenu - -menu "OTA Options" - - config ENABLE_OTA_REQUESTOR - bool "Enable OTA Requestor" - default y - help - Enable this option to enable the OTA Requestor -endmenu diff --git a/examples/ota-requestor-app/esp32/main/BDXDownloader.cpp b/examples/ota-requestor-app/esp32/main/BDXDownloader.cpp deleted file mode 100644 index db1f08f1f40f25..00000000000000 --- a/examples/ota-requestor-app/esp32/main/BDXDownloader.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * 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 "BDXDownloader.h" - -#include -#include -#include -#include - -using namespace chip::bdx; - -void BdxDownloader::SetInitialExchange(chip::Messaging::ExchangeContext * ec) -{ - mExchangeCtx = ec; -} - -void BdxDownloader::SetCallbacks(BdxDownloaderCallbacks callbacks) -{ - mOnBlockReceivedCallback = callbacks.onBlockReceived; - mOnTransferCompleteCallback = callbacks.onTransferComplete; - mOnTransferFailedCallback = callbacks.onTransferFailed; -} - -void BdxDownloader::HandleTransferSessionOutput(TransferSession::OutputEvent & event) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - if (event.EventType != TransferSession::OutputEventType::kNone) - { - ChipLogDetail(BDX, "OutputEvent type: %s", event.ToString(event.EventType)); - } - - switch (event.EventType) - { - case TransferSession::OutputEventType::kNone: - if (mIsTransferComplete) - { - if (mOnTransferCompleteCallback != nullptr && mOnTransferCompleteCallback->mCall != nullptr) - { - mOnTransferCompleteCallback->mCall(mOnTransferCompleteCallback->mContext); - } - else - { - ChipLogError(BDX, "onTransferComplete Callback not set"); - } - mTransfer.Reset(); - mIsTransferComplete = false; - } - break; - case TransferSession::OutputEventType::kMsgToSend: { - chip::Messaging::SendFlags sendFlags; - VerifyOrReturn(mExchangeCtx != nullptr, ChipLogError(BDX, "mExchangeContext is null, cannot proceed")); - if (event.msgTypeData.MessageType == static_cast(MessageType::ReceiveInit)) - { - sendFlags.Set(chip::Messaging::SendMessageFlags::kFromInitiator); - } - if (event.msgTypeData.MessageType != static_cast(MessageType::BlockAckEOF)) - { - sendFlags.Set(chip::Messaging::SendMessageFlags::kExpectResponse); - } - err = mExchangeCtx->SendMessage(event.msgTypeData.ProtocolId, event.msgTypeData.MessageType, std::move(event.MsgData), - sendFlags); - VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(BDX, "SendMessage failed: %" CHIP_ERROR_FORMAT, err.Format())); - break; - } - case TransferSession::OutputEventType::kAcceptReceived: - VerifyOrReturn(CHIP_NO_ERROR == mTransfer.PrepareBlockQuery(), ChipLogError(BDX, "PrepareBlockQuery failed")); - break; - case TransferSession::OutputEventType::kBlockReceived: { - ChipLogDetail(BDX, "Got block length %zu", event.blockdata.Length); - - // TODO: while convenient, we should not do a synchronous block write in our example application - this is bad practice - if (mOnBlockReceivedCallback != nullptr && mOnBlockReceivedCallback->mCall != nullptr) - { - mOnBlockReceivedCallback->mCall(mOnBlockReceivedCallback->mContext, event.blockdata); - } - else - { - ChipLogError(BDX, "onBlockReceived Callback not set"); - } - if (event.blockdata.IsEof) - { - err = mTransfer.PrepareBlockAck(); - VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(BDX, "PrepareBlockAck failed: %" CHIP_ERROR_FORMAT, err.Format())); - mIsTransferComplete = true; - } - else - { - err = mTransfer.PrepareBlockQuery(); - VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(BDX, "PrepareBlockQuery failed: %" CHIP_ERROR_FORMAT, err.Format())); - } - break; - } - case TransferSession::OutputEventType::kStatusReceived: - ChipLogError(BDX, "Got StatusReport %x", static_cast(event.statusData.statusCode)); - if (mOnTransferFailedCallback != nullptr && mOnTransferFailedCallback->mCall != nullptr) - { - mOnTransferFailedCallback->mCall(mOnTransferFailedCallback->mContext, kErrorBdxDownloaderStatusReceived); - } - else - { - ChipLogError(BDX, "onTransferFailed Callback not set"); - } - mTransfer.Reset(); - mExchangeCtx->Close(); - break; - case TransferSession::OutputEventType::kInternalError: - ChipLogError(BDX, "InternalError"); - if (mOnTransferFailedCallback != nullptr && mOnTransferFailedCallback->mCall != nullptr) - { - mOnTransferFailedCallback->mCall(mOnTransferFailedCallback->mContext, kErrorBdxDownloaderInternal); - } - else - { - ChipLogError(BDX, "onTransferFailed Callback not set"); - } - mTransfer.Reset(); - mExchangeCtx->Close(); - break; - case TransferSession::OutputEventType::kTransferTimeout: - ChipLogError(BDX, "Transfer timed out"); - if (mOnTransferFailedCallback != nullptr && mOnTransferFailedCallback->mCall != nullptr) - { - mOnTransferFailedCallback->mCall(mOnTransferFailedCallback->mContext, kErrorBdxDownloaderTimeOut); - } - else - { - ChipLogError(BDX, "onTransferFailed Callback not set"); - } - mTransfer.Reset(); - mExchangeCtx->Close(); - 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, static_cast(event.EventType)); - } -} diff --git a/examples/ota-requestor-app/esp32/main/CMakeLists.txt b/examples/ota-requestor-app/esp32/main/CMakeLists.txt index 156ef5f8cb9a04..da030f0bccf926 100644 --- a/examples/ota-requestor-app/esp32/main/CMakeLists.txt +++ b/examples/ota-requestor-app/esp32/main/CMakeLists.txt @@ -18,8 +18,8 @@ # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_CURRENT_LIST_DIR}/include" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/ota-requestor-app/" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/ota-requestor-app/ota-requestor-common" SRC_DIRS "${CMAKE_CURRENT_LIST_DIR}" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/zzz_generated/ota-requestor-app/zap-generated" @@ -44,9 +44,7 @@ idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/general-commissioning-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/network-commissioning" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/operational-credentials-server" - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/ota-requestor-app/ota-requestor-common" - EXCLUDE_SRCS - "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.cpp" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/ota-requestor" PRIV_REQUIRES chip QRCode bt console app_update) set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 14) diff --git a/examples/ota-requestor-app/esp32/main/OTARequesterImpl.cpp b/examples/ota-requestor-app/esp32/main/OTARequesterImpl.cpp deleted file mode 100644 index b6c84742019da4..00000000000000 --- a/examples/ota-requestor-app/esp32/main/OTARequesterImpl.cpp +++ /dev/null @@ -1,325 +0,0 @@ -/* - * - * 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 -#include -#include -#include -#include -#include - -#include - -#include "BDXDownloader.h" -#include "OTARequesterImpl.h" -#include "OTAUpdater.h" - -#define TAG "OTARequesterImpl" - -using chip::ByteSpan; -using chip::CharSpan; -using chip::EndpointId; -using chip::FabricIndex; -using chip::NodeId; -using chip::OnDeviceConnected; -using chip::OnDeviceConnectionFailure; -using chip::OperationalDeviceProxy; -using chip::Optional; -using chip::PeerId; -using chip::Server; -using chip::VendorId; -using chip::bdx::TransferSession; -using chip::Callback::Callback; -using chip::Inet::IPAddress; -using chip::System::Layer; -using chip::Transport::PeerAddress; -using namespace chip::Messaging; -using namespace chip::app::Clusters::OtaSoftwareUpdateProvider::Commands; - -void OnQueryImageResponse(void * context, const QueryImageResponse::DecodableType & response); -void OnQueryImageFailure(void * context, EmberAfStatus status); -void OnApplyUpdateResponse(void * context, const ApplyUpdateResponse::DecodableType & response); -void OnApplyUpdateRequestFailure(void * context, EmberAfStatus status); - -void OnConnected(void * context, chip::OperationalDeviceProxy * deviceProxy); -void OnConnectionFailure(void * context, NodeId deviceId, CHIP_ERROR error); - -void OnBlockReceived(void * context, const chip::bdx::TransferSession::BlockData & blockdata); -void OnTransferComplete(void * context); -void OnTransferFailed(void * context, BdxDownloaderErrorTypes status); - -enum OTARequestorCommands -{ - kCommandQueryImage = 0, - kCommandApplyUpdateRequest, - kCommandNotifyUpdateApplied, -}; - -namespace { -// TODO: Encapsulate these globals and the callbacks in some class -ExchangeContext * exchangeCtx = nullptr; -BdxDownloader bdxDownloader; -enum OTARequestorCommands operationalDeviceContext; - -constexpr uint8_t kMaxUpdateTokenLen = 32; // must be between 8 and 32 -uint8_t otaUpdateToken[kMaxUpdateTokenLen] = { 0 }; -uint8_t otaUpdateTokenLen = 0; - -/* Callbacks for operational device proxy connect response */ -Callback onConnectedCallback(OnConnected, &operationalDeviceContext); -Callback onConnectionFailureCallback(OnConnectionFailure, nullptr); - -/* Callbacks for BDX data transfer */ -Callback onBlockReceivedCallback(OnBlockReceived, nullptr); -Callback onTransferCompleteCallback(OnTransferComplete, nullptr); -Callback onTransferFailedCallback(OnTransferFailed, nullptr); - -FabricIndex providerFabricIndex = 1; -} // namespace - -void OnQueryImageResponse(void * context, const QueryImageResponse::DecodableType & response) -{ - ChipLogDetail(SoftwareUpdate, "QueryImageResponse responded with action %" PRIu8, response.status); - - if (response.updateToken.HasValue()) - { - otaUpdateTokenLen = response.updateToken.Value().size(); - memcpy(otaUpdateToken, response.updateToken.Value().data(), otaUpdateTokenLen); - } - if (response.imageURI.HasValue() == false) - { - ChipLogError(BDX, "OTA image URI missing"); - return; - } - - // TODO: Handle image URI for protocol other than bdx - // Ignore the first 23 "bdx:///" - char fileDesignator[128]; // 128 is arbitrary value - memset(fileDesignator, 0, sizeof(fileDesignator)); - size_t fileDesignatorLength = response.imageURI.Value().size() - 23 + 1; // + 1 for \0 - if ((response.imageURI.Value().size() - 23) > sizeof(fileDesignator)) - { - fileDesignatorLength = sizeof(fileDesignator); - } - strlcpy(fileDesignator, response.imageURI.Value().data() + 23, fileDesignatorLength); - - TransferSession::TransferInitData initOptions; - initOptions.TransferCtlFlags = chip::bdx::TransferControlFlags::kReceiverDrive; - initOptions.MaxBlockSize = 1024; - initOptions.FileDesLength = static_cast(fileDesignatorLength); - initOptions.FileDesignator = reinterpret_cast(fileDesignator); - - chip::OperationalDeviceProxy * operationalDeviceProxy = Server::GetInstance().GetOperationalDeviceProxy(); - if (operationalDeviceProxy != nullptr) - { - chip::Messaging::ExchangeManager * exchangeMgr = operationalDeviceProxy->GetExchangeManager(); - chip::Optional session = operationalDeviceProxy->GetSecureSession(); - if (exchangeMgr != nullptr && session.HasValue()) - { - exchangeCtx = exchangeMgr->NewContext(session.Value(), &bdxDownloader); - } - if (exchangeCtx == nullptr) - { - ChipLogError(BDX, "unable to allocate ec: exchangeMgr=%p sessionExists? %u", exchangeMgr, session.HasValue()); - return; - } - } - else - { - ChipLogError(BDX, "Failed to get OperationalDeviceProxy"); - return; - } - - bdxDownloader.SetInitialExchange(exchangeCtx); - - BdxDownloaderCallbacks bdxCallbacks; - bdxCallbacks.onBlockReceived = &onBlockReceivedCallback; - bdxCallbacks.onTransferComplete = &onTransferCompleteCallback; - bdxCallbacks.onTransferFailed = &onTransferFailedCallback; - bdxDownloader.SetCallbacks(bdxCallbacks); - - // This will kick of a timer which will regularly check for updates to the bdx::TransferSession state machine. - bdxDownloader.InitiateTransfer(&chip::DeviceLayer::SystemLayer(), chip::bdx::TransferRole::kReceiver, initOptions, - chip::System::Clock::Seconds16(20)); -} - -void OnApplyUpdateResponse(void * context, const ApplyUpdateResponse::DecodableType & response) -{ - ChipLogDetail(SoftwareUpdate, "ApplyUpdateResponse responded with action %" PRIu8, response.action); - // Providing arbitrary value - OTAUpdater::GetInstance().Apply(3); -} - -void OnQueryImageFailure(void * context, EmberAfStatus status) -{ - ChipLogDetail(SoftwareUpdate, "QueryImage failure response %" PRIu8, status); -} - -void OnApplyUpdateRequestFailure(void * context, EmberAfStatus status) -{ - ChipLogDetail(SoftwareUpdate, "ApplyUpdateRequest failure response %" PRIu8, status); -} - -void OnConnected(void * context, chip::OperationalDeviceProxy * deviceProxy) -{ - ChipLogDetail(SoftwareUpdate, "Callback OnConnected"); - uint8_t * command = reinterpret_cast(context); - - chip::Controller::OtaSoftwareUpdateProviderCluster cluster; - constexpr EndpointId kOtaProviderEndpoint = 0; - - CHIP_ERROR err = cluster.Associate(deviceProxy, kOtaProviderEndpoint); - if (err != CHIP_NO_ERROR) - { - ChipLogError(SoftwareUpdate, "Associate() failed: %s", chip::ErrorStr(err)); - return; - } - - switch (*command) - { - case kCommandQueryImage: { - // These parameters are chosen arbitrarily - constexpr VendorId kExampleVendorId = VendorId::Common; - constexpr uint16_t kExampleProductId = CONFIG_DEVICE_PRODUCT_ID; - constexpr uint16_t kExampleHWVersion = 0; - constexpr uint16_t kExampleSoftwareVersion = 0; - constexpr EmberAfOTADownloadProtocol kExampleProtocolsSupported[] = { EMBER_ZCL_OTA_DOWNLOAD_PROTOCOL_BDX_SYNCHRONOUS }; - const char locationBuf[] = { 'U', 'S' }; - CharSpan exampleLocation(locationBuf); - constexpr bool kExampleClientCanConsent = false; - ByteSpan metadata; - - QueryImage::Type args; - args.vendorId = kExampleVendorId; - args.productId = kExampleProductId; - args.softwareVersion = kExampleSoftwareVersion; - args.protocolsSupported = kExampleProtocolsSupported; - args.hardwareVersion.Emplace(kExampleHWVersion); - args.location.Emplace(exampleLocation); - args.requestorCanConsent.Emplace(kExampleClientCanConsent); - args.metadataForProvider.Emplace(metadata); - - err = cluster.InvokeCommand(args, nullptr, OnQueryImageResponse, OnQueryImageFailure); - if (err != CHIP_NO_ERROR) - { - ChipLogError(SoftwareUpdate, "QueryImage() failed: %" CHIP_ERROR_FORMAT, err.Format()); - } - break; - } - case kCommandApplyUpdateRequest: { - constexpr uint32_t kNewVersion = 1; - - ApplyUpdateRequest::Type args; - args.updateToken = ByteSpan(otaUpdateToken, otaUpdateTokenLen); - args.newVersion = kNewVersion; - - err = cluster.InvokeCommand(args, nullptr, OnApplyUpdateResponse, OnApplyUpdateRequestFailure); - if (err != CHIP_NO_ERROR) - { - ChipLogError(SoftwareUpdate, "ApplyUpdateRequest() failed: %s", chip::ErrorStr(err)); - } - break; - } - default: - break; - } -} - -void OnConnectionFailure(void * context, NodeId deviceId, CHIP_ERROR error) -{ - ChipLogError(SoftwareUpdate, "failed to connect to 0x%" PRIX64 ": %" CHIP_ERROR_FORMAT, deviceId, error.Format()); -} - -void OnBlockReceived(void * context, const chip::bdx::TransferSession::BlockData & blockdata) -{ - if (OTAUpdater::GetInstance().IsInProgress() == false) - { - OTAUpdater::GetInstance().Begin(); - } - // TODO: Process/skip the Matter OTA header - OTAUpdater::GetInstance().Write(reinterpret_cast(blockdata.Data), blockdata.Length); -} - -void OnTransferComplete(void * context) -{ - ESP_LOGI(TAG, "Transfer complete!"); - OTAUpdater::GetInstance().End(); -} - -void OnTransferFailed(void * context, BdxDownloaderErrorTypes status) -{ - ESP_LOGI(TAG, "Transfer Failed, status:%x", status); - OTAUpdater::GetInstance().Abort(); -} - -void ConnectToProvider(const char * ipAddress, uint32_t nodeId) -{ - NodeId providerNodeId = nodeId; - - chip::OperationalDeviceProxy * operationalDeviceProxy = Server::GetInstance().GetOperationalDeviceProxy(); - if (operationalDeviceProxy != nullptr && operationalDeviceProxy->GetDeviceId() != providerNodeId) - { - operationalDeviceProxy->Disconnect(); - delete operationalDeviceProxy; - operationalDeviceProxy = nullptr; - } - - if (operationalDeviceProxy == nullptr) - { - Server * server = &(Server::GetInstance()); - chip::FabricInfo * fabric = server->GetFabricTable().FindFabricWithIndex(providerFabricIndex); - - chip::DeviceProxyInitParams initParams = { - .sessionManager = &(server->GetSecureSessionManager()), - .exchangeMgr = &(server->GetExchangeManager()), - .idAllocator = &(server->GetSessionIDAllocator()), - .fabricInfo = fabric, - // TODO: Determine where this should be instantiated - .imDelegate = chip::Platform::New(), - }; - - PeerId peerID = fabric->GetPeerId(); - peerID.SetNodeId(providerNodeId); - operationalDeviceProxy = new chip::OperationalDeviceProxy(initParams, peerID); - server->SetOperationalDeviceProxy(operationalDeviceProxy); - - // Explicitly calling UpdateDeviceData() should not be needed once OperationalDeviceProxy can resolve IP address from node - // ID and fabric index - IPAddress ipAddr; - IPAddress::FromString(ipAddress, ipAddr); - PeerAddress addr = PeerAddress::UDP(ipAddr, CHIP_PORT); - operationalDeviceProxy->UpdateDeviceData(addr, operationalDeviceProxy->GetMRPConfig()); - } - - CHIP_ERROR err = operationalDeviceProxy->Connect(&onConnectedCallback, &onConnectionFailureCallback); - if (err != CHIP_NO_ERROR) - { - ChipLogError(SoftwareUpdate, "Cannot establish connection to peer device: %" CHIP_ERROR_FORMAT, err.Format()); - } -} - -void OTARequesterImpl::SendQueryImageCommand(const char * ipAddress, uint32_t nodeId) -{ - operationalDeviceContext = kCommandQueryImage; - ConnectToProvider(ipAddress, nodeId); -} - -void OTARequesterImpl::SendApplyUpdateRequestCommand(const char * ipAddress, uint32_t nodeId) -{ - operationalDeviceContext = kCommandApplyUpdateRequest; - ConnectToProvider(ipAddress, nodeId); -} diff --git a/examples/ota-requestor-app/esp32/main/OTAUpdater.cpp b/examples/ota-requestor-app/esp32/main/OTAUpdater.cpp deleted file mode 100644 index 82156fee97a10c..00000000000000 --- a/examples/ota-requestor-app/esp32/main/OTAUpdater.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * 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 -#include -#include -#include - -#include - -using namespace ::chip; -using namespace ::chip::System; -using namespace ::chip::DeviceLayer; - -namespace { - -const char * TAG = "OTAUpdate"; -bool otaUpdateInProgress = false; -const esp_partition_t * otaUpdatePartition = nullptr; -esp_ota_handle_t otaUpdateHandle; -uint32_t otaUpdateImageLen = 0; - -} // namespace - -bool OTAUpdater::IsInProgress(void) -{ - return otaUpdateInProgress; -} - -esp_err_t OTAUpdater::Begin(void) -{ - if (otaUpdateInProgress == true) - { - ESP_LOGW(TAG, "Already in progress"); - return ESP_ERR_INVALID_STATE; - } - - ESP_LOGI(TAG, "Begin"); - otaUpdatePartition = esp_ota_get_next_update_partition(NULL); - if (otaUpdatePartition == NULL) - { - ESP_LOGE(TAG, "Partition not found"); - return ESP_ERR_NOT_FOUND; - } - ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x", otaUpdatePartition->subtype, otaUpdatePartition->address); - - esp_err_t err = esp_ota_begin(otaUpdatePartition, OTA_WITH_SEQUENTIAL_WRITES, &otaUpdateHandle); - if (err != ESP_OK) - { - ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err)); - return err; - } - otaUpdateImageLen = 0; - otaUpdateInProgress = true; - return ESP_OK; -} - -esp_err_t OTAUpdater::Write(const void * data, size_t length) -{ - if (otaUpdateInProgress == false) - { - return ESP_ERR_INVALID_STATE; - } - - esp_err_t err = esp_ota_write(otaUpdateHandle, data, length); - if (err != ESP_OK) - { - ESP_LOGE(TAG, "esp_ota_write failed (%s)", esp_err_to_name(err)); - Abort(); - return err; - } - - otaUpdateImageLen += length; - ESP_LOGI(TAG, "Written image length %d", otaUpdateImageLen); - return ESP_OK; -} - -esp_err_t OTAUpdater::Abort(void) -{ - if (otaUpdateInProgress == false) - { - return ESP_ERR_INVALID_STATE; - } - - ESP_LOGI(TAG, "Abort"); - otaUpdateInProgress = false; - otaUpdateImageLen = 0; - return esp_ota_abort(otaUpdateHandle); -} - -esp_err_t OTAUpdater::End(void) -{ - if (otaUpdateInProgress == false) - { - return ESP_ERR_INVALID_STATE; - } - - ESP_LOGI(TAG, "OTA image length %d bytes", otaUpdateImageLen); - esp_err_t err = esp_ota_end(otaUpdateHandle); - if (err != ESP_OK) - { - if (err == ESP_ERR_OTA_VALIDATE_FAILED) - { - ESP_LOGE(TAG, "Image validation failed, image is corrupted"); - } - else - { - ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err)); - } - } - otaUpdateInProgress = false; - return err; -} - -void RestartTimerHandler(Layer * systemLayer, void * appState) -{ - ESP_LOGI(TAG, "Prepare to restart system!"); - esp_restart(); -} - -// TODO: Apply update after delayed action time -// TODO: Handle applying update after reboot -esp_err_t OTAUpdater::Apply(uint32_t delayedActionTime) -{ - if (otaUpdateInProgress == true) - { - return ESP_ERR_INVALID_STATE; - } - - esp_err_t err = esp_ota_set_boot_partition(otaUpdatePartition); - if (err != ESP_OK) - { - ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)); - return err; - } - - ESP_LOGI(TAG, "Applying, Boot partition set offset:0x%x", otaUpdatePartition->address); - // Allow requestor to send the Ack for the previous message - chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(delayedActionTime * 1000), RestartTimerHandler, - nullptr); - return ESP_OK; -} diff --git a/examples/ota-requestor-app/esp32/main/include/BDXDownloader.h b/examples/ota-requestor-app/esp32/main/include/BDXDownloader.h deleted file mode 100644 index a05b772cea0008..00000000000000 --- a/examples/ota-requestor-app/esp32/main/include/BDXDownloader.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * 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 -#include -#include -#include - -#pragma once - -enum BdxDownloaderErrorTypes -{ - kErrorBdxDownloaderNoError = 0, - kErrorBdxDownloaderStatusReceived, - kErrorBdxDownloaderInternal, - kErrorBdxDownloaderTimeOut, -}; - -/** - * @brief - * This callback is called when bdx transfer receives Block or BlockEOF message - * - * @param[in] context User context - * @param[in] blockData BlockData structure which contains pointer to data, length of data and IsEof flag - */ -typedef void (*OnBdxBlockReceived)(void * context, const chip::bdx::TransferSession::BlockData & blockdata); - -/** - * @brief - * This callback is called after BlockEOF message is processed - * - * @param[in] context User context - */ -typedef void (*OnBdxTransferComplete)(void * context); - -/** - * @brief - * This callback is called when bdx transfer receives StatusReport messages, - * if there is any internal error, or transfer timed out - * - * @param[in] context User context - * @param[in] status Error code - */ -typedef void (*OnBdxTransferFailed)(void * context, BdxDownloaderErrorTypes status); - -// TODO: With this approach we might end up adding callback for every bdx event/message. -// Can be refactored into a single callback with events -struct BdxDownloaderCallbacks -{ - chip::Callback::Callback * onBlockReceived = nullptr; - chip::Callback::Callback * onTransferComplete = nullptr; - chip::Callback::Callback * onTransferFailed = nullptr; -}; - -class BdxDownloader : public chip::bdx::Initiator -{ -public: - void SetInitialExchange(chip::Messaging::ExchangeContext * ec); - - void SetCallbacks(BdxDownloaderCallbacks callbacks); - -private: - // inherited from bdx::Endpoint - void HandleTransferSessionOutput(chip::bdx::TransferSession::OutputEvent & event); - - bool mIsTransferComplete = false; - - chip::Callback::Callback * mOnBlockReceivedCallback = nullptr; - chip::Callback::Callback * mOnTransferCompleteCallback = nullptr; - chip::Callback::Callback * mOnTransferFailedCallback = nullptr; -}; diff --git a/examples/ota-requestor-app/esp32/main/include/OTAUpdater.h b/examples/ota-requestor-app/esp32/main/include/OTAUpdater.h deleted file mode 100644 index 725ea7bbcd62ba..00000000000000 --- a/examples/ota-requestor-app/esp32/main/include/OTAUpdater.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * - * 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 - -#pragma once - -/** - * @class OTAUpdater - * - * @brief This is a helper class to perform OTA on ESP devices. - * It supports preparing the flash region for new OTA image, - * writing OTA data to the flash region, successfully ending an OTA, - * aborting the OTA process, and booting from the new OTA image. - */ -class OTAUpdater -{ -public: - static OTAUpdater & GetInstance(void) - { - static OTAUpdater instance; - return instance; - } - - /** - * @brief - * Test if OTA is in progress or not. - * - * @return \c true if OTA is in progress; - * return \c false if OTA is not in progress; - */ - bool IsInProgress(void); - - /** - * @brief - * Begins an OTA data writing. - * This function finds the available flash region to write the OTA data and erase the region. - * - * @return \c ESP_OK on success; - * return \c ESP_ERR_INVALID_STATE if OTA is in progress; - * return appropriate error code otherwise; - */ - esp_err_t Begin(void); - - /** - * @brief - * Finish OTA update and validate newly written OTA image. - * - * @return \c ESP_OK on success; - * return \c ESP_ERR_INVALID_STATE if OTA is not in progress; - * return \c ESP_ERR_OTA_VALIDATE_FAILED if OTA image is invalid; - * return appropriate error code otherwise; - */ - esp_err_t End(void); - - /** - * @brief - * Write OTA data. This function can be called multiple times as data is received during the OTA operation. - * Data is written sequentially to the partition. - * - * @param[in] data OTA data - * @param[in] length Length of OTA data - * - * @return \c ESP_OK on success; - * return \c ESP_ERR_OTA_VALIDATE_FAILED First byte of image contains invalid app image magic byte; - * return appropriate error code otherwise; - */ - esp_err_t Write(const void * data, size_t length); - - /** - * @brief - * Abort the OTA. - * - * @return \c ESP_OK on success; - * return appropriate error code otherwise; - */ - esp_err_t Abort(void); - - /** - * @brief - * Apply an OTA update. - * Configures the boot partition to newly written OTA partition and restart device to boot from new app. - * - * @return \c ESP_OK on success; - * return appropriate error code otherwise; - */ - esp_err_t Apply(uint32_t delayedActionTime); - -private: - OTAUpdater(void) {} - ~OTAUpdater() {} -}; diff --git a/examples/ota-requestor-app/esp32/main/main.cpp b/examples/ota-requestor-app/esp32/main/main.cpp index 71f5e3b491b95b..ab3bc6fff2843d 100644 --- a/examples/ota-requestor-app/esp32/main/main.cpp +++ b/examples/ota-requestor-app/esp32/main/main.cpp @@ -28,6 +28,8 @@ #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "nvs_flash.h" +#include +#include #include #include @@ -40,7 +42,9 @@ #include -#include "OTARequesterImpl.h" +#include "OTAImageProcessorImpl.h" +#include "OTARequestorDriverImpl.h" +#include "platform/OTARequestorInterface.h" #include #include @@ -52,57 +56,24 @@ using namespace ::chip::DeviceLayer; struct CmdArgs { - struct arg_str * ipAddr; - struct arg_int * nodeId; struct arg_end * end; }; namespace { const char * TAG = "ota-requester-app"; static DeviceCallbacks EchoCallbacks; -CmdArgs queryImageCmdArgs, applyUpdateCmdArgs; -} // namespace - -void QueryImageTimerHandler(Layer * systemLayer, void * appState) -{ - ESP_LOGI(TAG, "Calling SendQueryImageCommand()"); - OTARequesterImpl::GetInstance().SendQueryImageCommand(queryImageCmdArgs.ipAddr->sval[0], queryImageCmdArgs.nodeId->ival[0]); -} - -void ApplyUpdateTimerHandler(Layer * systemLayer, void * appState) -{ - ESP_LOGI(TAG, "Calling SendApplyUpdateRequestCommand()"); - OTARequesterImpl::GetInstance().SendApplyUpdateRequestCommand(queryImageCmdArgs.ipAddr->sval[0], - queryImageCmdArgs.nodeId->ival[0]); -} - -int ESPQueryImageCmdHandler(int argc, char ** argv) -{ - int nerrors = arg_parse(argc, argv, (void **) &queryImageCmdArgs); - if (nerrors != 0) - { - arg_print_errors(stderr, queryImageCmdArgs.end, argv[0]); - return 1; - } - ESP_LOGI(TAG, "ipAddr:%s nodeId:%x", queryImageCmdArgs.ipAddr->sval[0], queryImageCmdArgs.nodeId->ival[0]); +CmdArgs applyUpdateCmdArgs; - /* Start one shot timer with 1 second timeout to send ApplyUpdateRequest command */ - chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(1 * 1000), QueryImageTimerHandler, nullptr); - return 0; -} +OTARequestor gRequestorCore; +OTARequestorDriverImpl gRequestorUser; +BDXDownloader gDownloader; +OTAImageProcessorImpl gImageProcessor; +} // namespace int ESPApplyUpdateCmdHandler(int argc, char ** argv) { - int nerrors = arg_parse(argc, argv, (void **) &applyUpdateCmdArgs); - if (nerrors != 0) - { - arg_print_errors(stderr, applyUpdateCmdArgs.end, argv[0]); - return 1; - } - ESP_LOGI(TAG, "ipAddr:%s nodeId:%x", applyUpdateCmdArgs.ipAddr->sval[0], applyUpdateCmdArgs.nodeId->ival[0]); - - /* Start one shot timer with 1 second timeout to Query for OTA image */ - chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(1 * 1000), ApplyUpdateTimerHandler, nullptr); + gRequestorCore.ApplyUpdate(); + ESP_LOGI(TAG, "Apply the Update"); return 0; } @@ -118,25 +89,14 @@ void ESPInitConsole(void) esp_console_register_help_command(); - esp_console_cmd_t queryImageCommand, applyUpdateCommand; - memset(&queryImageCommand, 0, sizeof(queryImageCommand)); + esp_console_cmd_t applyUpdateCommand; memset(&applyUpdateCommand, 0, sizeof(applyUpdateCommand)); - queryImageCmdArgs.ipAddr = arg_str0(NULL, NULL, "", "OTA Provider IP Address"); - queryImageCmdArgs.nodeId = arg_int0(NULL, NULL, "", "OTA Provider Node ID in decimal"); - queryImageCmdArgs.end = arg_end(1); - - queryImageCommand.command = "QueryImage", queryImageCommand.help = "Query for OTA image", - queryImageCommand.func = &ESPQueryImageCmdHandler, queryImageCommand.argtable = &queryImageCmdArgs; - - applyUpdateCmdArgs.ipAddr = arg_str0(NULL, NULL, "", "OTA Provider IP Address"); - applyUpdateCmdArgs.nodeId = arg_int0(NULL, NULL, "", "OTA Provider Node ID in decimal"); - applyUpdateCmdArgs.end = arg_end(1); + applyUpdateCmdArgs.end = arg_end(1); applyUpdateCommand.command = "ApplyUpdateRequest", applyUpdateCommand.help = "Request to OTA update image", applyUpdateCommand.func = &ESPApplyUpdateCmdHandler, applyUpdateCommand.argtable = &applyUpdateCmdArgs; - esp_console_cmd_register(&queryImageCommand); esp_console_cmd_register(&applyUpdateCommand); esp_console_new_repl_uart(&uartConfig, &replConfig, &repl); @@ -181,15 +141,14 @@ extern "C" void app_main() SetDeviceAttestationCredentialsProvider(Examples::GetExampleDACProvider()); ESPInitConsole(); -} + SetRequestorInstance(&gRequestorCore); -// TODO: We should use the function definition in /src/app/clusters/ota-requestor/ClusterInterface.cpp -// Temporarily add this function. + Server * server = &(Server::GetInstance()); + gRequestorCore.SetServerInstance(server); + gRequestorCore.SetOtaRequestorDriver(&gRequestorUser); -bool emberAfOtaSoftwareUpdateRequestorClusterAnnounceOtaProviderCallback( - chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath, - const chip::app::Clusters::OtaSoftwareUpdateRequestor::Commands::AnnounceOtaProvider::DecodableType & commandData) -{ - emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS); - return true; + gImageProcessor.SetOTADownloader(&gDownloader); + gDownloader.SetImageProcessorDelegate(&gImageProcessor); + + gRequestorCore.SetBDXDownloader(&gDownloader); } diff --git a/examples/ota-requestor-app/esp32/sdkconfig.defaults b/examples/ota-requestor-app/esp32/sdkconfig.defaults index aa3e6cb62047a6..ac8d7d38f4e065 100644 --- a/examples/ota-requestor-app/esp32/sdkconfig.defaults +++ b/examples/ota-requestor-app/esp32/sdkconfig.defaults @@ -52,3 +52,6 @@ CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096 # Serial Flasher config CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y CONFIG_ESPTOOLPY_FLASHSIZE="4MB" + +# Enable OTA Requestor +CONFIG_ENABLE_OTA_REQUESTOR=y diff --git a/examples/ota-requestor-app/linux/BUILD.gn b/examples/ota-requestor-app/linux/BUILD.gn index 2fa7cad7391c49..2d698377703640 100644 --- a/examples/ota-requestor-app/linux/BUILD.gn +++ b/examples/ota-requestor-app/linux/BUILD.gn @@ -16,11 +16,7 @@ import("//build_overrides/build.gni") import("//build_overrides/chip.gni") executable("chip-ota-requestor-app") { - sources = [ - "LinuxOTAImageProcessor.cpp", - "LinuxOTARequestorDriver.cpp", - "main.cpp", - ] + sources = [ "main.cpp" ] deps = [ "${chip_root}/examples/ota-requestor-app/ota-requestor-common", diff --git a/examples/ota-requestor-app/linux/args.gni b/examples/ota-requestor-app/linux/args.gni index a6463ca2c05fae..bbf4dd22e611c7 100644 --- a/examples/ota-requestor-app/linux/args.gni +++ b/examples/ota-requestor-app/linux/args.gni @@ -15,3 +15,7 @@ import("//build_overrides/chip.gni") import("${chip_root}/config/standalone/args.gni") + +declare_args() { + chip_enable_ota_requestor = true +} diff --git a/examples/ota-requestor-app/linux/main.cpp b/examples/ota-requestor-app/linux/main.cpp index 3c7181ca8052a6..7131edb35f96dd 100644 --- a/examples/ota-requestor-app/linux/main.cpp +++ b/examples/ota-requestor-app/linux/main.cpp @@ -22,10 +22,10 @@ #include #include -#include "LinuxOTAImageProcessor.h" -#include "LinuxOTARequestorDriver.h" #include "app/clusters/ota-requestor/BDXDownloader.h" #include "app/clusters/ota-requestor/OTARequestor.h" +#include "platform/Linux/OTAImageProcessorImpl.h" +#include "platform/Linux/OTARequestorDriverImpl.h" using chip::BDXDownloader; using chip::ByteSpan; @@ -33,11 +33,11 @@ using chip::CharSpan; using chip::EndpointId; using chip::FabricIndex; using chip::GetRequestorInstance; -using chip::LinuxOTAImageProcessor; using chip::NodeId; using chip::OnDeviceConnected; using chip::OnDeviceConnectionFailure; using chip::OTADownloader; +using chip::OTAImageProcessorImpl; using chip::OTAImageProcessorParams; using chip::OTARequestor; using chip::PeerId; @@ -52,9 +52,9 @@ using namespace chip::Messaging; using namespace chip::app::Clusters::OtaSoftwareUpdateProvider::Commands; OTARequestor gRequestorCore; -LinuxOTARequestorDriver gRequestorUser; +OTARequestorDriverImpl gRequestorUser; BDXDownloader gDownloader; -LinuxOTAImageProcessor gImageProcessor; +OTAImageProcessorImpl gImageProcessor; bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue); void OnStartDelayTimerHandler(Layer * systemLayer, void * appState); diff --git a/src/lib/shell/commands/BUILD.gn b/src/lib/shell/commands/BUILD.gn index d669f6bf85427c..3ae6b5b7626650 100644 --- a/src/lib/shell/commands/BUILD.gn +++ b/src/lib/shell/commands/BUILD.gn @@ -51,7 +51,9 @@ source_set("commands") { sources += [ "Dns.cpp" ] } - if (chip_enable_ota_requestor && chip_device_platform != "none") { + if (chip_enable_ota_requestor && chip_device_platform != "none" && + chip_device_platform != "linux" && chip_device_platform != "darwin") { + #TODO: the ota commands in shell should use the interfaces in /src/app/clusters/ota-requestor sources += [ "Ota.cpp" ] configs += [ "${chip_root}/src/controller:config" ] } diff --git a/src/platform/Darwin/BUILD.gn b/src/platform/Darwin/BUILD.gn index 49286449375002..7b31a881b60172 100644 --- a/src/platform/Darwin/BUILD.gn +++ b/src/platform/Darwin/BUILD.gn @@ -76,6 +76,16 @@ static_library("Darwin") { public_configs = [ ":darwin_config" ] + if (chip_enable_ota_requestor) { + sources += [ + # using the implements from Linux platform + "../Linux/OTAImageProcessorImpl.cpp", + "../Linux/OTAImageProcessorImpl.h", + "../Linux/OTARequestorDriverImpl.cpp", + "../Linux/OTARequestorDriverImpl.h", + ] + } + if (chip_enable_ble) { sources += [ "BleApplicationDelegate.h", diff --git a/src/platform/ESP32/BUILD.gn b/src/platform/ESP32/BUILD.gn index 8173f9bddd80b6..e06792500a7de4 100644 --- a/src/platform/ESP32/BUILD.gn +++ b/src/platform/ESP32/BUILD.gn @@ -54,6 +54,14 @@ static_library("ESP32") { "${chip_root}/src/crypto", "${chip_root}/src/platform:platform_base", ] + if (chip_enable_ota_requestor) { + sources += [ + "OTAImageProcessorImpl.cpp", + "OTAImageProcessorImpl.h", + "OTARequestorDriverImpl.cpp", + "OTARequestorDriverImpl.h", + ] + } if (chip_enable_wifi) { sources += [ diff --git a/src/platform/ESP32/OTAImageProcessorImpl.cpp b/src/platform/ESP32/OTAImageProcessorImpl.cpp new file mode 100644 index 00000000000000..67d873b2abc569 --- /dev/null +++ b/src/platform/ESP32/OTAImageProcessorImpl.cpp @@ -0,0 +1,211 @@ +/* + * + * 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 +#include + +#include "OTAImageProcessorImpl.h" +#include "esp_err.h" +#include "esp_log.h" +#include "esp_ota_ops.h" +#include "esp_system.h" +#include "lib/core/CHIPError.h" + +#define TAG "OTAImageProcessor" +using namespace ::chip::DeviceLayer::Internal; + +namespace chip { + +CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandlePrepareDownload, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Finalize() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Apply() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleApply, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::Abort() +{ + DeviceLayer::PlatformMgr().ScheduleWork(HandleAbort, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block) +{ + CHIP_ERROR err = SetBlock(block); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Cannot set block data: %" CHIP_ERROR_FORMAT, err.Format()); + return err; + } + DeviceLayer::PlatformMgr().ScheduleWork(HandleProcessBlock, reinterpret_cast(this)); + return CHIP_NO_ERROR; +} + +void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + else if (imageProcessor->mDownloader == nullptr) + { + ChipLogError(SoftwareUpdate, "mDownloader is null"); + return; + } + imageProcessor->mOTAUpdatePartition = esp_ota_get_next_update_partition(NULL); + if (imageProcessor->mOTAUpdatePartition == NULL) + { + ChipLogError(SoftwareUpdate, "OTA partition not found"); + return; + } + esp_err_t err = + esp_ota_begin(imageProcessor->mOTAUpdatePartition, OTA_WITH_SEQUENTIAL_WRITES, &(imageProcessor->mOTAUpdateHandle)); + if (err != ESP_OK) + { + imageProcessor->mDownloader->OnPreparedForDownload(ESP32Utils::MapError(err)); + return; + } + imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); +} + +void OTAImageProcessorImpl::HandleFinalize(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + esp_err_t err = esp_ota_end(imageProcessor->mOTAUpdateHandle); + if (err != ESP_OK) + { + if (err == ESP_ERR_OTA_VALIDATE_FAILED) + { + ESP_LOGE(TAG, "Image validation failed, image is corrupted"); + } + else + { + ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err)); + } + return; + } + imageProcessor->ReleaseBlock(); + ChipLogProgress(SoftwareUpdate, "OTA image downloaded to offset 0x%x", imageProcessor->mOTAUpdatePartition->address); +} + +void OTAImageProcessorImpl::HandleAbort(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + if (esp_ota_abort(imageProcessor->mOTAUpdateHandle) != ESP_OK) + { + ESP_LOGE(TAG, "ESP OTA abort failed"); + } + imageProcessor->ReleaseBlock(); +} + +void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + if (imageProcessor == nullptr) + { + ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); + return; + } + else if (imageProcessor->mDownloader == nullptr) + { + ChipLogError(SoftwareUpdate, "mDownloader is null"); + return; + } + esp_err_t err = esp_ota_write(imageProcessor->mOTAUpdateHandle, imageProcessor->mBlock.data(), imageProcessor->mBlock.size()); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "esp_ota_write failed (%s)", esp_err_to_name(err)); + imageProcessor->mDownloader->EndDownload(CHIP_ERROR_WRITE_FAILED); + } + imageProcessor->mParams.downloadedBytes += imageProcessor->mBlock.size(); + imageProcessor->mDownloader->FetchNextData(); +} + +void OTAImageProcessorImpl::HandleApply(intptr_t context) +{ + auto * imageProcessor = reinterpret_cast(context); + esp_err_t err = esp_ota_set_boot_partition(imageProcessor->mOTAUpdatePartition); + if (err != ESP_OK) + { + ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err)); + return; + } + ESP_LOGI(TAG, "Applying, Boot partition set offset:0x%x", imageProcessor->mOTAUpdatePartition->address); +} + +CHIP_ERROR OTAImageProcessorImpl::SetBlock(ByteSpan & block) +{ + if (!IsSpanUsable(block)) + { + ReleaseBlock(); + return CHIP_NO_ERROR; + } + if (mBlock.size() < block.size()) + { + if (!mBlock.empty()) + { + ReleaseBlock(); + } + uint8_t * mBlock_ptr = static_cast(chip::Platform::MemoryAlloc(block.size())); + if (mBlock_ptr == nullptr) + { + return CHIP_ERROR_NO_MEMORY; + } + mBlock = MutableByteSpan(mBlock_ptr, block.size()); + } + 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 OTAImageProcessorImpl::ReleaseBlock() +{ + if (mBlock.data() != nullptr) + { + chip::Platform::MemoryFree(mBlock.data()); + } + mBlock = MutableByteSpan(); + return CHIP_NO_ERROR; +} +} // namespace chip diff --git a/src/platform/ESP32/OTAImageProcessorImpl.h b/src/platform/ESP32/OTAImageProcessorImpl.h new file mode 100644 index 00000000000000..f8530606229645 --- /dev/null +++ b/src/platform/ESP32/OTAImageProcessorImpl.h @@ -0,0 +1,54 @@ +/* + * + * 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. + */ + +#pragma once + +#include "esp_ota_ops.h" +#include +#include +#include + +namespace chip { + +class OTAImageProcessorImpl : public OTAImageProcessorInterface +{ +public: + //////////// OTAImageProcessorInterface Implementation /////////////// + CHIP_ERROR PrepareDownload() override; + CHIP_ERROR Finalize() override; + CHIP_ERROR Apply() override; + CHIP_ERROR Abort() override; + CHIP_ERROR ProcessBlock(ByteSpan & block) override; + void SetOTADownloader(OTADownloader * downloader) { mDownloader = downloader; }; + +private: + static void HandlePrepareDownload(intptr_t context); + static void HandleFinalize(intptr_t context); + static void HandleAbort(intptr_t context); + static void HandleProcessBlock(intptr_t context); + static void HandleApply(intptr_t context); + + CHIP_ERROR SetBlock(ByteSpan & block); + CHIP_ERROR ReleaseBlock(); + + OTADownloader * mDownloader = nullptr; + MutableByteSpan mBlock; + const esp_partition_t * mOTAUpdatePartition = nullptr; + esp_ota_handle_t mOTAUpdateHandle; +}; + +} // namespace chip diff --git a/src/platform/ESP32/OTARequestorDriverImpl.cpp b/src/platform/ESP32/OTARequestorDriverImpl.cpp new file mode 100644 index 00000000000000..0d12b195284e31 --- /dev/null +++ b/src/platform/ESP32/OTARequestorDriverImpl.cpp @@ -0,0 +1,40 @@ +/* + * + * 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 "OTARequestorDriverImpl.h" +#include "esp_log.h" + +#define TAG "OTARequestorDriver" + +namespace chip { + +bool OTARequestorDriverImpl::CheckImageDownloadAllowed() +{ + return true; +} + +void OTARequestorDriverImpl::ImageDownloadComplete() +{ + ESP_LOGI(TAG, "Image download complete"); +} + +UserConsentAction OTARequestorDriverImpl::RequestUserConsent() +{ + return ImmediateYes; +} + +} // namespace chip diff --git a/examples/ota-requestor-app/esp32/main/include/OTARequesterImpl.h b/src/platform/ESP32/OTARequestorDriverImpl.h similarity index 61% rename from examples/ota-requestor-app/esp32/main/include/OTARequesterImpl.h rename to src/platform/ESP32/OTARequestorDriverImpl.h index 01fb7c701dba0e..848f6d14ae0620 100644 --- a/examples/ota-requestor-app/esp32/main/include/OTARequesterImpl.h +++ b/src/platform/ESP32/OTARequestorDriverImpl.h @@ -14,23 +14,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#pragma once - -class OTARequesterImpl -{ -public: - static OTARequesterImpl & GetInstance(void) - { - static OTARequesterImpl instance; - return instance; - } - void SendQueryImageCommand(const char * ipAddress, uint32_t nodeId); +#pragma once - void SendApplyUpdateRequestCommand(const char * ipAddress, uint32_t nodeId); +#include - void SendNotifyUpdateAppliedCommand(const char * ipAddress, uint32_t nodeId); +namespace chip { -private: - OTARequesterImpl() {} +class OTARequestorDriverImpl : public OTARequestorDriver +{ +public: + bool CheckImageDownloadAllowed() override; + void ImageDownloadComplete() override; + UserConsentAction RequestUserConsent() override; }; +} // namespace chip diff --git a/src/platform/Linux/BUILD.gn b/src/platform/Linux/BUILD.gn index 6c9bcb122dc072..8803940a7b5d21 100644 --- a/src/platform/Linux/BUILD.gn +++ b/src/platform/Linux/BUILD.gn @@ -98,6 +98,15 @@ static_library("Linux") { public_configs += [ ":avahi_client_config" ] } + if (chip_enable_ota_requestor) { + sources += [ + "OTAImageProcessorImpl.cpp", + "OTAImageProcessorImpl.h", + "OTARequestorDriverImpl.cpp", + "OTARequestorDriverImpl.h", + ] + } + if (chip_enable_openthread) { sources += [ "GlibTypeDeleter.h", diff --git a/examples/ota-requestor-app/linux/LinuxOTAImageProcessor.cpp b/src/platform/Linux/OTAImageProcessorImpl.cpp similarity index 83% rename from examples/ota-requestor-app/linux/LinuxOTAImageProcessor.cpp rename to src/platform/Linux/OTAImageProcessorImpl.cpp index 0465a271409930..14a061484b680e 100644 --- a/examples/ota-requestor-app/linux/LinuxOTAImageProcessor.cpp +++ b/src/platform/Linux/OTAImageProcessorImpl.cpp @@ -18,11 +18,11 @@ #include -#include "LinuxOTAImageProcessor.h" +#include "OTAImageProcessorImpl.h" namespace chip { -CHIP_ERROR LinuxOTAImageProcessor::PrepareDownload() +CHIP_ERROR OTAImageProcessorImpl::PrepareDownload() { if (mParams.imageFile.empty()) { @@ -34,18 +34,18 @@ CHIP_ERROR LinuxOTAImageProcessor::PrepareDownload() return CHIP_NO_ERROR; } -CHIP_ERROR LinuxOTAImageProcessor::Finalize() +CHIP_ERROR OTAImageProcessorImpl::Finalize() { DeviceLayer::PlatformMgr().ScheduleWork(HandleFinalize, reinterpret_cast(this)); return CHIP_NO_ERROR; } -CHIP_ERROR LinuxOTAImageProcessor::Apply() +CHIP_ERROR OTAImageProcessorImpl::Apply() { return CHIP_NO_ERROR; } -CHIP_ERROR LinuxOTAImageProcessor::Abort() +CHIP_ERROR OTAImageProcessorImpl::Abort() { if (mParams.imageFile.empty()) { @@ -57,7 +57,7 @@ CHIP_ERROR LinuxOTAImageProcessor::Abort() return CHIP_NO_ERROR; } -CHIP_ERROR LinuxOTAImageProcessor::ProcessBlock(ByteSpan & block) +CHIP_ERROR OTAImageProcessorImpl::ProcessBlock(ByteSpan & block) { if (!mOfs.is_open() || !mOfs.good()) { @@ -80,9 +80,9 @@ CHIP_ERROR LinuxOTAImageProcessor::ProcessBlock(ByteSpan & block) return CHIP_NO_ERROR; } -void LinuxOTAImageProcessor::HandlePrepareDownload(intptr_t context) +void OTAImageProcessorImpl::HandlePrepareDownload(intptr_t context) { - auto * imageProcessor = reinterpret_cast(context); + auto * imageProcessor = reinterpret_cast(context); if (imageProcessor == nullptr) { ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); @@ -107,9 +107,9 @@ void LinuxOTAImageProcessor::HandlePrepareDownload(intptr_t context) imageProcessor->mDownloader->OnPreparedForDownload(CHIP_NO_ERROR); } -void LinuxOTAImageProcessor::HandleFinalize(intptr_t context) +void OTAImageProcessorImpl::HandleFinalize(intptr_t context) { - auto * imageProcessor = reinterpret_cast(context); + auto * imageProcessor = reinterpret_cast(context); if (imageProcessor == nullptr) { return; @@ -121,9 +121,9 @@ void LinuxOTAImageProcessor::HandleFinalize(intptr_t context) ChipLogProgress(SoftwareUpdate, "OTA image downloaded to %s", imageProcessor->mParams.imageFile.data()); } -void LinuxOTAImageProcessor::HandleAbort(intptr_t context) +void OTAImageProcessorImpl::HandleAbort(intptr_t context) { - auto * imageProcessor = reinterpret_cast(context); + auto * imageProcessor = reinterpret_cast(context); if (imageProcessor == nullptr) { return; @@ -134,9 +134,9 @@ void LinuxOTAImageProcessor::HandleAbort(intptr_t context) imageProcessor->ReleaseBlock(); } -void LinuxOTAImageProcessor::HandleProcessBlock(intptr_t context) +void OTAImageProcessorImpl::HandleProcessBlock(intptr_t context) { - auto * imageProcessor = reinterpret_cast(context); + auto * imageProcessor = reinterpret_cast(context); if (imageProcessor == nullptr) { ChipLogError(SoftwareUpdate, "ImageProcessor context is null"); @@ -161,7 +161,7 @@ void LinuxOTAImageProcessor::HandleProcessBlock(intptr_t context) imageProcessor->mDownloader->FetchNextData(); } -CHIP_ERROR LinuxOTAImageProcessor::SetBlock(ByteSpan & block) +CHIP_ERROR OTAImageProcessorImpl::SetBlock(ByteSpan & block) { if ((block.data() == nullptr) || block.empty()) { @@ -189,7 +189,7 @@ CHIP_ERROR LinuxOTAImageProcessor::SetBlock(ByteSpan & block) return CHIP_NO_ERROR; } -CHIP_ERROR LinuxOTAImageProcessor::ReleaseBlock() +CHIP_ERROR OTAImageProcessorImpl::ReleaseBlock() { if (mBlock.data() != nullptr) { diff --git a/examples/ota-requestor-app/linux/LinuxOTAImageProcessor.h b/src/platform/Linux/OTAImageProcessorImpl.h similarity index 96% rename from examples/ota-requestor-app/linux/LinuxOTAImageProcessor.h rename to src/platform/Linux/OTAImageProcessorImpl.h index ed66a4c091700f..77a13ca36e890c 100644 --- a/examples/ota-requestor-app/linux/LinuxOTAImageProcessor.h +++ b/src/platform/Linux/OTAImageProcessorImpl.h @@ -26,7 +26,7 @@ namespace chip { -class LinuxOTAImageProcessor : public OTAImageProcessorInterface +class OTAImageProcessorImpl : public OTAImageProcessorInterface { public: //////////// OTAImageProcessorInterface Implementation /////////////// diff --git a/examples/ota-requestor-app/linux/LinuxOTARequestorDriver.cpp b/src/platform/Linux/OTARequestorDriverImpl.cpp similarity index 84% rename from examples/ota-requestor-app/linux/LinuxOTARequestorDriver.cpp rename to src/platform/Linux/OTARequestorDriverImpl.cpp index ad3d0c814525eb..5fcd1f68ab4438 100644 --- a/examples/ota-requestor-app/linux/LinuxOTARequestorDriver.cpp +++ b/src/platform/Linux/OTARequestorDriverImpl.cpp @@ -20,22 +20,22 @@ * interface class */ -#include "LinuxOTARequestorDriver.h" +#include "OTARequestorDriverImpl.h" using namespace chip; // A call into the application logic to give it a chance to allow or stop the Requestor // from proceeding with actual image download. Returning TRUE will allow the download // to proceed, returning FALSE will abort the download process. -bool LinuxOTARequestorDriver::CheckImageDownloadAllowed() +bool OTARequestorDriverImpl::CheckImageDownloadAllowed() { return true; } // Notify the application that the download is complete and the image can be applied -void LinuxOTARequestorDriver::ImageDownloadComplete() {} +void OTARequestorDriverImpl::ImageDownloadComplete() {} -UserConsentAction LinuxOTARequestorDriver::RequestUserConsent() +UserConsentAction OTARequestorDriverImpl::RequestUserConsent() { return ImmediateYes; } diff --git a/examples/ota-requestor-app/linux/LinuxOTARequestorDriver.h b/src/platform/Linux/OTARequestorDriverImpl.h similarity index 96% rename from examples/ota-requestor-app/linux/LinuxOTARequestorDriver.h rename to src/platform/Linux/OTARequestorDriverImpl.h index f039d32c1ae980..43664db1b12558 100644 --- a/examples/ota-requestor-app/linux/LinuxOTARequestorDriver.h +++ b/src/platform/Linux/OTARequestorDriverImpl.h @@ -23,7 +23,7 @@ namespace chip { -class LinuxOTARequestorDriver : public OTARequestorDriver +class OTARequestorDriverImpl : public OTARequestorDriver { // Virtual functions from OTARequestorDriver -- start