Skip to content

Commit

Permalink
Implement UI to unpair devices in iOS CHIP Tool (#4875)
Browse files Browse the repository at this point in the history
* Enable opening of pairing window on multiple devices

* increment device ID only on successful pairing

* address review comments
  • Loading branch information
pan-apple authored and pull[bot] committed Mar 2, 2021
1 parent 8c9a815 commit 6c3548a
Show file tree
Hide file tree
Showing 21 changed files with 459 additions and 143 deletions.
10 changes: 5 additions & 5 deletions src/controller/CHIPDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ void Device::OnMessageReceived(const PacketHeader & header, const PayloadHeader
}
}

CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, bool useToken, uint16_t discriminator, SetupPayload & setupPayload)
CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, PairingWindowOption option, SetupPayload & setupPayload)
{
// TODO: This code is temporary, and must be updated to use the Cluster API.
// Issue: https://github.com/project-chip/connectedhomeip/issues/4725
Expand All @@ -262,12 +262,13 @@ CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, bool useToken, uint16_t d

ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 1), timeout));

if (useToken)
if (option != PairingWindowOption::kOriginalSetupCode)
{
ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 2), discriminator));
ReturnErrorOnFailure(writer.Put(TLV::ProfileTag(writer.ImplicitProfileId, 2), setupPayload.discriminator));

PASEVerifier verifier;
ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, setupPayload.setUpPINCode));
bool randomSetupPIN = (option == PairingWindowOption::kTokenWithRandomPIN);
ReturnErrorOnFailure(PASESession::GeneratePASEVerifier(verifier, randomSetupPIN, setupPayload.setUpPINCode));
ReturnErrorOnFailure(writer.PutBytes(TLV::ProfileTag(writer.ImplicitProfileId, 3),
reinterpret_cast<const uint8_t *>(verifier), sizeof(verifier)));
}
Expand All @@ -283,7 +284,6 @@ CHIP_ERROR Device::OpenPairingWindow(uint32_t timeout, bool useToken, uint16_t d

setupPayload.version = 1;
setupPayload.rendezvousInformation = RendezvousInformationFlags::kBLE;
setupPayload.discriminator = discriminator;

return CHIP_NO_ERROR;
}
Expand Down
17 changes: 12 additions & 5 deletions src/controller/CHIPDevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ class DLL_EXPORT Device
}
}

enum class PairingWindowOption
{
kOriginalSetupCode,
kTokenWithRandomPIN,
kTokenWithProvidedPIN,
};

/**
* @brief
* Set the delegate object which will be called when a message is received.
Expand Down Expand Up @@ -241,15 +248,15 @@ class DLL_EXPORT Device
* The device will exit the pairing mode after a successful pairing, or after the given `timeout` time.
*
* @param[in] timeout The pairing mode should terminate after this much time.
* @param[in] useToken Generate an onboarding token and send it to the device. The device must
* use the provided onboarding token instead of the original pairing setup PIN
* and discriminator.
* @param[in] discriminator The discriminator that the device should use for advertising and pairing.
* @param[in] option The pairing window can be opened using the original setup code, or an
* onboarding token can be generated using a random setup PIN code (or with
* the PIN code provied in the setupPayload). This argument selects one of these
* methods.
* @param[out] setupPayload The setup payload corresponding to the generated onboarding token.
*
* @return CHIP_ERROR CHIP_NO_ERROR on success, or corresponding error
*/
CHIP_ERROR OpenPairingWindow(uint32_t timeout, bool useToken, uint16_t discriminator, SetupPayload & setupPayload);
CHIP_ERROR OpenPairingWindow(uint32_t timeout, PairingWindowOption option, SetupPayload & setupPayload);

