diff --git a/config/ios/CHIPProjectConfig.h b/config/ios/CHIPProjectConfig.h index f9be4d998c7319..6a9d7eb3213836 100644 --- a/config/ios/CHIPProjectConfig.h +++ b/config/ios/CHIPProjectConfig.h @@ -40,6 +40,8 @@ #define CHIP_CONFIG_MAX_SOFTWARE_VERSION_LENGTH 128 +#ifndef CHIP_CONFIG_KVS_PATH #define CHIP_CONFIG_KVS_PATH "chip.store" +#endif #endif /* CHIPPROJECTCONFIG_H */ diff --git a/examples/tv-casting-app/darwin/TvCasting/MatterBridge/CastingServerBridge.h b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/CastingServerBridge.h index 712128353db3cb..5e2587416e8eeb 100644 --- a/examples/tv-casting-app/darwin/TvCasting/MatterBridge/CastingServerBridge.h +++ b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/CastingServerBridge.h @@ -15,6 +15,7 @@ * limitations under the License. */ +#import "DiscoveredNodeData.h" #import #ifndef CastingServerBridge_h @@ -22,10 +23,20 @@ @interface CastingServerBridge : NSObject -+ (CastingServerBridge *)getSharedInstance; ++ (CastingServerBridge * _Nullable)getSharedInstance; -// TBD: placeholder will be replaced with true CastingServer functions -- (int)add:(int)a secondNum:(int)b; +- (void)discoverCommissioners:(dispatch_queue_t _Nonnull)clientQueue + discoveryRequestSentHandler:(nullable void (^)(bool))discoveryRequestSentHandler; + +- (void)getDiscoveredCommissioner:(int)index + clientQueue:(dispatch_queue_t _Nonnull)clientQueue + discoveredCommissionerHandler:(nullable void (^)(DiscoveredNodeData * _Nullable))discoveredCommissionerHandler; + +- (void)sendUserDirectedCommissioningRequest:(NSString * _Nonnull)commissionerIpAddress + commissionerPort:(uint16_t)commissionerPort + platformInterface:(unsigned int)platformInterface + clientQueue:(dispatch_queue_t _Nonnull)clientQueue + udcRequestSentHandler:(nullable void (^)(bool))udcRequestSentHandler; @end diff --git a/examples/tv-casting-app/darwin/TvCasting/MatterBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/CastingServerBridge.mm index 05635ac19caf26..33678347bd3ed6 100644 --- a/examples/tv-casting-app/darwin/TvCasting/MatterBridge/CastingServerBridge.mm +++ b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/CastingServerBridge.mm @@ -18,12 +18,21 @@ #import "CastingServerBridge.h" #import "CastingServer.h" +#import "DiscoveredNodeDataConverter.hpp" + #include #include +@interface CastingServerBridge () + +// queue used to serialize all work performed by the CastingServerBridge +@property (atomic, readonly) dispatch_queue_t chipWorkQueue; + +@end + @implementation CastingServerBridge -+ (CastingServerBridge *)getSharedInstance ++ (CastingServerBridge * _Nullable)getSharedInstance { static CastingServerBridge * instance = nil; static dispatch_once_t onceToken; @@ -48,15 +57,100 @@ - (instancetype)init return nil; } + // init app Server + static chip::CommonCaseDeviceServerInitParams initParams; + err = initParams.InitializeStaticResourcesBeforeServerInit(); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "InitializeStaticResourcesBeforeServerInit failed: %s", ErrorStr(err)); + return nil; + } + err = chip::Server::GetInstance().Init(initParams); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "chip::Server init failed: %s", ErrorStr(err)); + return nil; + } + + _chipWorkQueue = chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue(); + + chip::DeviceLayer::PlatformMgrImpl().StartEventLoopTask(); + CastingServer::GetInstance()->Init(); } return self; } -// TBD: placeholder will be replaced with true CastingServer functions -- (int)add:(int)a secondNum:(int)b +- (void)discoverCommissioners:(dispatch_queue_t _Nonnull)clientQueue + discoveryRequestSentHandler:(nullable void (^)(bool))discoveryRequestSentHandler { - return a + b; + ChipLogProgress(AppServer, "CastingServerBridge().discoverCommissioners() called"); + dispatch_async(_chipWorkQueue, ^{ + bool discoveryRequestStatus = true; + CHIP_ERROR err = CastingServer::GetInstance()->DiscoverCommissioners(); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "CastingServerBridge().discoverCommissioners() failed: %" CHIP_ERROR_FORMAT, err.Format()); + discoveryRequestStatus = false; + } + + dispatch_async(clientQueue, ^{ + discoveryRequestSentHandler(discoveryRequestStatus); + }); + }); +} + +- (void)getDiscoveredCommissioner:(int)index + clientQueue:(dispatch_queue_t _Nonnull)clientQueue + discoveredCommissionerHandler:(nullable void (^)(DiscoveredNodeData * _Nullable))discoveredCommissionerHandler +{ + ChipLogProgress(AppServer, "CastingServerBridge().getDiscoveredCommissioner() called"); + + dispatch_async(_chipWorkQueue, ^{ + DiscoveredNodeData * commissioner = nil; + const chip::Dnssd::DiscoveredNodeData * chipDiscoveredNodeData + = CastingServer::GetInstance()->GetDiscoveredCommissioner(index); + if (chipDiscoveredNodeData != nullptr) { + commissioner = [DiscoveredNodeDataConverter convertToObjC:chipDiscoveredNodeData]; + } + + dispatch_async(clientQueue, ^{ + discoveredCommissionerHandler(commissioner); + }); + }); } +- (void)sendUserDirectedCommissioningRequest:(NSString * _Nonnull)commissionerIpAddress + commissionerPort:(uint16_t)commissionerPort + platformInterface:(unsigned int)platformInterface + clientQueue:(dispatch_queue_t _Nonnull)clientQueue + udcRequestSentHandler:(nullable void (^)(bool))udcRequestSentHandler +{ + ChipLogProgress( + AppServer, "CastingServerBridge().sendUserDirectedCommissioningRequest() called with port %d", commissionerPort); + + dispatch_async(chip::DeviceLayer::PlatformMgrImpl().GetWorkQueue(), ^{ + bool udcRequestStatus; + chip::Inet::IPAddress commissionerAddrInet; + if (chip::Inet::IPAddress::FromString([commissionerIpAddress UTF8String], commissionerAddrInet) == false) { + ChipLogError(AppServer, "CastingServerBridge().sendUserDirectedCommissioningRequest() failed to parse IP address"); + udcRequestStatus = false; + } else { + chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId(platformInterface); + + chip::Transport::PeerAddress commissionerPeerAddress + = chip::Transport::PeerAddress::UDP(commissionerAddrInet, commissionerPort, interfaceId); + + CHIP_ERROR err = CastingServer::GetInstance()->SendUserDirectedCommissioningRequest(commissionerPeerAddress); + if (err != CHIP_NO_ERROR) { + ChipLogError(AppServer, "CastingServerBridge().sendUserDirectedCommissioningRequest() failed: %" CHIP_ERROR_FORMAT, + err.Format()); + udcRequestStatus = false; + } else { + udcRequestStatus = true; + } + } + + dispatch_async(clientQueue, ^{ + udcRequestSentHandler(udcRequestStatus); + }); + }); +} @end diff --git a/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeData.h b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeData.h new file mode 100644 index 00000000000000..24240cc4a4acda --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeData.h @@ -0,0 +1,59 @@ +/** + * + * Copyright (c) 2020-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 + +#ifndef DiscoveredNodeData_h +#define DiscoveredNodeData_h + +@interface DiscoveredNodeData : NSObject + +@property NSString * deviceName; + +@property uint16_t vendorId; + +@property uint16_t productId; + +@property uint16_t deviceType; + +@property uint16_t longDiscriminator; + +@property uint8_t commissioningMode; + +@property uint16_t pairingHint; + +@property const uint8_t * rotatingId; + +@property size_t rotatingIdLen; + +@property NSString * instanceName; + +@property uint16_t port; + +@property NSString * hostName; + +@property unsigned int platformInterface; + +@property NSMutableArray * ipAddresses; + +@property size_t numIPs; + +- (DiscoveredNodeData *)initWithDeviceName:(NSString *)deviceName vendorId:(uint16_t)vendorId productId:(uint16_t)productId; + +@end + +#endif /* DiscoveredNodeData_h */ diff --git a/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeData.mm b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeData.mm new file mode 100644 index 00000000000000..541352b3d31bf9 --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeData.mm @@ -0,0 +1,73 @@ +/** + * + * Copyright (c) 2020-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 + +#import "DiscoveredNodeData.h" +#include + +@implementation DiscoveredNodeData + +- (DiscoveredNodeData *)initWithDeviceName:(NSString *)deviceName vendorId:(uint16_t)vendorId productId:(uint16_t)productId +{ + self = [super init]; + if (self) { + _deviceName = deviceName; + _vendorId = vendorId; + _productId = productId; + } + return self; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"%@ with Product ID: %d and Vendor ID: %d", _deviceName, _productId, _vendorId]; +} + +- (BOOL)isEqualToDiscoveredNodeData:(DiscoveredNodeData *)other +{ + return [self.instanceName isEqualToString:other.instanceName]; +} + +- (BOOL)isEqual:(id)other +{ + if (other == nil) { + return NO; + } + + if (self == other) { + return YES; + } + + if (![other isKindOfClass:[DiscoveredNodeData class]]) { + return NO; + } + + return [self isEqualToDiscoveredNodeData:(DiscoveredNodeData *) other]; +} + +- (NSUInteger)hash +{ + const NSUInteger prime = 31; + NSUInteger result = 1; + + result = prime * result + [self.instanceName hash]; + + return result; +} + +@end diff --git a/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeDataConverter.hpp b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeDataConverter.hpp new file mode 100644 index 00000000000000..3833767bcae2c4 --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeDataConverter.hpp @@ -0,0 +1,32 @@ +/** + * + * Copyright (c) 2020-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 + +#import "DiscoveredNodeData.h" +#include + +#ifndef DiscoveredNodeDataConverter_h +#define DiscoveredNodeDataConverter_h + +@interface DiscoveredNodeDataConverter : NSObject + ++ (DiscoveredNodeData *)convertToObjC:(const chip::Dnssd::DiscoveredNodeData *)chipDiscoveredNodedata; + +@end + +#endif /* DiscoveredNodeDataConverter_h */ diff --git a/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeDataConverter.mm b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeDataConverter.mm new file mode 100644 index 00000000000000..2c96ca48cb95ab --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/MatterBridge/DiscoveredNodeDataConverter.mm @@ -0,0 +1,58 @@ +/** + * + * Copyright (c) 2020-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 + +#import "DiscoveredNodeDataConverter.hpp" + +@implementation DiscoveredNodeDataConverter + ++ (DiscoveredNodeData *)convertToObjC:(const chip::Dnssd::DiscoveredNodeData *)chipDiscoveredNodeData +{ + DiscoveredNodeData * objCDiscoveredNodeData = [DiscoveredNodeData new]; + + // from CommissionNodeData + objCDiscoveredNodeData.deviceType = chipDiscoveredNodeData->commissionData.deviceType; + objCDiscoveredNodeData.vendorId = chipDiscoveredNodeData->commissionData.vendorId; + objCDiscoveredNodeData.productId = chipDiscoveredNodeData->commissionData.productId; + objCDiscoveredNodeData.longDiscriminator = chipDiscoveredNodeData->commissionData.longDiscriminator; + objCDiscoveredNodeData.commissioningMode = chipDiscoveredNodeData->commissionData.commissioningMode; + objCDiscoveredNodeData.pairingHint = chipDiscoveredNodeData->commissionData.pairingHint; + objCDiscoveredNodeData.deviceName = [NSString stringWithCString:chipDiscoveredNodeData->commissionData.deviceName + encoding:NSASCIIStringEncoding]; + objCDiscoveredNodeData.rotatingIdLen = chipDiscoveredNodeData->commissionData.rotatingIdLen; + objCDiscoveredNodeData.rotatingId = chipDiscoveredNodeData->commissionData.rotatingId; + objCDiscoveredNodeData.instanceName = [NSString stringWithCString:chipDiscoveredNodeData->commissionData.instanceName + encoding:NSASCIIStringEncoding]; + + // from CommonResolutionData + objCDiscoveredNodeData.port = chipDiscoveredNodeData->resolutionData.port; + objCDiscoveredNodeData.hostName = [NSString stringWithCString:chipDiscoveredNodeData->resolutionData.hostName + encoding:NSASCIIStringEncoding]; + objCDiscoveredNodeData.platformInterface = chipDiscoveredNodeData->resolutionData.interfaceId.GetPlatformInterface(); + objCDiscoveredNodeData.numIPs = chipDiscoveredNodeData->resolutionData.numIPs; + if (chipDiscoveredNodeData->resolutionData.numIPs > 0) { + objCDiscoveredNodeData.ipAddresses = [NSMutableArray new]; + } + for (int i = 0; i < chipDiscoveredNodeData->resolutionData.numIPs; i++) { + char addrCString[chip::Inet::IPAddress::kMaxStringLength]; + chipDiscoveredNodeData->resolutionData.ipAddress->ToString(addrCString, chip::Inet::IPAddress::kMaxStringLength); + objCDiscoveredNodeData.ipAddresses[i] = [NSString stringWithCString:addrCString encoding:NSASCIIStringEncoding]; + } + return objCDiscoveredNodeData; +} + +@end diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting.xcodeproj/project.pbxproj b/examples/tv-casting-app/darwin/TvCasting/TvCasting.xcodeproj/project.pbxproj index a417f366f7203f..179a71f9ac2275 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting.xcodeproj/project.pbxproj +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting.xcodeproj/project.pbxproj @@ -8,6 +8,12 @@ /* Begin PBXBuildFile section */ 3C75075C284B080900D7DB3A /* libmbedtls.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C75075B284B07E800D7DB3A /* libmbedtls.a */; settings = {ATTRIBUTES = (Required, ); }; }; + 3C7507A72851188500D7DB3A /* DiscoveredNodeData.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C7507A62851188500D7DB3A /* DiscoveredNodeData.mm */; }; + 3C7507AD285299DF00D7DB3A /* CommissionerDiscoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C7507AC285299DF00D7DB3A /* CommissionerDiscoveryView.swift */; }; + 3C7507AF28529A5F00D7DB3A /* CommissioningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C7507AE28529A5F00D7DB3A /* CommissioningView.swift */; }; + 3C7507B72853A3AD00D7DB3A /* CommissionerDiscoveryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C7507B62853A3AD00D7DB3A /* CommissionerDiscoveryViewModel.swift */; }; + 3C7507B92853EFF000D7DB3A /* CommissioningViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C7507B82853EFF000D7DB3A /* CommissioningViewModel.swift */; }; + 3C7507BC2857A6EE00D7DB3A /* DiscoveredNodeDataConverter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 3C7507BB2857A6EE00D7DB3A /* DiscoveredNodeDataConverter.mm */; }; 3C9ACC05284ABF4000718B2D /* libTvCastingCommon.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C9ACC04284ABF2F00718B2D /* libTvCastingCommon.a */; }; 3CC0E8FA2841DD3400EC6A18 /* TvCastingApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CC0E8F92841DD3400EC6A18 /* TvCastingApp.swift */; }; 3CC0E8FC2841DD3400EC6A18 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3CC0E8FB2841DD3400EC6A18 /* ContentView.swift */; }; @@ -19,6 +25,14 @@ /* Begin PBXFileReference section */ 3C75075B284B07E800D7DB3A /* libmbedtls.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbedtls.a; path = lib/libmbedtls.a; sourceTree = BUILT_PRODUCTS_DIR; }; 3C75075E284C1DF800D7DB3A /* TvCasting.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = TvCasting.entitlements; sourceTree = ""; }; + 3C7507A52851187500D7DB3A /* DiscoveredNodeData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DiscoveredNodeData.h; sourceTree = ""; }; + 3C7507A62851188500D7DB3A /* DiscoveredNodeData.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DiscoveredNodeData.mm; sourceTree = ""; }; + 3C7507AC285299DF00D7DB3A /* CommissionerDiscoveryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommissionerDiscoveryView.swift; sourceTree = ""; }; + 3C7507AE28529A5F00D7DB3A /* CommissioningView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommissioningView.swift; sourceTree = ""; }; + 3C7507B62853A3AD00D7DB3A /* CommissionerDiscoveryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommissionerDiscoveryViewModel.swift; sourceTree = ""; }; + 3C7507B82853EFF000D7DB3A /* CommissioningViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommissioningViewModel.swift; sourceTree = ""; }; + 3C7507BB2857A6EE00D7DB3A /* DiscoveredNodeDataConverter.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = DiscoveredNodeDataConverter.mm; sourceTree = ""; }; + 3C7507BD2857A72A00D7DB3A /* DiscoveredNodeDataConverter.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = DiscoveredNodeDataConverter.hpp; sourceTree = ""; }; 3C9ACC04284ABF2F00718B2D /* libTvCastingCommon.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libTvCastingCommon.a; path = lib/libTvCastingCommon.a; sourceTree = BUILT_PRODUCTS_DIR; }; 3CC0E8F62841DD3400EC6A18 /* TvCasting.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TvCasting.app; sourceTree = BUILT_PRODUCTS_DIR; }; 3CC0E8F92841DD3400EC6A18 /* TvCastingApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TvCastingApp.swift; sourceTree = ""; }; @@ -80,6 +94,10 @@ 3CC0E8FB2841DD3400EC6A18 /* ContentView.swift */, 3CC0E8FD2841DD3500EC6A18 /* Assets.xcassets */, 3CC0E8FF2841DD3500EC6A18 /* Preview Content */, + 3C7507AC285299DF00D7DB3A /* CommissionerDiscoveryView.swift */, + 3C7507B62853A3AD00D7DB3A /* CommissionerDiscoveryViewModel.swift */, + 3C7507AE28529A5F00D7DB3A /* CommissioningView.swift */, + 3C7507B82853EFF000D7DB3A /* CommissioningViewModel.swift */, ); path = TvCasting; sourceTree = ""; @@ -95,9 +113,13 @@ 3CC0E9072841DD4B00EC6A18 /* MatterBridge */ = { isa = PBXGroup; children = ( - 3CC0E9092841DD7000EC6A18 /* CastingServerBridge.mm */, 3CC0E9082841DD6F00EC6A18 /* TvCasting-Bridging-Header.h */, 3CC0E90B2841DD8500EC6A18 /* CastingServerBridge.h */, + 3CC0E9092841DD7000EC6A18 /* CastingServerBridge.mm */, + 3C7507A52851187500D7DB3A /* DiscoveredNodeData.h */, + 3C7507A62851188500D7DB3A /* DiscoveredNodeData.mm */, + 3C7507BB2857A6EE00D7DB3A /* DiscoveredNodeDataConverter.mm */, + 3C7507BD2857A72A00D7DB3A /* DiscoveredNodeDataConverter.hpp */, ); path = MatterBridge; sourceTree = ""; @@ -206,9 +228,15 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 3C7507AF28529A5F00D7DB3A /* CommissioningView.swift in Sources */, 3CC0E90A2841DD7000EC6A18 /* CastingServerBridge.mm in Sources */, + 3C7507B72853A3AD00D7DB3A /* CommissionerDiscoveryViewModel.swift in Sources */, 3CC0E8FC2841DD3400EC6A18 /* ContentView.swift in Sources */, + 3C7507AD285299DF00D7DB3A /* CommissionerDiscoveryView.swift in Sources */, 3CC0E8FA2841DD3400EC6A18 /* TvCastingApp.swift in Sources */, + 3C7507B92853EFF000D7DB3A /* CommissioningViewModel.swift in Sources */, + 3C7507BC2857A6EE00D7DB3A /* DiscoveredNodeDataConverter.mm in Sources */, + 3C7507A72851188500D7DB3A /* DiscoveredNodeData.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryView.swift new file mode 100644 index 00000000000000..b49e774164ad94 --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryView.swift @@ -0,0 +1,80 @@ +/** + * + * Copyright (c) 2020-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 SwiftUI + +extension DiscoveredNodeData : Identifiable { + public var id: String { + instanceName + } +} + +struct CommissionerDiscoveryView: View { + @StateObject var viewModel = CommissionerDiscoveryViewModel() + + var body: some View { + VStack(alignment: .leading) { + NavigationLink( + destination: CommissioningView(_selectedCommissioner: nil), + label: { + Text("Skip to manual commissioning >>") + .frame(width: 300, height: 30, alignment: .center) + .border(Color.black, width: 1) + } + ).background(Color.blue) + .foregroundColor(Color.white) + .padding() + + Button("Discover commissioners", action: viewModel.discoverAndUpdate) + .frame(width: 200, height: 30, alignment: .center) + .border(Color.black, width: 1) + .background(Color.blue) + .foregroundColor(Color.white) + .padding() + + if(viewModel.discoveryRequestStatus == false) + { + Text("Failed to send discovery request") + } + else if(!viewModel.commissioners.isEmpty) + { + Text("Select a commissioner TV...") + ForEach(viewModel.commissioners) { commissioner in + NavigationLink( + destination: CommissioningView(_selectedCommissioner: commissioner), + label: { + Text(commissioner.description) + } + ) + .frame(width: 350, height: 50, alignment: .center) + .border(Color.black, width: 1) + .background(Color.blue) + .foregroundColor(Color.white) + .padding(1) + } + } + } + .navigationTitle("TV Discovery") + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top) + } +} + +struct CommissionerDiscoveryView_Previews: PreviewProvider { + static var previews: some View { + CommissionerDiscoveryView() + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryViewModel.swift new file mode 100644 index 00000000000000..5defa202520d7a --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissionerDiscoveryViewModel.swift @@ -0,0 +1,66 @@ +/** + * + * Copyright (c) 2020-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 Foundation +import os.log + +class CommissionerDiscoveryViewModel: ObservableObject { + let Log = Logger(subsystem: "com.matter.casting", + category: "CommissionerDiscoveryViewModel") + + @Published var commissioners: [DiscoveredNodeData] = [] + + @Published var discoveryRequestStatus: Bool?; + + func discoverAndUpdate() { + if let castingServerBridge = CastingServerBridge.getSharedInstance() + { + castingServerBridge.discoverCommissioners(DispatchQueue.main, discoveryRequestSentHandler: { (result: Bool) -> () in + self.discoveryRequestStatus = result + }) + } + + Task { + try? await Task.sleep(nanoseconds: 5_000_000_000) // Wait for commissioners to respond + updateCommissioners() + } + } + + private func updateCommissioners() { + if let castingServerBridge = CastingServerBridge.getSharedInstance() + { + var i: Int32 = 0 + var commissioner: DiscoveredNodeData?; + repeat { + castingServerBridge.getDiscoveredCommissioner(i, clientQueue: DispatchQueue.main, discoveredCommissionerHandler: { (result: DiscoveredNodeData?) -> () in + commissioner = result; + if(commissioner != nil){ + if(self.commissioners.contains(commissioner!)) + { + self.Log.info("Skipping previously discovered commissioner \(commissioner!.description)") + } + else + { + self.commissioners.append(commissioner!) + } + } + }) + i += 1 + } while(commissioner != nil) + } + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift new file mode 100644 index 00000000000000..fee82a9c9cfacd --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningView.swift @@ -0,0 +1,75 @@ +/** + * + * Copyright (c) 2020-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 SwiftUI + +struct CommissioningView: View { + var selectedCommissioner: DiscoveredNodeData? + + @StateObject var viewModel = CommissioningViewModel(); + + init(_selectedCommissioner: DiscoveredNodeData?) { + self.selectedCommissioner = _selectedCommissioner + } + + var body: some View { + VStack(alignment: .leading) { + if(viewModel.commisisoningWindowOpened == true) { + Text("Commissioning window opened.") + + if(self.selectedCommissioner != nil) + { + if(viewModel.udcRequestSent == true) + { + Text("Complete commissioning on " + (selectedCommissioner?.deviceName)!) + } + else if(viewModel.udcRequestSent == false) { + Text("Could not send user directed commissioning request to " + (selectedCommissioner?.deviceName)! + "! Complete commissioning manually!") + .foregroundColor(Color.red) + } + } + else{ + Text("Complete commissioning with a commissioner manually!") + } + + // TBD: actual values + Text("Onboarding PIN: ") + .padding() + .border(Color.black, width: 1) + Text("Discriminator: ") + .padding() + .border(Color.black, width: 1) + } + else if(viewModel.commisisoningWindowOpened == false) { + Text("Failed to open Commissioning window!") + .foregroundColor(Color.red) + } + } + .navigationTitle("Commissioning...") + .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top) + .onAppear(perform: { + viewModel.prepareForCommissioning(selectedCommissioner: self.selectedCommissioner) + }) + } +} + +struct CommissioningView_Previews: PreviewProvider { + static var previews: some View { + CommissioningView(_selectedCommissioner: nil) + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift new file mode 100644 index 00000000000000..6e8a030a065c1d --- /dev/null +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/CommissioningViewModel.swift @@ -0,0 +1,48 @@ +/** + * + * Copyright (c) 2020-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 Foundation + +class CommissioningViewModel: ObservableObject { + @Published var udcRequestSent: Bool?; + + @Published var commisisoningWindowOpened: Bool?; + + func prepareForCommissioning(selectedCommissioner: DiscoveredNodeData?) { + // TBD: Call openBasicCommissioningWindow() and get Onboarding payload + + // Send User directed commissioning request if a commissioner with a known IP addr was selected + if(selectedCommissioner != nil && selectedCommissioner!.numIPs > 0) + { + sendUserDirectedCommissioningRequest(selectedCommissioner: selectedCommissioner) + } + } + + private func sendUserDirectedCommissioningRequest(selectedCommissioner: DiscoveredNodeData?) { + let ipAddress: String = selectedCommissioner!.ipAddresses[0] as! String + let port: UInt16 = selectedCommissioner!.port + let platformInterface: UInt32 = selectedCommissioner!.platformInterface + + if let castingServerBridge = CastingServerBridge.getSharedInstance() + { + castingServerBridge.sendUserDirectedCommissioningRequest(ipAddress, commissionerPort: port, platformInterface: platformInterface, clientQueue: DispatchQueue.main, udcRequestSentHandler: { (result: Bool) -> () in + self.udcRequestSent = result + }) + } + } +} diff --git a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentView.swift b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentView.swift index 737ea26a856383..13d7255a3d0838 100644 --- a/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentView.swift +++ b/examples/tv-casting-app/darwin/TvCasting/TvCasting/ContentView.swift @@ -19,8 +19,9 @@ import SwiftUI struct ContentView: View { var body: some View { - Text("Hello tv-casting-common C++, from Objective-C, from Swift! Sum: " + String(CastingServerBridge.getSharedInstance().add(5, secondNum: 6))) - .padding() + NavigationView { + CommissionerDiscoveryView() + } } } diff --git a/examples/tv-casting-app/darwin/TvCasting/chip_xcode_build_connector.sh b/examples/tv-casting-app/darwin/TvCasting/chip_xcode_build_connector.sh index d5ec1edcb4c206..3d0f82ed0d2e39 100755 --- a/examples/tv-casting-app/darwin/TvCasting/chip_xcode_build_connector.sh +++ b/examples/tv-casting-app/darwin/TvCasting/chip_xcode_build_connector.sh @@ -107,7 +107,7 @@ declare -a args=( [[ $PLATFORM_FAMILY_NAME != macOS ]] && { args+=( 'target_os="ios"' - 'import("//config/ios/args.gni")' + 'import("//examples/tv-casting-app/darwin/args.gni")' ) } diff --git a/examples/tv-casting-app/darwin/args.gni b/examples/tv-casting-app/darwin/args.gni new file mode 100644 index 00000000000000..1171f4d8398a89 --- /dev/null +++ b/examples/tv-casting-app/darwin/args.gni @@ -0,0 +1,31 @@ +# Copyright (c) 2020-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("//build_overrides/chip.gni") + +import("${chip_root}/config/ios/args.gni") + +chip_device_project_config_include = "" +chip_project_config_include = "" +chip_system_project_config_include = "" + +chip_project_config_include_dirs += + [ "${chip_root}/examples/tv-casting-app/tv-casting-common/include" ] +chip_project_config_include_dirs += [ "${chip_root}/config/ios" ] + +chip_build_libshell = true + +chip_enable_additional_data_advertising = true + +chip_enable_rotating_device_id = true