From 154251405cb427014eda8fd75400c6843d853186 Mon Sep 17 00:00:00 2001 From: Carol Yang Date: Fri, 8 Jul 2022 17:24:16 -0700 Subject: [PATCH] [Darwin] Add OTA Provider Delegate Bridge implementation (#20516) --- .../CHIP/MTROTAProviderDelegateBridge.h | 16 ++ .../CHIP/MTROTAProviderDelegateBridge.mm | 236 ++++++++++++++++++ .../Matter.xcodeproj/project.pbxproj | 6 +- 3 files changed, 257 insertions(+), 1 deletion(-) create mode 100644 src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm diff --git a/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.h b/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.h index 4b36d91f0eb804..8f01a6d253cdf0 100644 --- a/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.h +++ b/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.h @@ -42,6 +42,22 @@ class MTROTAProviderDelegateBridge : public chip::app::Clusters::OTAProviderDele const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::DecodableType & commandData) override; private: + void ConvertToQueryImageParams( + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::DecodableType & commandData, + MTROtaSoftwareUpdateProviderClusterQueryImageParams * commandParams); + void ConvertFromQueryImageResponseParms( + const MTROtaSoftwareUpdateProviderClusterQueryImageResponseParams * responseParams, + chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImageResponse::Type & response); + void ConvertToApplyUpdateRequestParams( + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::DecodableType & commandData, + MTROtaSoftwareUpdateProviderClusterApplyUpdateRequestParams * commandParams); + void ConvertFromApplyUpdateRequestResponseParms( + const MTROtaSoftwareUpdateProviderClusterApplyUpdateResponseParams * responseParams, + chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateResponse::Type & response); + void ConvertToNotifyUpdateAppliedParams( + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::DecodableType & commandData, + MTROtaSoftwareUpdateProviderClusterNotifyUpdateAppliedParams * commandParams); + _Nullable id mDelegate; _Nullable dispatch_queue_t mQueue; }; diff --git a/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm b/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm new file mode 100644 index 00000000000000..b5675ca4f79bbe --- /dev/null +++ b/src/darwin/Framework/CHIP/MTROTAProviderDelegateBridge.mm @@ -0,0 +1,236 @@ +/** + * + * Copyright (c) 2022 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. + */ + +#import "MTROTAProviderDelegateBridge.h" + +#include + +static NSInteger const kOtaProviderEndpoint = 0; + +MTROTAProviderDelegateBridge::MTROTAProviderDelegateBridge(void) + : mDelegate(nil) +{ +} + +MTROTAProviderDelegateBridge::~MTROTAProviderDelegateBridge(void) {} + +void MTROTAProviderDelegateBridge::setDelegate(id delegate, dispatch_queue_t queue) +{ + if (delegate && queue) { + mDelegate = delegate; + mQueue = queue; + } else { + mDelegate = nil; + mQueue = nil; + } + + chip::app::Clusters::OTAProvider::SetDelegate(kOtaProviderEndpoint, this); +} + +void MTROTAProviderDelegateBridge::HandleQueryImage(chip::app::CommandHandler * commandObj, + const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::DecodableType & commandData) +{ + // Make sure to hold on to the command handler and command path to be used in the completion block + __block chip::app::CommandHandler::Handle handle(commandObj); + __block chip::app::ConcreteCommandPath cachedCommandPath( + commandPath.mEndpointId, commandPath.mClusterId, commandPath.mCommandId); + + id strongDelegate = mDelegate; + if ([strongDelegate respondsToSelector:@selector(handleQueryImage:completionHandler:)]) { + if (strongDelegate && mQueue) { + auto * commandParams = [[MTROtaSoftwareUpdateProviderClusterQueryImageParams alloc] init]; + ConvertToQueryImageParams(commandData, commandParams); + + dispatch_async(mQueue, ^{ + [strongDelegate handleQueryImage:commandParams + completionHandler:^(MTROtaSoftwareUpdateProviderClusterQueryImageResponseParams * _Nullable data, + NSError * _Nullable error) { + chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImageResponse::Type response; + ConvertFromQueryImageResponseParms(data, response); + + chip::app::CommandHandler * handler = handle.Get(); + if (handler) { + handler->AddResponse(cachedCommandPath, response); + handle.Release(); + } + }]; + }); + } + } +} + +void MTROTAProviderDelegateBridge::HandleApplyUpdateRequest(chip::app::CommandHandler * commandObj, + const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::DecodableType & commandData) +{ + // Make sure to hold on to the command handler and command path to be used in the completion block + __block chip::app::CommandHandler::Handle handle(commandObj); + __block chip::app::ConcreteCommandPath cachedCommandPath( + commandPath.mEndpointId, commandPath.mClusterId, commandPath.mCommandId); + + id strongDelegate = mDelegate; + if ([strongDelegate respondsToSelector:@selector(handleApplyUpdateRequest:completionHandler:)]) { + if (strongDelegate && mQueue) { + auto * commandParams = [[MTROtaSoftwareUpdateProviderClusterApplyUpdateRequestParams alloc] init]; + ConvertToApplyUpdateRequestParams(commandData, commandParams); + + dispatch_async(mQueue, ^{ + [strongDelegate + handleApplyUpdateRequest:commandParams + completionHandler:^(MTROtaSoftwareUpdateProviderClusterApplyUpdateResponseParams * _Nullable data, + NSError * _Nullable error) { + chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateResponse::Type response; + ConvertFromApplyUpdateRequestResponseParms(data, response); + + chip::app::CommandHandler * handler = handle.Get(); + if (handler) { + handler->AddResponse(cachedCommandPath, response); + handle.Release(); + } + }]; + }); + } + } +} + +void MTROTAProviderDelegateBridge::HandleNotifyUpdateApplied(chip::app::CommandHandler * commandObj, + const chip::app::ConcreteCommandPath & commandPath, + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::DecodableType & commandData) +{ + // Make sure to hold on to the command handler and command path to be used in the completion block + __block chip::app::CommandHandler::Handle handle(commandObj); + __block chip::app::ConcreteCommandPath cachedCommandPath( + commandPath.mEndpointId, commandPath.mClusterId, commandPath.mCommandId); + + id strongDelegate = mDelegate; + if ([strongDelegate respondsToSelector:@selector(handleNotifyUpdateApplied:completionHandler:)]) { + if (strongDelegate && mQueue) { + auto * commandParams = [[MTROtaSoftwareUpdateProviderClusterNotifyUpdateAppliedParams alloc] init]; + ConvertToNotifyUpdateAppliedParams(commandData, commandParams); + + dispatch_async(mQueue, ^{ + [strongDelegate + handleNotifyUpdateApplied:commandParams + completionHandler:^(NSError * _Nullable error) { + chip::app::CommandHandler * handler = handle.Get(); + if (handler) { + handler->AddStatus(cachedCommandPath, chip::Protocols::InteractionModel::Status::Success); + handle.Release(); + } + }]; + }); + } + } +} + +void MTROTAProviderDelegateBridge::ConvertToQueryImageParams( + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::DecodableType & commandData, + MTROtaSoftwareUpdateProviderClusterQueryImageParams * commandParams) +{ + commandParams.vendorId = [NSNumber numberWithInt:commandData.vendorId]; + commandParams.productId = [NSNumber numberWithInt:commandData.productId]; + commandParams.softwareVersion = [NSNumber numberWithInt:commandData.softwareVersion]; + auto iterator = commandData.protocolsSupported.begin(); + NSMutableArray * protocolsSupported = [[NSMutableArray alloc] init]; + while (iterator.Next()) { + chip::app::Clusters::OtaSoftwareUpdateProvider::OTADownloadProtocol protocol = iterator.GetValue(); + [protocolsSupported addObject:[NSNumber numberWithInt:static_cast(protocol)]]; + } + commandParams.protocolsSupported = [protocolsSupported copy]; + + if (commandData.hardwareVersion.HasValue()) { + commandParams.hardwareVersion = [NSNumber numberWithInt:commandData.hardwareVersion.Value()]; + } + + if (commandData.location.HasValue()) { + commandParams.location = [NSString stringWithUTF8String:commandData.location.Value().data()]; + } + + if (commandData.requestorCanConsent.HasValue()) { + commandParams.requestorCanConsent = [NSNumber numberWithBool:commandData.requestorCanConsent.Value()]; + } + + if (commandData.metadataForProvider.HasValue()) { + commandParams.metadataForProvider = [NSData dataWithBytes:commandData.metadataForProvider.Value().data() + length:commandData.metadataForProvider.Value().size()]; + } +} + +void MTROTAProviderDelegateBridge::ConvertFromQueryImageResponseParms( + const MTROtaSoftwareUpdateProviderClusterQueryImageResponseParams * responseParams, + chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImageResponse::Type & response) +{ + response.status = static_cast([responseParams.status intValue]); + + if (responseParams.delayedActionTime) { + response.delayedActionTime.SetValue([responseParams.delayedActionTime intValue]); + } + + if (responseParams.imageURI) { + response.imageURI.SetValue(chip::CharSpan([responseParams.imageURI UTF8String], responseParams.imageURI.length)); + } + + if (responseParams.softwareVersion) { + response.softwareVersion.SetValue([responseParams.softwareVersion intValue]); + } + + if (responseParams.softwareVersionString) { + response.softwareVersionString.SetValue( + chip::CharSpan([responseParams.softwareVersionString UTF8String], responseParams.softwareVersionString.length)); + } + + if (responseParams.updateToken) { + UInt8 * updateTokenBytes = (UInt8 *) responseParams.updateToken.bytes; + response.updateToken.SetValue(chip::ByteSpan(updateTokenBytes, responseParams.updateToken.length)); + } + + if (responseParams.userConsentNeeded) { + response.userConsentNeeded.SetValue([responseParams.userConsentNeeded boolValue]); + } + + if (responseParams.metadataForRequestor) { + UInt8 * metadataForRequestorBytes = (UInt8 *) responseParams.metadataForRequestor.bytes; + response.metadataForRequestor.SetValue( + chip::ByteSpan(metadataForRequestorBytes, responseParams.metadataForRequestor.length)); + } +} + +void MTROTAProviderDelegateBridge::ConvertToApplyUpdateRequestParams( + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateRequest::DecodableType & commandData, + MTROtaSoftwareUpdateProviderClusterApplyUpdateRequestParams * commandParams) +{ + commandParams.updateToken = [NSData dataWithBytes:commandData.updateToken.data() length:commandData.updateToken.size()]; + commandParams.newVersion = [NSNumber numberWithInt:commandData.newVersion]; +} + +void MTROTAProviderDelegateBridge::ConvertFromApplyUpdateRequestResponseParms( + const MTROtaSoftwareUpdateProviderClusterApplyUpdateResponseParams * responseParams, + chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::ApplyUpdateResponse::Type & response) +{ + response.action + = static_cast([responseParams.action intValue]); + response.delayedActionTime = [responseParams.delayedActionTime intValue]; +} + +void MTROTAProviderDelegateBridge::ConvertToNotifyUpdateAppliedParams( + const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::NotifyUpdateApplied::DecodableType & commandData, + MTROtaSoftwareUpdateProviderClusterNotifyUpdateAppliedParams * commandParams) +{ + commandParams.updateToken = [NSData dataWithBytes:commandData.updateToken.data() length:commandData.updateToken.size()]; + commandParams.softwareVersion = [NSNumber numberWithInt:commandData.softwareVersion]; +} diff --git a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj index 688e7fa03bb1fc..35cbffdeba16c4 100644 --- a/src/darwin/Framework/Matter.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/Matter.xcodeproj/project.pbxproj @@ -95,6 +95,7 @@ 99D466E12798936D0089A18F /* MTRCommissioningParameters.h in Headers */ = {isa = PBXBuildFile; fileRef = 99D466E02798936D0089A18F /* MTRCommissioningParameters.h */; settings = {ATTRIBUTES = (Public, ); }; }; AF1CB86E2874B03B00865A96 /* MTROTAProviderDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1CB86D2874B03B00865A96 /* MTROTAProviderDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; }; AF1CB8702874B04C00865A96 /* MTROTAProviderDelegateBridge.h in Headers */ = {isa = PBXBuildFile; fileRef = AF1CB86F2874B04C00865A96 /* MTROTAProviderDelegateBridge.h */; }; + AF5F90FF2878D351005503FA /* MTROTAProviderDelegateBridge.mm in Sources */ = {isa = PBXBuildFile; fileRef = AF5F90FE2878D351005503FA /* MTROTAProviderDelegateBridge.mm */; }; B20252972459E34F00F97062 /* Matter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B202528D2459E34F00F97062 /* Matter.framework */; }; B289D4212639C0D300D4E314 /* MTROnboardingPayloadParser.h in Headers */ = {isa = PBXBuildFile; fileRef = B289D41F2639C0D300D4E314 /* MTROnboardingPayloadParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; B289D4222639C0D300D4E314 /* MTROnboardingPayloadParser.m in Sources */ = {isa = PBXBuildFile; fileRef = B289D4202639C0D300D4E314 /* MTROnboardingPayloadParser.m */; }; @@ -211,6 +212,7 @@ 99D466E02798936D0089A18F /* MTRCommissioningParameters.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTRCommissioningParameters.h; sourceTree = ""; }; AF1CB86D2874B03B00865A96 /* MTROTAProviderDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROTAProviderDelegate.h; sourceTree = ""; }; AF1CB86F2874B04C00865A96 /* MTROTAProviderDelegateBridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MTROTAProviderDelegateBridge.h; sourceTree = ""; }; + AF5F90FE2878D351005503FA /* MTROTAProviderDelegateBridge.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MTROTAProviderDelegateBridge.mm; sourceTree = ""; }; B202528D2459E34F00F97062 /* Matter.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Matter.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B20252912459E34F00F97062 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B20252962459E34F00F97062 /* MatterTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MatterTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -343,8 +345,9 @@ 2CB7163E252F731E0026E2BB /* MTRDevicePairingDelegate.h */, 2CB71638252E8A7B0026E2BB /* MTRDevicePairingDelegateBridge.h */, 2CB71639252E8A7B0026E2BB /* MTRDevicePairingDelegateBridge.mm */, - AF1CB86F2874B04C00865A96 /* MTROTAProviderDelegateBridge.h */, AF1CB86D2874B03B00865A96 /* MTROTAProviderDelegate.h */, + AF1CB86F2874B04C00865A96 /* MTROTAProviderDelegateBridge.h */, + AF5F90FE2878D351005503FA /* MTROTAProviderDelegateBridge.mm */, B2E0D7A8245B0B5C003C5B48 /* Matter.h */, B2E0D7AB245B0B5C003C5B48 /* MTRError_Internal.h */, 5129BCFC26A9EE3300122DDF /* MTRError.h */, @@ -610,6 +613,7 @@ 998F287126D56940001846C6 /* MTRP256KeypairBridge.mm in Sources */, 5136661428067D550025EDAE /* MTRControllerFactory.mm in Sources */, 51B22C2A2740CB47008D5055 /* MTRCommandPayloadsObjc.mm in Sources */, + AF5F90FF2878D351005503FA /* MTROTAProviderDelegateBridge.mm in Sources */, 2C5EEEF7268A85C400CAE3D3 /* MTRDeviceConnectionBridge.mm in Sources */, 51B22C262740CB32008D5055 /* MTRStructsObjc.mm in Sources */, 2C222AD1255C620600E446B9 /* MTRBaseDevice.mm in Sources */,