/**
* @brief
Expand Down
22 changes: 20 additions & 2 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,10 @@ CHIP_ERROR DeviceController::GetDevice(NodeId deviceId, Device ** out_device)
{
chip::Platform::MemoryFree(buffer);
}
if (err != CHIP_NO_ERROR && device != nullptr)
{
ReleaseDevice(device);
}
return err;
}

Expand Down Expand Up @@ -452,6 +456,17 @@ void DeviceController::ReleaseDevice(uint16_t index)
}
}

void DeviceController::ReleaseDeviceById(NodeId remoteDeviceId)
{
for (uint16_t i = 0; i < kNumMaxActiveDevices; i++)
{
if (mActiveDevices[i].GetDeviceId() == remoteDeviceId)
{
ReleaseDevice(&mActiveDevices[i]);
}
}
}

void DeviceController::ReleaseAllDevices()
{
for (uint16_t i = 0; i < kNumMaxActiveDevices; i++)
Expand Down Expand Up @@ -672,6 +687,7 @@ CHIP_ERROR DeviceCommissioner::PairTestDeviceWithoutSecurity(NodeId remoteDevice

return err;
}

CHIP_ERROR DeviceCommissioner::StopPairing(NodeId remoteDeviceId)
{
CHIP_ERROR err = CHIP_NO_ERROR;
Expand Down Expand Up @@ -703,10 +719,12 @@ CHIP_ERROR DeviceCommissioner::UnpairDevice(NodeId remoteDeviceId)
if (mStorageDelegate != nullptr)
{
PERSISTENT_KEY_OP(remoteDeviceId, kPairedDeviceKeyPrefix, key, mStorageDelegate->DeleteKeyValue(key));
mPairedDevices.Remove(remoteDeviceId);
mPairedDevicesUpdated = true;
}

mPairedDevices.Remove(remoteDeviceId);
mPairedDevicesUpdated = true;
ReleaseDeviceById(remoteDeviceId);

return CHIP_NO_ERROR;
}

Expand Down
1 change: 1 addition & 0 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ class DLL_EXPORT DeviceController : public SecureSessionMgrDelegate, public Pers
uint16_t FindDeviceIndex(SecureSessionHandle session);
uint16_t FindDeviceIndex(NodeId id);
void ReleaseDevice(uint16_t index);
void ReleaseDeviceById(NodeId remoteDeviceId);
CHIP_ERROR SetPairedDeviceList(const char * pairedDeviceSerializedSet);

Transport::AdminId mAdminId = 0;
Expand Down
14 changes: 14 additions & 0 deletions src/darwin/CHIPTool/CHIPTool.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
0CA0E0CF248599BB009087B9 /* OnOffViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 0CA0E0CE248599BB009087B9 /* OnOffViewController.m */; };
2C21071525D1A8F200DDA4AD /* MultiAdminViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C21071325D1A8F200DDA4AD /* MultiAdminViewController.m */; };
2C460C2425D7594B000512D6 /* DeviceSelector.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C460C2325D7594B000512D6 /* DeviceSelector.m */; };
2C460C3225D97CB3000512D6 /* UnpairDevicesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 2C460C3025D97CB3000512D6 /* UnpairDevicesViewController.m */; };
991DC091247747F500C13860 /* EchoViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 991DC090247747F500C13860 /* EchoViewController.m */; };
997A639C253F93F7005C64E6 /* CHIP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 997A639B253F93F7005C64E6 /* CHIP.framework */; };
997A639D253F93F7005C64E6 /* CHIP.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 997A639B253F93F7005C64E6 /* CHIP.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
Expand Down Expand Up @@ -58,6 +59,8 @@
2C21071425D1A8F200DDA4AD /* MultiAdminViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultiAdminViewController.h; sourceTree = "<group>"; };
2C460C2225D7594B000512D6 /* DeviceSelector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceSelector.h; sourceTree = "<group>"; };
2C460C2325D7594B000512D6 /* DeviceSelector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeviceSelector.m; sourceTree = "<group>"; };
2C460C3025D97CB3000512D6 /* UnpairDevicesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UnpairDevicesViewController.m; sourceTree = "<group>"; };
2C460C3125D97CB3000512D6 /* UnpairDevicesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnpairDevicesViewController.h; sourceTree = "<group>"; };
991DC08F247747F500C13860 /* EchoViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = EchoViewController.h; sourceTree = "<group>"; };
991DC090247747F500C13860 /* EchoViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = EchoViewController.m; sourceTree = "<group>"; };
997A639B253F93F7005C64E6 /* CHIP.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = CHIP.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -144,6 +147,15 @@
path = MultiAdmin;
sourceTree = "<group>";
};
2C460C2F25D97CB3000512D6 /* UnpairDevices */ = {
isa = PBXGroup;
children = (
2C460C3025D97CB3000512D6 /* UnpairDevicesViewController.m */,
2C460C3125D97CB3000512D6 /* UnpairDevicesViewController.h */,
);
path = UnpairDevices;
sourceTree = "<group>";
};
B20252DE2459EC7600F97062 /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -206,6 +218,7 @@
B232D8BF251A0EC500792CB4 /* View Controllers */ = {
isa = PBXGroup;
children = (
2C460C2F25D97CB3000512D6 /* UnpairDevices */,
2C460C2225D7594B000512D6 /* DeviceSelector.h */,
2C460C2325D7594B000512D6 /* DeviceSelector.m */,
2C21071225D1A8F200DDA4AD /* MultiAdmin */,
Expand Down Expand Up @@ -364,6 +377,7 @@
2C460C2425D7594B000512D6 /* DeviceSelector.m in Sources */,
2C21071525D1A8F200DDA4AD /* MultiAdminViewController.m in Sources */,
B204A627244E1D0600C7C0E1 /* QRCodeViewController.m in Sources */,
2C460C3225D97CB3000512D6 /* UnpairDevicesViewController.m in Sources */,
B232D8BA2514BD0800792CB4 /* CHIPUIViewUtils.m in Sources */,
B2946A9B24C9A7BF005C87D0 /* DefaultsUtils.m in Sources */,
991DC091247747F500C13860 /* EchoViewController.m in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ extern NSString * const kCHIPToolDefaultsDomain;
extern NSString * const kNetworkSSIDDefaultsKey;
extern NSString * const kNetworkPasswordDefaultsKey;

CHIPDeviceController * InitializeCHIP(void);
id CHIPGetDomainValueForKey(NSString * domain, NSString * key);
void CHIPSetDomainValueForKey(NSString * domain, NSString * key, id value);
void CHIPRemoveDomainValueForKey(NSString * domain, NSString * key);
uint64_t CHIPGetNextAvailableDeviceID(void);
void CHIPSetNextAvailableDeviceID(uint64_t id);
CHIPDevice * CHIPGetPairedDevice(void);
CHIPDevice * CHIPGetPairedDeviceWithID(uint64_t id);
void CHIPUnpairDeviceWithID(uint64_t deviceId);

@interface CHIPToolPersistentStorageDelegate : NSObject <CHIPPersistentStorageDelegate>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ void CHIPSetNextAvailableDeviceID(uint64_t id)
return [controller getPairedDevice:deviceId error:&error];
}

void CHIPUnpairDeviceWithID(uint64_t deviceId)
{
CHIPDeviceController * controller = InitializeCHIP();

NSError * error;
[controller unpairDevice:deviceId error:&error];
}

@implementation CHIPToolPersistentStorageDelegate

// MARK: CHIPPersistentStorageDelegate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ - (void)setupUI

- (void)_clearTextFields
{
CHIPDeviceController * chipController = [CHIPDeviceController sharedController];
CHIPDeviceController * chipController = InitializeCHIP();
_nodeIDTextField.text = [NSString stringWithFormat:@"%@", chipController.getControllerNodeId];
_endpointIDTextField.text = @"1";
_groupIDTextField.text = @"0";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,12 @@

NS_ASSUME_NONNULL_BEGIN

typedef void (^DeviceAction)(uint64_t deviceId);

@interface DeviceSelector : UITextField <UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate>
- (instancetype)init;
- (CHIPDevice *)selectedDevice;
- (void)refreshDeviceList;
- (void)forSelectedDevices:(DeviceAction)action;
@end

NS_ASSUME_NONNULL_END
67 changes: 43 additions & 24 deletions src/darwin/CHIPTool/CHIPTool/View Controllers/DeviceSelector.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@
#import "DefaultsUtils.h"

@interface DeviceSelector ()
@property (readwrite) CHIPDevice * chipDevice;
@property (readwrite) uint64_t nextDeviceID;
@end

@implementation DeviceSelector {
Expand All @@ -34,43 +32,49 @@ @implementation DeviceSelector {
- (id)init
{
if (self = [super init]) {
_nextDeviceID = CHIPGetNextAvailableDeviceID();
_selectedDeviceIndex = self.nextDeviceID + 1;
[self refreshDeviceList];
[self setupView];
[self setEnabled:YES];
}
return self;
}

- (void)refreshDeviceList
{
uint64_t nextDeviceID = CHIPGetNextAvailableDeviceID();
_deviceList = [NSMutableArray new];
for (uint64_t i = 0; i < _nextDeviceID; i++) {
for (uint64_t i = 0; i < nextDeviceID; i++) {
if (CHIPGetPairedDeviceWithID(i) != nil) {
[_deviceList addObject:[@(i) stringValue]];
}
}
_selectedDeviceIndex = 0;
}

- (void)selectDevice
{
if ([_deviceList count] > 0) {
uint64_t deviceID = [_deviceList[_selectedDeviceIndex] intValue];
_chipDevice = CHIPGetPairedDeviceWithID(deviceID);
}
// This will refresh the view with the updated device list
[self setEnabled:self.isEnabled];
}

- (CHIPDevice *)selectedDevice
- (void)forSelectedDevices:(DeviceAction)action
{
return _chipDevice;
if ([self isEnabled]) {
if ([_deviceList count] > 0) {
uint64_t nodeId;
NSScanner * scanner = [NSScanner scannerWithString:[_deviceList objectAtIndex:_selectedDeviceIndex]];
[scanner scanUnsignedLongLong:&nodeId];
action(nodeId);
}
} else {
for (id device in _deviceList) {
uint64_t nodeId;
NSScanner * scanner = [NSScanner scannerWithString:device];
[scanner scanUnsignedLongLong:&nodeId];
action(nodeId);
}
}
}

- (void)setupView
{
if ([_deviceList count] > 0) {
self.text = [_deviceList objectAtIndex:_selectedDeviceIndex];
}
_devicePicker = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 100, 0, 0)];
self.inputView = _devicePicker;
[_devicePicker setDataSource:self];
Expand All @@ -79,7 +83,7 @@ - (void)setupView

UIToolbar * deviceSelectButtonView = [[UIToolbar alloc] init];
[deviceSelectButtonView sizeToFit];
UIBarButtonItem * deviceSelectButton = [[UIBarButtonItem alloc] initWithTitle:@"Select Device"
UIBarButtonItem * deviceSelectButton = [[UIBarButtonItem alloc] initWithTitle:@"Select"
style:UIBarButtonItemStylePlain
target:self
action:@selector(deviceSelectClicked:)];
Expand All @@ -88,16 +92,26 @@ - (void)setupView
action:nil];
[deviceSelectButtonView setItems:[NSArray arrayWithObjects:flexible, deviceSelectButton, nil]];
self.inputAccessoryView = deviceSelectButtonView;
}

[self selectDevice];
- (void)setEnabled:(BOOL)enabled
{
[super setEnabled:enabled];
if (enabled == NO) {
self.text = [_deviceList description];
} else if ([_deviceList count] > 0) {
self.text = [NSString stringWithFormat:@"%@", [_deviceList objectAtIndex:_selectedDeviceIndex]];
}
}

// MARK: UIPickerView

- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
NSLog(@"%@", [_deviceList objectAtIndex:row]);
self.text = [NSString stringWithFormat:@"%@", [_deviceList objectAtIndex:row]];
if ([_deviceList count] > 0) {
NSLog(@"%@", [_deviceList objectAtIndex:row]);
self.text = [NSString stringWithFormat:@"%@", [_deviceList objectAtIndex:row]];
}
}

- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
Expand All @@ -112,7 +126,11 @@ - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView

- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
return [_deviceList objectAtIndex:row];
if ([_deviceList count] > 0) {
return [_deviceList objectAtIndex:row];
} else {
return [NSString new];
}
}

- (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)component
Expand All @@ -122,9 +140,10 @@ - (CGFloat)pickerView:(UIPickerView *)pickerView widthForComponent:(NSInteger)co

- (IBAction)deviceSelectClicked:(id)sender
{
_selectedDeviceIndex = [_deviceList indexOfObject:self.text];
if ([_deviceList count] > 0) {
_selectedDeviceIndex = [_deviceList indexOfObject:self.text];
}
[self resignFirstResponder];
[self selectDevice];
}

// MARK: CHIPDeviceControllerDelegate
Expand Down
Loading

0 comments on commit 6c3548a

Please sign in to comment.