3 * Copyright (c) 2020 Project CHIP Authors
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #import "CHIPDeviceController.h"
19 #import "CHIPDevicePairingDelegateBridge.h"
20 #import "CHIPDevice_Internal.h"
22 #import "CHIPLogging.h"
23 #import "CHIPPersistentStorageDelegateBridge.h"
25 #include <controller/CHIPDeviceController.h>
26 #include <support/CHIPMem.h>
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";
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";
42 @interface CHIPDeviceController ()
44 @property (nonatomic, readonly, strong, nonnull) NSRecursiveLock * lock;
46 // queue used to serialize all work performed by the CHIPDeviceController
47 @property (atomic, readonly) dispatch_queue_t chipWorkQueue;
49 @property (readonly) chip::Controller::DeviceCommissioner * cppCommissioner;
50 @property (readonly) CHIPDevicePairingDelegateBridge * pairingDelegateBridge;
51 @property (readonly) CHIPPersistentStorageDelegateBridge * persistentStorageDelegateBridge;
52 @property (readonly) chip::NodeId localDeviceId;
56 @implementation CHIPDeviceController
58 + (CHIPDeviceController *)sharedController
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];
71 if (self = [super init]) {
72 CHIP_ERROR errorCode = CHIP_NO_ERROR;
74 _chipWorkQueue = dispatch_queue_create(CHIP_CONTROLLER_QUEUE, DISPATCH_QUEUE_SERIAL);
75 if ([self checkForStartError:(_chipWorkQueue != nil) logMsg:kErrorNetworkDispatchQueueInit]) {
79 errorCode = chip::Platform::MemoryInit();
80 if ([self checkForInitError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorMemoryInit]) {
84 _pairingDelegateBridge = new CHIPDevicePairingDelegateBridge();
85 if ([self checkForInitError:(_pairingDelegateBridge != nullptr) logMsg:kErrorPairingInit]) {
89 _persistentStorageDelegateBridge = new CHIPPersistentStorageDelegateBridge();
90 if ([self checkForInitError:(_persistentStorageDelegateBridge != nullptr) logMsg:kErrorPersistentStorageInit]) {
99 __block BOOL commissionerInitialized;
100 dispatch_sync(_chipWorkQueue, ^{
101 commissionerInitialized = [self _isRunning];
103 return commissionerInitialized;
108 return _cppCommissioner != nullptr;
113 dispatch_sync(_chipWorkQueue, ^{
114 if (_cppCommissioner) {
115 CHIP_LOG_DEBUG("%@", kInfoStackShutdown);
116 _cppCommissioner->Shutdown();
117 delete _cppCommissioner;
118 _cppCommissioner = nullptr;
125 - (BOOL)startup:(id<CHIPPersistentStorageDelegate>)storageDelegate queue:(nonnull dispatch_queue_t)queue
127 __block BOOL commissionerInitialized = NO;
128 dispatch_sync(_chipWorkQueue, ^{
129 if ([self _isRunning]) {
130 commissionerInitialized = YES;
134 CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
136 _persistentStorageDelegateBridge->setFrameworkDelegate(storageDelegate, queue);
137 // initialize NodeID if needed
138 [self _getControllerNodeId];
140 _cppCommissioner = new chip::Controller::DeviceCommissioner();
141 if (_cppCommissioner != nullptr) {
142 errorCode = _cppCommissioner->Init(_localDeviceId, _persistentStorageDelegateBridge, _pairingDelegateBridge);
144 if ([self checkForStartError:(CHIP_NO_ERROR == errorCode) logMsg:kErrorCommissionerInit]) {
149 self.cppCommissioner->ServiceEvents();
155 - (NSNumber *)getControllerNodeId
157 __block NSNumber * nodeID;
158 dispatch_sync(_chipWorkQueue, ^{
159 nodeID = [self _getControllerNodeId];
164 - (NSNumber *)_getControllerNodeId
166 uint16_t idStringLen = 32;
167 char deviceIdString[idStringLen];
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]);
176 NSScanner * scanner = [NSScanner scannerWithString:[NSString stringWithUTF8String:deviceIdString]];
177 [scanner scanHexLongLong:&_localDeviceId];
178 CHIP_LOG_ERROR("Found %llx node ID for the controller", _localDeviceId);
180 return [NSNumber numberWithUnsignedLongLong:_localDeviceId];
183 - (BOOL)pairDevice:(uint64_t)deviceID
184 discriminator:(uint16_t)discriminator
185 setupPINCode:(uint32_t)setupPINCode
186 error:(NSError * __autoreleasing *)error
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;
194 if ([self _isRunning]) {
195 errorCode = self.cppCommissioner->PairDevice(deviceID, params);
197 success = ![self checkForError:errorCode logMsg:kErrorPairDevice error:error];
203 - (BOOL)unpairDevice:(uint64_t)deviceID error:(NSError * __autoreleasing *)error
205 __block BOOL success;
206 dispatch_sync(_chipWorkQueue, ^{
207 CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
209 if ([self _isRunning]) {
210 errorCode = self.cppCommissioner->UnpairDevice(deviceID);
212 success = ![self checkForError:errorCode logMsg:kErrorUnpairDevice error:error];
218 - (BOOL)stopDevicePairing:(uint64_t)deviceID error:(NSError * __autoreleasing *)error
220 __block BOOL success;
221 dispatch_sync(_chipWorkQueue, ^{
222 CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
224 if ([self _isRunning]) {
225 errorCode = self.cppCommissioner->StopPairing(deviceID);
227 success = ![self checkForError:errorCode logMsg:kErrorStopPairing error:error];
233 - (CHIPDevice *)getPairedDevice:(uint64_t)deviceID error:(NSError * __autoreleasing *)error
235 __block CHIPDevice * chipDevice = nil;
236 dispatch_sync(_chipWorkQueue, ^{
237 CHIP_ERROR errorCode = CHIP_ERROR_INCORRECT_STATE;
238 chip::Controller::Device * device = nullptr;
240 if ([self _isRunning]) {
241 errorCode = self.cppCommissioner->GetDevice(deviceID, &device);
244 if ([self checkForError:errorCode logMsg:kErrorGetPairedDevice error:error]) {
248 chipDevice = [[CHIPDevice alloc] initWithDevice:device];
254 - (void)setPairingDelegate:(id<CHIPDevicePairingDelegate>)delegate queue:(dispatch_queue_t)queue
256 dispatch_async(_chipWorkQueue, ^{
257 self->_pairingDelegateBridge->setDelegate(delegate, queue);
261 - (void)sendWiFiCredentials:(NSString *)ssid password:(NSString *)password
263 dispatch_async(_chipWorkQueue, ^{
264 self->_pairingDelegateBridge->SendWiFiCredentials(ssid, password);
268 - (void)sendThreadCredentials:(NSData *)threadDataSet
270 dispatch_async(_chipWorkQueue, ^{
271 self->_pairingDelegateBridge->SendThreadCredentials(threadDataSet);
275 - (BOOL)checkForInitError:(BOOL)condition logMsg:(NSString *)logMsg
281 CHIP_LOG_ERROR("Error: %@", logMsg);
283 if (_cppCommissioner) {
284 delete _cppCommissioner;
285 _cppCommissioner = NULL;
288 if (_pairingDelegateBridge) {
289 delete _pairingDelegateBridge;
290 _pairingDelegateBridge = NULL;
293 if (_persistentStorageDelegateBridge) {
294 delete _persistentStorageDelegateBridge;
295 _persistentStorageDelegateBridge = NULL;
301 - (BOOL)checkForStartError:(BOOL)condition logMsg:(NSString *)logMsg
307 CHIP_LOG_ERROR("Error: %@", logMsg);
309 if (_cppCommissioner) {
310 delete _cppCommissioner;
311 _cppCommissioner = NULL;
317 - (BOOL)checkForError:(CHIP_ERROR)errorCode logMsg:(NSString *)logMsg error:(NSError * __autoreleasing *)error
319 if (CHIP_NO_ERROR == errorCode) {
323 CHIP_LOG_ERROR("Error(%d): %@, %@", errorCode, [CHIPError errorForCHIPErrorCode:errorCode], logMsg);
325 *error = [CHIPError errorForCHIPErrorCode:errorCode];