Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / darwin / Framework / CHIP / CHIPDeviceController.mm
1 /**
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *
5  *    Licensed under the Apache License, Version 2.0 (the "License");
6  *    you may not use this file except in compliance with the License.
7  *    You may obtain a copy of the License at
8  *
9  *        http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *    Unless required by applicable law or agreed to in writing, software
12  *    distributed under the License is distributed on an "AS IS" BASIS,
13  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *    See the License for the specific language governing permissions and
15  *    limitations under the License.
16  */
17 #import "CHIPDeviceController.h"
18
19 #import "CHIPDevicePairingDelegateBridge.h"
20 #import "CHIPDevice_Internal.h"
21 #import "CHIPError.h"
22 #import "CHIPLogging.h"
23 #import "CHIPPersistentStorageDelegateBridge.h"
24
25 #include <controller/CHIPDeviceController.h>
26 #include <support/CHIPMem.h>
27
28 static const char * const CHIP_CONTROLLER_QUEUE = "com.zigbee.chip.framework.controller.workqueue";
29 static const char * const CHIP_COMMISSIONER_DEVICE_ID_KEY = "com.zigbee.chip.commissioner.device.id";
30
31 static NSString * const kErrorMemoryInit = @"Init Memory failure";
32 static NSString * const kErrorCommissionerInit = @"Init failure while initializing a commissioner";
33 static NSString * const kErrorPairingInit = @"Init failure while creating a pairing delegate";
34 static NSString * const kErrorPersistentStorageInit = @"Init failure while creating a persistent storage delegate";
35 static NSString * const kErrorNetworkDispatchQueueInit = @"Init failure while initializing a dispatch queue for the network events";
36 static NSString * const kErrorPairDevice = @"Failure while pairing the device";
37 static NSString * const kErrorUnpairDevice = @"Failure while unpairing the device";
38 static NSString * const kErrorStopPairing = @"Failure while trying to stop the pairing process";
39 static NSString * const kErrorGetPairedDevice = @"Failure while trying to retrieve a paired device";
40 static NSString * const kInfoStackShutdown = @"Shutting down the CHIP Stack";
41
42 @interface CHIPDeviceController ()
43
44 @property (nonatomic, readonly, strong, nonnull) NSRecursiveLock * lock;
45
46 // queue used to serialize all work performed by the CHIPDeviceController
47 @property (atomic, readonly) dispatch_queue_t chipWorkQueue;
48
49 @property (readonly) chip::Controller::DeviceCommissioner * cppCommissioner;
50 @property (readonly) CHIPDevicePairingDelegateBridge * pairingDelegateBridge;
51 @property (readonly) CHIPPersistentStorageDelegateBridge * persistentStorageDelegateBridge;
52 @property (readonly) chip::NodeId localDeviceId;
53
54 @end
55
56 @implementation CHIPDeviceController
57
58 + (CHIPDeviceController *)sharedController
59 {
60     static CHIPDeviceController * controller = nil;
61     static dispatch_once_t onceToken;
62     dispatch_once(&onceToken, ^{
63         // initialize the device controller
64         controller = [[CHIPDeviceController alloc] init];
65     });
66     return controller;
67 }
68
69 - (instancetype)init
70 {
71     if (self = [super init]) {
72         CHIP_ERROR errorCode = CHIP_NO_ERROR;
73
74         _chipWorkQueue = dispatch_queue_create(CHIP_CONTROLLER_QUEUE, DISPATCH_QUEUE_SERIAL);
75         if ([self checkForStartError:(_chipWorkQueue != nil) logMsg:kErrorNetworkDispatchQueueInit]) {
76             return nil;
77         }
78
79         errorCode = chip::Platform::MemoryInit();
80         if ([self checkForInitError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorMemoryInit]) {
81             return nil;
82         }
83
84         _pairingDelegateBridge = new CHIPDevicePairingDelegateBridge();
85         if ([self checkForInitError:(_pairingDelegateBridge != nullptr) logMsg:kErrorPairingInit]) {
86             return nil;
87         }
88
89         _persistentStorageDelegateBridge = new CHIPPersistentStorageDelegateBridge();
90         if ([self checkForInitError:(_persistentStorageDelegateBridge != nullptr) logMsg:kErrorPersistentStorageInit]) {
91             return nil;
92         }
93     }
94     return self;
95 }
96
97 - (BOOL)isRunning
98 {
99     __block BOOL commissionerInitialized;
100     dispatch_sync(_chipWorkQueue, ^{
101         commissionerInitialized = [self _isRunning];
102     });
103     return commissionerInitialized;
104 }
105
106 - (BOOL)_isRunning
107 {
108     return _cppCommissioner != nullptr;
109 }
110
111 - (BOOL)shutdown
112 {
113     dispatch_sync(_chipWorkQueue, ^{
114         if (_cppCommissioner) {
115             CHIP_LOG_DEBUG("%@", kInfoStackShutdown);
116             _cppCommissioner->Shutdown();
117             delete _cppCommissioner;
118             _cppCommissioner = nullptr;
119         }
120     });
121
122     return YES;
123 }
124
125 - (BOOL)startup:(id<CHIPPersistentStorageDelegate>)storageDelegate queue:(nonnull dispatch_queue_t)queue
126 {
127     __block BOOL commissionerInitialized = NO;
128     dispatch_sync(_chipWorkQueue, ^{
129         if ([self _isRunning]) {
130             commissionerInitialized = YES;
131             return;
132         }
133
134         CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
135
136         _persistentStorageDelegateBridge->setFrameworkDelegate(storageDelegate, queue);
137         // initialize NodeID if needed
138         [self _getControllerNodeId];
139
140         _cppCommissioner = new chip::Controller::DeviceCommissioner();
141         if (_cppCommissioner != nullptr) {
142             errorCode = _cppCommissioner->Init(_localDeviceId, _persistentStorageDelegateBridge, _pairingDelegateBridge);
143         }
144         if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorCommissionerInit]) {
145             return;
146         }
147
148         // Start the IO pump
149         self.cppCommissioner->ServiceEvents();
150     });
151
152     return YES;
153 }
154
155 - (NSNumber *)getControllerNodeId
156 {
157     __block NSNumber * nodeID;
158     dispatch_sync(_chipWorkQueue, ^{
159         nodeID = [self _getControllerNodeId];
160     });
161     return nodeID;
162 }
163
164 - (NSNumber *)_getControllerNodeId
165 {
166     uint16_t idStringLen = 32;
167     char deviceIdString[idStringLen];
168     if (CHIP_NO_ERROR
169         != _persistentStorageDelegateBridge->SyncGetKeyValue(CHIP_COMMISSIONER_DEVICE_ID_KEY, deviceIdString, idStringLen)) {
170         _localDeviceId = arc4random();
171         _localDeviceId = _localDeviceId << 32 | arc4random();
172         CHIP_LOG_ERROR("Assigned %llx node ID to the controller", _localDeviceId);
173         _persistentStorageDelegateBridge->AsyncSetKeyValue(
174             CHIP_COMMISSIONER_DEVICE_ID_KEY, [[NSString stringWithFormat:@"%llx", _localDeviceId] UTF8String]);
175     } else {
176         NSScanner * scanner = [NSScanner scannerWithString:[NSString stringWithUTF8String:deviceIdString]];
177         [scanner scanHexLongLong:&_localDeviceId];
178         CHIP_LOG_ERROR("Found %llx node ID for the controller", _localDeviceId);
179     }
180     return [NSNumber numberWithUnsignedLongLong:_localDeviceId];
181 }
182
183 - (BOOL)pairDevice:(uint64_t)deviceID
184      discriminator:(uint16_t)discriminator
185       setupPINCode:(uint32_t)setupPINCode
186              error:(NSError * __autoreleasing *)error
187 {
188     __block BOOL success;
189     dispatch_sync(_chipWorkQueue, ^{
190         chip::RendezvousParameters params
191             = chip::RendezvousParameters().SetSetupPINCode(setupPINCode).SetDiscriminator(discriminator);
192         CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
193
194         if ([self _isRunning]) {
195             errorCode = self.cppCommissioner->PairDevice(deviceID, params);
196         }
197         success = ![self checkForError:errorCode logMsg:kErrorPairDevice error:error];
198     });
199
200     return success;
201 }
202
203 - (BOOL)unpairDevice:(uint64_t)deviceID error:(NSError * __autoreleasing *)error
204 {
205     __block BOOL success;
206     dispatch_sync(_chipWorkQueue, ^{
207         CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
208
209         if ([self _isRunning]) {
210             errorCode = self.cppCommissioner->UnpairDevice(deviceID);
211         }
212         success = ![self checkForError:errorCode logMsg:kErrorUnpairDevice error:error];
213     });
214
215     return success;
216 }
217
218 - (BOOL)stopDevicePairing:(uint64_t)deviceID error:(NSError * __autoreleasing *)error
219 {
220     __block BOOL success;
221     dispatch_sync(_chipWorkQueue, ^{
222         CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
223
224         if ([self _isRunning]) {
225             errorCode = self.cppCommissioner->StopPairing(deviceID);
226         }
227         success = ![self checkForError:errorCode logMsg:kErrorStopPairing error:error];
228     });
229
230     return success;
231 }
232
233 - (CHIPDevice *)getPairedDevice:(uint64_t)deviceID error:(NSError * __autoreleasing *)error
234 {
235     __block CHIPDevice * chipDevice = nil;
236     dispatch_sync(_chipWorkQueue, ^{
237         CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
238         chip::Controller::Device * device = nullptr;
239
240         if ([self _isRunning]) {
241             errorCode = self.cppCommissioner->GetDevice(deviceID, &device);
242         }
243
244         if ([self checkForError:errorCode logMsg:kErrorGetPairedDevice error:error]) {
245             return;
246         }
247
248         chipDevice = [[CHIPDevice alloc] initWithDevice:device];
249     });
250
251     return chipDevice;
252 }
253
254 - (void)setPairingDelegate:(id<CHIPDevicePairingDelegate>)delegate queue:(dispatch_queue_t)queue
255 {
256     dispatch_async(_chipWorkQueue, ^{
257         self->_pairingDelegateBridge->setDelegate(delegate, queue);
258     });
259 }
260
261 - (void)sendWiFiCredentials:(NSString *)ssid password:(NSString *)password
262 {
263     dispatch_async(_chipWorkQueue, ^{
264         self->_pairingDelegateBridge->SendWiFiCredentials(ssid, password);
265     });
266 }
267
268 - (void)sendThreadCredentials:(NSData *)threadDataSet
269 {
270     dispatch_async(_chipWorkQueue, ^{
271         self->_pairingDelegateBridge->SendThreadCredentials(threadDataSet);
272     });
273 }
274
275 - (BOOL)checkForInitError:(BOOL)condition logMsg:(NSString *)logMsg
276 {
277     if (condition) {
278         return NO;
279     }
280
281     CHIP_LOG_ERROR("Error: %@", logMsg);
282
283     if (_cppCommissioner) {
284         delete _cppCommissioner;
285         _cppCommissioner = NULL;
286     }
287
288     if (_pairingDelegateBridge) {
289         delete _pairingDelegateBridge;
290         _pairingDelegateBridge = NULL;
291     }
292
293     if (_persistentStorageDelegateBridge) {
294         delete _persistentStorageDelegateBridge;
295         _persistentStorageDelegateBridge = NULL;
296     }
297
298     return YES;
299 }
300
301 - (BOOL)checkForStartError:(BOOL)condition logMsg:(NSString *)logMsg
302 {
303     if (condition) {
304         return NO;
305     }
306
307     CHIP_LOG_ERROR("Error: %@", logMsg);
308
309     if (_cppCommissioner) {
310         delete _cppCommissioner;
311         _cppCommissioner = NULL;
312     }
313
314     return YES;
315 }
316
317 - (BOOL)checkForError:(CHIP_ERROR)errorCode logMsg:(NSString *)logMsg error:(NSError * __autoreleasing *)error
318 {
319     if (CHIP_NO_ERROR == errorCode) {
320         return NO;
321     }
322
323     CHIP_LOG_ERROR("Error(%d): %@, %@", errorCode, [CHIPError errorForCHIPErrorCode:errorCode], logMsg);
324     if (error) {
325         *error = [CHIPError errorForCHIPErrorCode:errorCode];
326     }
327
328     return YES;
329 }
330
331 @end