diff --git a/.gitignore b/.gitignore index 0e37ed07..7813ba0c 100644 --- a/.gitignore +++ b/.gitignore @@ -60,7 +60,7 @@ xcuserdata/ *.dSYM # CocoaPods - Refactored to standalone file - +Pods/* # Carthage - Refactored to standalone file diff --git a/SiliconLabsApp-Bridging-Header.h b/SiliconLabsApp-Bridging-Header.h index 8a9aa0ad..29a1eb71 100644 --- a/SiliconLabsApp-Bridging-Header.h +++ b/SiliconLabsApp-Bridging-Header.h @@ -20,3 +20,5 @@ #import "UIColor+SILColors.h" #import "NSString+SILBrowserNotifications.h" #import "SILBluetoothBrowser+Constants.h" +#import "SILAdvertisementDataModel.h" +#import "SILBluetoothModelManager.h" diff --git a/SiliconLabsApp.xcodeproj/project.pbxproj b/SiliconLabsApp.xcodeproj/project.pbxproj index 06e161b2..f74e8000 100644 --- a/SiliconLabsApp.xcodeproj/project.pbxproj +++ b/SiliconLabsApp.xcodeproj/project.pbxproj @@ -54,7 +54,6 @@ 078138591BE9B014001EFE7E /* SILTextFieldEntryCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 078138571BE9B014001EFE7E /* SILTextFieldEntryCell.m */; }; 0797E34D1BF0071D0046EF0E /* SILTextFieldEntryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0797E34B1BF0071D0046EF0E /* SILTextFieldEntryCell.xib */; }; 0797E34E1BF0071D0046EF0E /* SILDebugCharacteristicEncodingViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0797E34C1BF0071D0046EF0E /* SILDebugCharacteristicEncodingViewController.xib */; }; - 07A9563F1BDD40CB0028D333 /* SILAlertBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 07A9563E1BDD40CB0028D333 /* SILAlertBarView.m */; }; 07B1AD781BFD043000D4D454 /* SILBeaconViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 07B1AD771BFD043000D4D454 /* SILBeaconViewModel.m */; }; 07B1AD7B1BFD05CA00D4D454 /* SILBGBeaconViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 07B1AD7A1BFD05CA00D4D454 /* SILBGBeaconViewModel.m */; }; 07B1AD7E1BFD0A2100D4D454 /* SILIBeaconViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 07B1AD7D1BFD0A2100D4D454 /* SILIBeaconViewModel.m */; }; @@ -95,7 +94,6 @@ 0C2FCB0C1F9A542300F4F259 /* SILBluetoothModelManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 07BBA74D1BD5858F00C2B07E /* SILBluetoothModelManager.m */; }; 0C2FCB0D1F9A542300F4F259 /* SILSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = E607A3501A8D4FD100DAAFD3 /* SILSettings.m */; }; 0C2FCB0E1F9A542300F4F259 /* SILWeakTargetWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = E642661F1A855DA8006C6B2F /* SILWeakTargetWrapper.m */; }; - 0C2FCB0F1F9A542300F4F259 /* SILAlertBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 07A9563E1BDD40CB0028D333 /* SILAlertBarView.m */; }; 0C2FCB101F9A542300F4F259 /* SILBeaconRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = E6CCCFEB1A73040C0004B2F4 /* SILBeaconRegistry.m */; }; 0C2FCB111F9A542300F4F259 /* SILDebugServiceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 07B8A8CF1BCD6E3B001948C1 /* SILDebugServiceTableViewCell.m */; }; 0C2FCB121F9A542300F4F259 /* SILDebugAdvDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 078138461BE99502001EFE7E /* SILDebugAdvDetailsViewController.m */; }; @@ -282,7 +280,6 @@ 0F4E50FF21525FDC00F58ACE /* SILBluetoothModelManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 07BBA74D1BD5858F00C2B07E /* SILBluetoothModelManager.m */; }; 0F4E510021525FDC00F58ACE /* SILSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = E607A3501A8D4FD100DAAFD3 /* SILSettings.m */; }; 0F4E510121525FDC00F58ACE /* SILWeakTargetWrapper.m in Sources */ = {isa = PBXBuildFile; fileRef = E642661F1A855DA8006C6B2F /* SILWeakTargetWrapper.m */; }; - 0F4E510221525FDC00F58ACE /* SILAlertBarView.m in Sources */ = {isa = PBXBuildFile; fileRef = 07A9563E1BDD40CB0028D333 /* SILAlertBarView.m */; }; 0F4E510321525FDC00F58ACE /* SILBeaconRegistry.m in Sources */ = {isa = PBXBuildFile; fileRef = E6CCCFEB1A73040C0004B2F4 /* SILBeaconRegistry.m */; }; 0F4E510421525FDC00F58ACE /* SILDebugServiceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 07B8A8CF1BCD6E3B001948C1 /* SILDebugServiceTableViewCell.m */; }; 0F4E510521525FDC00F58ACE /* SILDebugAdvDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 078138461BE99502001EFE7E /* SILDebugAdvDetailsViewController.m */; }; @@ -464,8 +461,14 @@ 1E113D08244ECD6600442752 /* SILDiscoveredPeripheralIdentifierProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E113D07244ECD6600442752 /* SILDiscoveredPeripheralIdentifierProvider.swift */; }; 1E1907B123FD850700DD014C /* SILSavedSearchesRealmModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E1907B023FD850700DD014C /* SILSavedSearchesRealmModel.m */; }; 1E1907B523FD8B9900DD014C /* SILBeaconTypeRealmModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E1907B423FD8B9900DD014C /* SILBeaconTypeRealmModel.m */; }; + 1E1A43C1246EA3CB0052DE8D /* SILAdTypeCBPeripheralDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1A43C0246EA3CB0052DE8D /* SILAdTypeCBPeripheralDecoder.swift */; }; + 1E1A43C324728F770052DE8D /* SILAdTypeEddystoneDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1A43C224728F770052DE8D /* SILAdTypeEddystoneDecoder.swift */; }; + 1E1AE4AE247FCB7F00E5F238 /* SILRealmConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E1AE4AD247FCB7F00E5F238 /* SILRealmConfiguration.swift */; }; 1E2D26D8244050430006B84A /* SILDocumentPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E2D26D7244050430006B84A /* SILDocumentPickerViewController.swift */; }; 1E2D9CAC23BA48D600816EC0 /* SILBluetoothBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E2D9CAB23BA48D600816EC0 /* SILBluetoothBrowserViewController.m */; }; + 1E48A1E92484E27300C188C0 /* SILAnimatedUIButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E48A1E82484E27300C188C0 /* SILAnimatedUIButton.swift */; }; + 1E48A1ED2484FBCF00C188C0 /* SILGattPropertiesErrorToastModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E48A1EC2484FBCF00C188C0 /* SILGattPropertiesErrorToastModel.swift */; }; + 1E48A1EF2484FC0B00C188C0 /* SILToastModelType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E48A1EE2484FC0B00C188C0 /* SILToastModelType.swift */; }; 1E4C37A42429095300C822E4 /* Roboto-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1E4C37A12429095300C822E4 /* Roboto-Bold.ttf */; }; 1E4C37A52429095300C822E4 /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1E4C37A22429095300C822E4 /* Roboto-Medium.ttf */; }; 1E4C37A62429095300C822E4 /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 1E4C37A32429095300C822E4 /* Roboto-Regular.ttf */; }; @@ -480,6 +483,14 @@ 1E6AF80123CDB32800EE8280 /* SILBrowserConnectionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E6AF80023CDB32800EE8280 /* SILBrowserConnectionsViewController.m */; }; 1E6AF80423CDB33600EE8280 /* SILBrowserFilterViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E6AF80323CDB33600EE8280 /* SILBrowserFilterViewController.m */; }; 1E70A97B240403320021C51B /* SILBrowserConnectionsViewModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E70A97A240403320021C51B /* SILBrowserConnectionsViewModel.m */; }; + 1E90F5E42473E73E0013AABD /* SILDebugServicesMenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E90F5E32473E73E0013AABD /* SILDebugServicesMenuViewController.swift */; }; + 1E90F5E72473E8340013AABD /* SILDebugServicesMenuTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E90F5E52473E8340013AABD /* SILDebugServicesMenuTableViewCell.swift */; }; + 1E90F5E82473E8340013AABD /* SILDebugServicesMenuTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1E90F5E62473E8340013AABD /* SILDebugServicesMenuTableViewCell.xib */; }; + 1E90F5EA2473EA650013AABD /* SILDebugServicesMenuViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E90F5E92473EA650013AABD /* SILDebugServicesMenuViewControllerDelegate.swift */; }; + 1E90F5EC24767C680013AABD /* UIViewController+Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E90F5EB24767C680013AABD /* UIViewController+Toast.swift */; }; + 1E90F5EE24767CC30013AABD /* SILDisconnectionToastModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E90F5ED24767CC30013AABD /* SILDisconnectionToastModel.swift */; }; + 1E90F5F12476C3C90013AABD /* SILKeychainInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E90F5EF2476C3C90013AABD /* SILKeychainInfoViewController.swift */; }; + 1E90F5F42477B1D00013AABD /* SILKeychainInfoViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1E90F5F32477B1D00013AABD /* SILKeychainInfoViewControllerDelegate.swift */; }; 1E93CDE423A8EBF90022640E /* SILUILabels.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E93CDE323A8EBF90022640E /* SILUILabels.m */; }; 1E93CDEA23A91FA20022640E /* SILAppSelectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E93CDE923A91FA20022640E /* SILAppSelectionViewController.m */; }; 1E967BAF24041F3E00D89B48 /* SILConnectedPeripheralDataModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 1E967BAE24041F3E00D89B48 /* SILConnectedPeripheralDataModel.m */; }; @@ -557,7 +568,7 @@ 4C4F2DDF2407F603005D43BB /* SILBottomCornersCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4F2DDE2407F603005D43BB /* SILBottomCornersCell.swift */; }; 4C4F2DE124080E50005D43BB /* SILRoundedButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4F2DE024080E50005D43BB /* SILRoundedButton.swift */; }; 4C95EB7723FEC8600091FB5A /* SILAppBluetoothBrowserDetails.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4C95EB7623FEC8600091FB5A /* SILAppBluetoothBrowserDetails.storyboard */; }; - 4C97A51123E86525000C6894 /* SILBrowserServiceViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C97A51023E86525000C6894 /* SILBrowserServiceViewCell.swift */; }; + 4C97A51123E86525000C6894 /* SILBrowserDeviceAdTypeViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C97A51023E86525000C6894 /* SILBrowserDeviceAdTypeViewCell.swift */; }; 4C97A51323E87364000C6894 /* SILBrowserDeviceViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C97A51223E87364000C6894 /* SILBrowserDeviceViewCell.swift */; }; 4C97A51B23E88184000C6894 /* SILBrowserButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C97A51A23E88184000C6894 /* SILBrowserButton.swift */; }; 4C97A51D23E89534000C6894 /* SILBrowserDeviceViewCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C97A51C23E89534000C6894 /* SILBrowserDeviceViewCellDelegate.swift */; }; @@ -751,8 +762,6 @@ 078138571BE9B014001EFE7E /* SILTextFieldEntryCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SILTextFieldEntryCell.m; path = DebugApp/PopoverViewControllers/CharacteristicEncoding/SILTextFieldEntryCell.m; sourceTree = ""; }; 0797E34B1BF0071D0046EF0E /* SILTextFieldEntryCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = SILTextFieldEntryCell.xib; path = ../Base.lproj/Debug/Popover/SILTextFieldEntryCell.xib; sourceTree = ""; }; 0797E34C1BF0071D0046EF0E /* SILDebugCharacteristicEncodingViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = SILDebugCharacteristicEncodingViewController.xib; path = ../Base.lproj/Debug/Popover/SILDebugCharacteristicEncodingViewController.xib; sourceTree = ""; }; - 07A9563D1BDD40CB0028D333 /* SILAlertBarView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SILAlertBarView.h; sourceTree = ""; }; - 07A9563E1BDD40CB0028D333 /* SILAlertBarView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SILAlertBarView.m; sourceTree = ""; }; 07B1AD761BFD043000D4D454 /* SILBeaconViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SILBeaconViewModel.h; path = SiliconLabsApp/ViewModels/SILBeaconViewModel.h; sourceTree = SOURCE_ROOT; }; 07B1AD771BFD043000D4D454 /* SILBeaconViewModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SILBeaconViewModel.m; path = SiliconLabsApp/ViewModels/SILBeaconViewModel.m; sourceTree = SOURCE_ROOT; }; 07B1AD791BFD05CA00D4D454 /* SILBGBeaconViewModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SILBGBeaconViewModel.h; path = SiliconLabsApp/ViewModels/SILBGBeaconViewModel.h; sourceTree = SOURCE_ROOT; }; @@ -846,9 +855,15 @@ 1E1907B223FD851C00DD014C /* SILSavedSearchesRealmModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SILSavedSearchesRealmModel.h; sourceTree = ""; }; 1E1907B323FD8B8600DD014C /* SILBeaconTypeRealmModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SILBeaconTypeRealmModel.h; sourceTree = ""; }; 1E1907B423FD8B9900DD014C /* SILBeaconTypeRealmModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SILBeaconTypeRealmModel.m; sourceTree = ""; }; + 1E1A43C0246EA3CB0052DE8D /* SILAdTypeCBPeripheralDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILAdTypeCBPeripheralDecoder.swift; sourceTree = ""; }; + 1E1A43C224728F770052DE8D /* SILAdTypeEddystoneDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILAdTypeEddystoneDecoder.swift; sourceTree = ""; }; + 1E1AE4AD247FCB7F00E5F238 /* SILRealmConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILRealmConfiguration.swift; sourceTree = ""; }; 1E2D26D7244050430006B84A /* SILDocumentPickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILDocumentPickerViewController.swift; sourceTree = ""; }; 1E2D9CAA23BA48D600816EC0 /* SILBluetoothBrowserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SILBluetoothBrowserViewController.h; sourceTree = ""; }; 1E2D9CAB23BA48D600816EC0 /* SILBluetoothBrowserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SILBluetoothBrowserViewController.m; sourceTree = ""; }; + 1E48A1E82484E27300C188C0 /* SILAnimatedUIButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILAnimatedUIButton.swift; sourceTree = ""; }; + 1E48A1EC2484FBCF00C188C0 /* SILGattPropertiesErrorToastModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILGattPropertiesErrorToastModel.swift; sourceTree = ""; }; + 1E48A1EE2484FC0B00C188C0 /* SILToastModelType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILToastModelType.swift; sourceTree = ""; }; 1E4C37A12429095300C822E4 /* Roboto-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Bold.ttf"; sourceTree = ""; }; 1E4C37A22429095300C822E4 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = ""; }; 1E4C37A32429095300C822E4 /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = ""; }; @@ -875,6 +890,14 @@ 1E6AF80723CDB4DF00EE8280 /* SILBrowserFilterViewControllerDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SILBrowserFilterViewControllerDelegate.h; sourceTree = ""; }; 1E70A97A240403320021C51B /* SILBrowserConnectionsViewModel.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SILBrowserConnectionsViewModel.m; sourceTree = ""; }; 1E70A97C240403470021C51B /* SILBrowserConnectionsViewModel.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SILBrowserConnectionsViewModel.h; sourceTree = ""; }; + 1E90F5E32473E73E0013AABD /* SILDebugServicesMenuViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILDebugServicesMenuViewController.swift; sourceTree = ""; }; + 1E90F5E52473E8340013AABD /* SILDebugServicesMenuTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILDebugServicesMenuTableViewCell.swift; sourceTree = ""; }; + 1E90F5E62473E8340013AABD /* SILDebugServicesMenuTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SILDebugServicesMenuTableViewCell.xib; sourceTree = ""; }; + 1E90F5E92473EA650013AABD /* SILDebugServicesMenuViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILDebugServicesMenuViewControllerDelegate.swift; sourceTree = ""; }; + 1E90F5EB24767C680013AABD /* UIViewController+Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+Toast.swift"; sourceTree = ""; }; + 1E90F5ED24767CC30013AABD /* SILDisconnectionToastModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SILDisconnectionToastModel.swift; sourceTree = ""; }; + 1E90F5EF2476C3C90013AABD /* SILKeychainInfoViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILKeychainInfoViewController.swift; sourceTree = ""; }; + 1E90F5F32477B1D00013AABD /* SILKeychainInfoViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILKeychainInfoViewControllerDelegate.swift; sourceTree = ""; }; 1E93CDE223A8EBF90022640E /* SILUILabels.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SILUILabels.h; sourceTree = ""; }; 1E93CDE323A8EBF90022640E /* SILUILabels.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SILUILabels.m; sourceTree = ""; }; 1E93CDE823A91FA20022640E /* SILAppSelectionViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SILAppSelectionViewController.h; sourceTree = ""; }; @@ -998,7 +1021,7 @@ 4C4F2DDE2407F603005D43BB /* SILBottomCornersCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILBottomCornersCell.swift; sourceTree = ""; }; 4C4F2DE024080E50005D43BB /* SILRoundedButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILRoundedButton.swift; sourceTree = ""; }; 4C95EB7623FEC8600091FB5A /* SILAppBluetoothBrowserDetails.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = SILAppBluetoothBrowserDetails.storyboard; sourceTree = ""; }; - 4C97A51023E86525000C6894 /* SILBrowserServiceViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILBrowserServiceViewCell.swift; sourceTree = ""; }; + 4C97A51023E86525000C6894 /* SILBrowserDeviceAdTypeViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILBrowserDeviceAdTypeViewCell.swift; sourceTree = ""; }; 4C97A51223E87364000C6894 /* SILBrowserDeviceViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILBrowserDeviceViewCell.swift; sourceTree = ""; }; 4C97A51A23E88184000C6894 /* SILBrowserButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILBrowserButton.swift; sourceTree = ""; }; 4C97A51C23E89534000C6894 /* SILBrowserDeviceViewCellDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SILBrowserDeviceViewCellDelegate.swift; sourceTree = ""; }; @@ -1631,11 +1654,22 @@ path = BluetoothBrowser; sourceTree = ""; }; + 1E48A1F02484FCA300C188C0 /* Toast */ = { + isa = PBXGroup; + children = ( + 1E48A1EE2484FC0B00C188C0 /* SILToastModelType.swift */, + 1E90F5ED24767CC30013AABD /* SILDisconnectionToastModel.swift */, + 1E48A1EC2484FBCF00C188C0 /* SILGattPropertiesErrorToastModel.swift */, + ); + name = Toast; + sourceTree = ""; + }; 1E4C37D3242C992300C822E4 /* Utils */ = { isa = PBXGroup; children = ( 1E4C37D6242C997B00C822E4 /* SILBluetoothBrowserExpandableViewManager.h */, 1E4C37D4242C996400C822E4 /* SILBluetoothBrowserExpandableViewManager.m */, + 1E48A1E82484E27300C188C0 /* SILAnimatedUIButton.swift */, ); path = Utils; sourceTree = ""; @@ -1643,6 +1677,7 @@ 1E56E9ED24169C1A00D5B92A /* KeyChains */ = { isa = PBXGroup; children = ( + 1E90F5F52477B42D0013AABD /* Info */, 4C3BA288240D58DF00CF3268 /* SILKeychainViewController.swift */, 4C2CB438240E7C840079040D /* SILMapCell.swift */, 4CEE629C241276EC00D88354 /* SILCell.swift */, @@ -1657,6 +1692,9 @@ 49FB4BE91E7A2EC200223F3E /* SILPopoverViewController.h */, 49FB4BEA1E7A2EC200223F3E /* SILPopoverViewController.m */, 49FB4BEB1E7A2EC200223F3E /* SILPopoverViewController.xib */, + DCB4310F1E8315CE00EE94F0 /* SILOTAHUDView.h */, + DCB431101E8315CE00EE94F0 /* SILOTAHUDView.m */, + DCB431121E8315EF00EE94F0 /* SILOTAHUDView.xib */, 491ADCB91E71EEA300AC2E69 /* SILOTAUICoordinator.h */, 491ADCBA1E71EEA300AC2E69 /* SILOTAUICoordinator.m */, 491ADCBC1E72E58300AC2E69 /* SILOTASetupViewController.h */, @@ -1724,9 +1762,30 @@ path = Filter; sourceTree = ""; }; + 1E90F5E22473E7220013AABD /* Menu */ = { + isa = PBXGroup; + children = ( + 1E90F5E32473E73E0013AABD /* SILDebugServicesMenuViewController.swift */, + 1E90F5E52473E8340013AABD /* SILDebugServicesMenuTableViewCell.swift */, + 1E90F5E62473E8340013AABD /* SILDebugServicesMenuTableViewCell.xib */, + 1E90F5E92473EA650013AABD /* SILDebugServicesMenuViewControllerDelegate.swift */, + ); + path = Menu; + sourceTree = ""; + }; + 1E90F5F52477B42D0013AABD /* Info */ = { + isa = PBXGroup; + children = ( + 1E90F5EF2476C3C90013AABD /* SILKeychainInfoViewController.swift */, + 1E90F5F32477B1D00013AABD /* SILKeychainInfoViewControllerDelegate.swift */, + ); + path = Info; + sourceTree = ""; + }; 1EA0119223E08E7E003B3E62 /* Details */ = { isa = PBXGroup; children = ( + 1E90F5E22473E7220013AABD /* Menu */, 1E56E9EE24169C5B00D5B92A /* OTA */, 07B8A8AB1BCD4D6E001948C1 /* ServicesTable */, 4C9EAB4824042A7B0023FFB1 /* SILServiceCell.swift */, @@ -1845,7 +1904,7 @@ 4C97A51223E87364000C6894 /* SILBrowserDeviceViewCell.swift */, 4C97A51C23E89534000C6894 /* SILBrowserDeviceViewCellDelegate.swift */, 4C97A51A23E88184000C6894 /* SILBrowserButton.swift */, - 4C97A51023E86525000C6894 /* SILBrowserServiceViewCell.swift */, + 4C97A51023E86525000C6894 /* SILBrowserDeviceAdTypeViewCell.swift */, ); path = Views; sourceTree = ""; @@ -2052,6 +2111,7 @@ E621B3491A655AFE00223C5A /* DataModels */ = { isa = PBXGroup; children = ( + 1E48A1F02484FCA300C188C0 /* Toast */, 4C2CB42F240E59EC0079040D /* Mapping */, 4C2C6336240923C70080CE76 /* Browser */, 1E586CDD23FBFEB900E2C385 /* Filter */, @@ -2103,6 +2163,8 @@ 1E967BAE24041F3E00D89B48 /* SILConnectedPeripheralDataModel.m */, E6CCCFE81A73040C0004B2F4 /* SILBeacon.h */, E6CCCFE91A73040C0004B2F4 /* SILBeacon.m */, + 1E1A43C0246EA3CB0052DE8D /* SILAdTypeCBPeripheralDecoder.swift */, + 1E1A43C224728F770052DE8D /* SILAdTypeEddystoneDecoder.swift */, ); name = DataModels; path = Models; @@ -2111,6 +2173,7 @@ E63DD42E1A71449500E0040F /* Categories */ = { isa = PBXGroup; children = ( + 1E90F5EB24767C680013AABD /* UIViewController+Toast.swift */, 4924BA691E7057F800AE9E56 /* CBPeripheral+Services.h */, 4924BA6A1E7057F800AE9E56 /* CBPeripheral+Services.m */, 4924BA6C1E70585100AE9E56 /* CBService+Categories.h */, @@ -2177,6 +2240,7 @@ 1E93CDE323A8EBF90022640E /* SILUILabels.m */, DC380D4F1E8A9FAA00898C12 /* EXTKeyPathCoding.h */, DC380D501E8A9FFD00898C12 /* metamacros.h */, + 1E1AE4AD247FCB7F00E5F238 /* SILRealmConfiguration.swift */, ); path = Helpers; sourceTree = ""; @@ -2196,13 +2260,8 @@ children = ( 496A42F11E7C582F006E87F2 /* SILBigRedButton.h */, 496A42F21E7C582F006E87F2 /* SILBigRedButton.m */, - DCB4310F1E8315CE00EE94F0 /* SILOTAHUDView.h */, - DCB431101E8315CE00EE94F0 /* SILOTAHUDView.m */, - DCB431121E8315EF00EE94F0 /* SILOTAHUDView.xib */, E666CBE91A77C75400676C5C /* SILSegmentedControl.h */, E666CBEA1A77C75400676C5C /* SILSegmentedControl.m */, - 07A9563D1BDD40CB0028D333 /* SILAlertBarView.h */, - 07A9563E1BDD40CB0028D333 /* SILAlertBarView.m */, ); path = Views; sourceTree = ""; @@ -2549,6 +2608,7 @@ 0C2FCBB81F9A542300F4F259 /* SILDebugAdvDetailsViewController.xib in Resources */, 4C95EB7723FEC8600091FB5A /* SILAppBluetoothBrowserDetails.storyboard in Resources */, 0C2FCBB91F9A542300F4F259 /* SILRetailBeaconDetailsViewController.xib in Resources */, + 1E90F5E82473E8340013AABD /* SILDebugServicesMenuTableViewCell.xib in Resources */, 1EEE315823F57CED0076E731 /* SILSavedSearchesTableViewCell.xib in Resources */, 0C2FCBBB1F9A542300F4F259 /* SILDebugCharacteristicPropertyView.xib in Resources */, 0C2FCBBF1F9A542300F4F259 /* SILRetailBeaconAppViewController.xib in Resources */, @@ -2918,6 +2978,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1E90F5F42477B1D00013AABD /* SILKeychainInfoViewControllerDelegate.swift in Sources */, 1EEE315D23F58C210076E731 /* SILBrowserFilterBeaconTypeViewController.m in Sources */, 1E1907B123FD850700DD014C /* SILSavedSearchesRealmModel.m in Sources */, 1E56E9E92416934D00D5B92A /* SILBluetoothBrowser+Constants.m in Sources */, @@ -2927,6 +2988,7 @@ 0C2FCB051F9A542300F4F259 /* SILOTAUICoordinator.m in Sources */, 1E93CDE423A8EBF90022640E /* SILUILabels.m in Sources */, 0C2FCB061F9A542300F4F259 /* SILActivityBarViewController.m in Sources */, + 1E90F5EC24767C680013AABD /* UIViewController+Toast.swift in Sources */, 4D9E26212212BFB200617DBA /* SILRangeTestBoardFeatures.swift in Sources */, 1E2D26D8244050430006B84A /* SILDocumentPickerViewController.swift in Sources */, 1EEE315923F57CED0076E731 /* SILBeaconTypeTableViewCell.m in Sources */, @@ -2934,13 +2996,13 @@ 0C2FCB081F9A542300F4F259 /* SILAppearance.m in Sources */, 0C2FCB091F9A542300F4F259 /* SILDiscoveredPeripheralDisplayData.m in Sources */, 0C2FCB0A1F9A542300F4F259 /* SILBigRedButton.m in Sources */, + 1E90F5F12476C3C90013AABD /* SILKeychainInfoViewController.swift in Sources */, 0C2FCB0B1F9A542300F4F259 /* SILDebugCharacteristicTableViewCell.m in Sources */, 1E586CDB23FBF3FC00E2C385 /* SILBrowserBeaconType.m in Sources */, 0C2FCB0C1F9A542300F4F259 /* SILBluetoothModelManager.m in Sources */, 0C2FCB0D1F9A542300F4F259 /* SILSettings.m in Sources */, 0C2FCB0E1F9A542300F4F259 /* SILWeakTargetWrapper.m in Sources */, 1EA0118E23DB2431003B3E62 /* SILDemoNavigationViewController.m in Sources */, - 0C2FCB0F1F9A542300F4F259 /* SILAlertBarView.m in Sources */, 0C2FCB101F9A542300F4F259 /* SILBeaconRegistry.m in Sources */, 1EBC4E3D2452DFBF005B8767 /* CBAttribute+UUID.swift in Sources */, 4C126076241118A20086951A /* UIColor+SILColors.swift in Sources */, @@ -2956,6 +3018,7 @@ 1EE61D7124000D4900D7E1E5 /* SILLogDataModel.m in Sources */, 0C2FCB181F9A542300F4F259 /* SILBluetoothBitFieldModel.m in Sources */, 0C2FCB191F9A542300F4F259 /* SILDiscoveredPeripheralDisplayDataViewModel.m in Sources */, + 1E90F5EE24767CC30013AABD /* SILDisconnectionToastModel.swift in Sources */, 0C2FCB1A1F9A542300F4F259 /* SILDebugDeviceTableViewCell.m in Sources */, 0C2FCB1B1F9A542300F4F259 /* DebugDeviceFilterViewController.swift in Sources */, 1E56E9E52416800B00D5B92A /* NSString+SILBrowserNotifications.m in Sources */, @@ -2965,6 +3028,8 @@ 1EDCA5B323E1A8A800F78B14 /* SILBrowserLogTableViewCell.m in Sources */, 4C2CB43D240EBC550079040D /* SILMapNameEditorViewController.swift in Sources */, 0C2FCB1F1F9A542300F4F259 /* SILDoubleKeyDictionaryPair.m in Sources */, + 1E48A1ED2484FBCF00C188C0 /* SILGattPropertiesErrorToastModel.swift in Sources */, + 1E1A43C1246EA3CB0052DE8D /* SILAdTypeCBPeripheralDecoder.swift in Sources */, 1E586CE023FBFEF900E2C385 /* SILBrowserSavedSearches.m in Sources */, 4C4F2DDF2407F603005D43BB /* SILBottomCornersCell.swift in Sources */, 0C2FCB211F9A542300F4F259 /* SILBluetoothEnumerationModel.m in Sources */, @@ -3006,7 +3071,9 @@ 0C2FCB3D1F9A542300F4F259 /* SILApp+AttributedProfiles.m in Sources */, 1E70A97B240403320021C51B /* SILBrowserConnectionsViewModel.m in Sources */, 0C2FCB3E1F9A542300F4F259 /* SILOTAFirmwareFile.m in Sources */, + 1E90F5E42473E73E0013AABD /* SILDebugServicesMenuViewController.swift in Sources */, 0C2FCB3F1F9A542300F4F259 /* SILBitRowModel.m in Sources */, + 1E1A43C324728F770052DE8D /* SILAdTypeEddystoneDecoder.swift in Sources */, 0C2FCB401F9A542300F4F259 /* SILRetailBeaconDetailsViewController.m in Sources */, 0C2FCB411F9A542300F4F259 /* SILCollectionViewRightAlignedFlowLayout.m in Sources */, 0C2FCB421F9A542300F4F259 /* UIColor+SILColors.m in Sources */, @@ -3034,8 +3101,10 @@ 0C2FCB501F9A542300F4F259 /* SILRetailBeaconAppViewController.m in Sources */, 0C2FCB511F9A542300F4F259 /* SILBeaconDataViewModel.m in Sources */, 0C2FCB521F9A542300F4F259 /* SILOTAFirmwareUpdate.m in Sources */, + 1E90F5E72473E8340013AABD /* SILDebugServicesMenuTableViewCell.swift in Sources */, 0C2FCB531F9A542300F4F259 /* SILBodySensorLocation.m in Sources */, 0C2FCB541F9A542300F4F259 /* TextFieldTableViewCell.swift in Sources */, + 1E48A1E92484E27300C188C0 /* SILAnimatedUIButton.swift in Sources */, 0C08FD5820CB1CA90016CABC /* SILConnectedLightingViewController.m in Sources */, 0C2FCB551F9A542300F4F259 /* SILCharacteristicFieldBuilder.m in Sources */, 0C2FCB561F9A542300F4F259 /* SILApp.m in Sources */, @@ -3044,7 +3113,7 @@ 4C4F2DE124080E50005D43BB /* SILRoundedButton.swift in Sources */, 0C2FCB571F9A542300F4F259 /* UIFont+Extensions.swift in Sources */, 0C2FCB581F9A542300F4F259 /* SILDebugServicesViewController.m in Sources */, - 4C97A51123E86525000C6894 /* SILBrowserServiceViewCell.swift in Sources */, + 4C97A51123E86525000C6894 /* SILBrowserDeviceAdTypeViewCell.swift in Sources */, 4CEE629D241276EC00D88354 /* SILCell.swift in Sources */, 0C2FCB591F9A542300F4F259 /* SILBeacon.m in Sources */, 0C2FCB5B1F9A542300F4F259 /* SILOTAProgressViewModel.m in Sources */, @@ -3081,6 +3150,8 @@ 0C2FCB761F9A542300F4F259 /* SILEnumerationFieldRowModel.m in Sources */, 0C2FCB771F9A542300F4F259 /* Int+Extensions.swift in Sources */, 0C2FCB781F9A542300F4F259 /* UIImage+SILHelpers.m in Sources */, + 1E1AE4AE247FCB7F00E5F238 /* SILRealmConfiguration.swift in Sources */, + 1E48A1EF2484FC0B00C188C0 /* SILToastModelType.swift in Sources */, 1E2D9CAC23BA48D600816EC0 /* SILBluetoothBrowserViewController.m in Sources */, 0C2FCB791F9A542300F4F259 /* SILOTAHUDView.m in Sources */, 0C2FCB7A1F9A542300F4F259 /* SILServiceTableModel.m in Sources */, @@ -3095,6 +3166,7 @@ 0C2FCB841F9A542300F4F259 /* DebugDeviceViewModel.swift in Sources */, 0C2FCB851F9A542300F4F259 /* SILDebugPopoverViewController.m in Sources */, 0C2FCB861F9A542300F4F259 /* SILRSSIMeasurement.m in Sources */, + 1E90F5EA2473EA650013AABD /* SILDebugServicesMenuViewControllerDelegate.swift in Sources */, 0C2FCB871F9A542300F4F259 /* SILIBeaconViewModel.m in Sources */, 4C2CB435240E725C0079040D /* SILMap.swift in Sources */, 0C2FCB891F9A542300F4F259 /* SILBluetoothBitModel.m in Sources */, @@ -3134,7 +3206,6 @@ 0F4E50FF21525FDC00F58ACE /* SILBluetoothModelManager.m in Sources */, 0F4E510021525FDC00F58ACE /* SILSettings.m in Sources */, 0F4E510121525FDC00F58ACE /* SILWeakTargetWrapper.m in Sources */, - 0F4E510221525FDC00F58ACE /* SILAlertBarView.m in Sources */, 0F4E510321525FDC00F58ACE /* SILBeaconRegistry.m in Sources */, 0F4E510421525FDC00F58ACE /* SILDebugServiceTableViewCell.m in Sources */, 0F4E510521525FDC00F58ACE /* SILDebugAdvDetailsViewController.m in Sources */, @@ -3284,7 +3355,6 @@ 07BBA74E1BD5858F00C2B07E /* SILBluetoothModelManager.m in Sources */, E607A3511A8D4FD100DAAFD3 /* SILSettings.m in Sources */, E64266201A855DA8006C6B2F /* SILWeakTargetWrapper.m in Sources */, - 07A9563F1BDD40CB0028D333 /* SILAlertBarView.m in Sources */, E6CCCFF11A73040C0004B2F4 /* SILBeaconRegistry.m in Sources */, 07B8A8D41BCD6E3B001948C1 /* SILDebugServiceTableViewCell.m in Sources */, 078138491BE99502001EFE7E /* SILDebugAdvDetailsViewController.m in Sources */, @@ -3489,7 +3559,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_RESOURCE_RULES_PATH = ""; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 23; + CURRENT_PROJECT_VERSION = 24; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 52444FG85C; DISPLAY_NAME = "EFR Connect"; @@ -3499,7 +3569,7 @@ INFOPLIST_FILE = "$(SRCROOT)/SiliconLabsApp/SupportingFiles/BlueGecko/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 2.0.2; + MARKETING_VERSION = 2.0.3; PRODUCT_BUNDLE_IDENTIFIER = com.silabs.BlueGeckoDemoApp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Blue Gecko Development"; @@ -3523,7 +3593,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_RESOURCE_RULES_PATH = ""; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 23; + CURRENT_PROJECT_VERSION = 24; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = 52444FG85C; DISPLAY_NAME = "EFR Connect"; @@ -3532,7 +3602,7 @@ INFOPLIST_FILE = "$(SRCROOT)/SiliconLabsApp/SupportingFiles/BlueGecko/Info.plist"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; - MARKETING_VERSION = 2.0.2; + MARKETING_VERSION = 2.0.3; PRODUCT_BUNDLE_IDENTIFIER = com.silabs.BlueGeckoDemoApp; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = "Blue Gecko Development"; diff --git a/SiliconLabsApp/BluetoothControllers/SILCentralManager.m b/SiliconLabsApp/BluetoothControllers/SILCentralManager.m index 7fbcd490..ddd9c3ab 100644 --- a/SiliconLabsApp/BluetoothControllers/SILCentralManager.m +++ b/SiliconLabsApp/BluetoothControllers/SILCentralManager.m @@ -378,31 +378,30 @@ - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(C [self removeUnfiredConnectionTimeoutTimer]; [self handleConnectionFailureWithError:error]; [self postRegisterLogNotification:[SILLogDataModel prepareLogDescription:@"didFailToConnectPeripheral: " andPeripheral:peripheral andError:error]]; + [self postFailedToConnectPeripheral:peripheral andError:error]; } - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"didDisconnectPeripheral: %@", peripheral.name); NSLog(@"error: %@", error); - if (self.connectedPeripheral && [self.connectedPeripheral isEqual:peripheral]) { - self.connectedPeripheral = nil; - - NSMutableDictionary *userInfo = nil; - if(self.disconnectingPeripheral) { - self.disconnectingPeripheral = nil; - } else { - userInfo = [NSMutableDictionary dictionary]; - userInfo[SILCentralManagerPeripheralKey] = peripheral; - if (error) { - userInfo[SILCentralManagerErrorKey] = error; - } - } - - [[NSNotificationCenter defaultCenter] postNotificationName:SILCentralManagerDidDisconnectPeripheralNotification - object:self - userInfo:userInfo]; + + BOOL wasConnected = [self.connectionsViewModel isConnectedPeripheral:peripheral]; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[SILCentralManagerPeripheralKey] = peripheral; + userInfo[SILNotificationKeyUUID] = peripheral.identifier.UUIDString; + if (error) { + userInfo[SILCentralManagerErrorKey] = error; } + + [[NSNotificationCenter defaultCenter] postNotificationName:SILCentralManagerDidDisconnectPeripheralNotification + object:self + userInfo:userInfo]; [self postRegisterLogNotification:[SILLogDataModel prepareLogDescription:@"didDisconnectPeripheral: " andPeripheral:peripheral andError:error]]; - [self postDeleteDisconnectedPeripheral:peripheral]; + if (wasConnected) { + [self postDeleteDisconnectedPeripheral:peripheral andError:error]; + } else { + [self postFailedToConnectPeripheral:peripheral andError:error]; + } } #pragma mark - Notifications @@ -446,11 +445,29 @@ - (void)removeScanForPeripheralsObserver:(id)observer { } - (void)postRegisterLogNotification:(NSString*)description { - [[NSNotificationCenter defaultCenter] postNotificationName:SILNotificationRegisterLog object:self userInfo:@{ SILNotificationKeyDescription : description}]; + [[NSNotificationCenter defaultCenter] postNotificationName:SILNotificationRegisterLog + object:self + userInfo:@{ + SILNotificationKeyDescription : description + }]; } -- (void)postDeleteDisconnectedPeripheral:(CBPeripheral*)peripheral { - [[NSNotificationCenter defaultCenter] postNotificationName:SILNotificationDeleteDisconnectedPeripheral object:self userInfo:@{ SILNotificationKeyUUID: peripheral.identifier.UUIDString}]; +- (void)postDeleteDisconnectedPeripheral:(CBPeripheral*)peripheral andError:(NSError*)error { + [[NSNotificationCenter defaultCenter] postNotificationName:SILNotificationDeleteDisconnectedPeripheral + object:self + userInfo:@{ + SILNotificationKeyUUID: peripheral.identifier.UUIDString, + SILNotificationKeyError: [NSString stringWithFormat:@"%ld", (long)error.code] + }]; +} + +- (void)postFailedToConnectPeripheral:(CBPeripheral*)peripheral andError:(NSError*)error { + [[NSNotificationCenter defaultCenter] postNotificationName:SILNotificationFailedToConnectPeripheral + object:self + userInfo:@{ + SILNotificationKeyPeripheralName: peripheral.name, + SILNotificationKeyError: [NSString stringWithFormat:@"%ld", (long)error.code] + }]; } #pragma mark - CLLocationManagerDelegate diff --git a/SiliconLabsApp/BluetoothControllers/SILDiscoveredPeripheral.h b/SiliconLabsApp/BluetoothControllers/SILDiscoveredPeripheral.h index e19cc5b7..6e163aa3 100644 --- a/SiliconLabsApp/BluetoothControllers/SILDiscoveredPeripheral.h +++ b/SiliconLabsApp/BluetoothControllers/SILDiscoveredPeripheral.h @@ -28,9 +28,11 @@ @property (strong, nonatomic) CBPeripheral *peripheral; @property (strong, nonatomic) SILRSSIMeasurementTable *RSSIMeasurementTable; @property (strong, nonatomic) NSString *advertisedLocalName; -@property (strong, nonatomic) NSArray *advertisedServiceUUIDs; +@property (strong, nonatomic) NSArray* advertisedServiceUUIDs; @property (strong, nonatomic) NSNumber *txPowerLevel; @property (strong, nonatomic) NSData *manufacturerData; +@property (strong, nonatomic) NSArray* solicitedServiceUUIDs; +@property (strong, nonatomic) NSDictionary* dataServiceData; @property (strong, nonatomic) SILBeacon* beacon; @property (nonatomic) BOOL isFavourite; @property double advertisingInterval; diff --git a/SiliconLabsApp/BluetoothControllers/SILDiscoveredPeripheral.m b/SiliconLabsApp/BluetoothControllers/SILDiscoveredPeripheral.m index 99393ccc..ad2de167 100644 --- a/SiliconLabsApp/BluetoothControllers/SILDiscoveredPeripheral.m +++ b/SiliconLabsApp/BluetoothControllers/SILDiscoveredPeripheral.m @@ -24,7 +24,7 @@ @implementation SILDiscoveredPeripheral NSString* const RSSIAppendingString = @" RSSI"; NSString* const ConnectableDevice = @"Connectable"; NSString* const NonConnectableDevice = @"Non-connectable"; - +NSString* const EddystoneService = @"FEAA"; + (NSString *)connectableDevice { return ConnectableDevice; } + (NSString *)nonConnectableDevice { return NonConnectableDevice; } @@ -51,13 +51,15 @@ - (instancetype)initWithPeripheral:(CBPeripheral *)peripheral - (void)updateWithAdvertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI andDiscoveringTimestamp:(double)timestamp { - self.advertisedLocalName = advertisementData[CBAdvertisementDataLocalNameKey] ?: self.peripheral.name; + self.advertisedLocalName = advertisementData[CBAdvertisementDataLocalNameKey]; self.advertisedServiceUUIDs = advertisementData[CBAdvertisementDataServiceUUIDsKey]; self.txPowerLevel = advertisementData[CBAdvertisementDataTxPowerLevelKey]; if (!self.isConnectable) { self.isConnectable = [advertisementData[CBAdvertisementDataIsConnectable] boolValue]; } self.manufacturerData = advertisementData[CBAdvertisementDataManufacturerDataKey]; + self.solicitedServiceUUIDs = advertisementData[CBAdvertisementDataSolicitedServiceUUIDsKey]; + self.dataServiceData = advertisementData[CBAdvertisementDataServiceDataKey]; self.beacon = [self parseBeaconData:advertisementData]; if ([self isCorrectAdvertisingPacket:timestamp]) { self.packetReceivedCount++; @@ -112,6 +114,9 @@ - (SILBeacon*)parseBeaconData:(NSDictionary*)adverisement { if (error == nil) { return beacon; } + } else if ([self hasEddystoneService]) { + SILBeacon* eddystoneBeacon = [SILBeacon beaconWithEddystone:self.dataServiceData[[CBUUID UUIDWithString:EddystoneService]]]; + return eddystoneBeacon; } SILBeacon* unknownBeacon = [[SILBeacon alloc] init]; @@ -180,6 +185,10 @@ - (BOOL)isRangeTest { return [self isContainService:SILServiceNumberRangeTest]; } +- (BOOL)hasEddystoneService { + return [self isContainService:EddystoneService]; +} + - (BOOL)isContainService:(NSString *)serviceUUID { CBUUID * const service = [CBUUID UUIDWithString:serviceUUID]; return [self.advertisedServiceUUIDs containsObject:service]; diff --git a/SiliconLabsApp/Categories/CBService+Categories.m b/SiliconLabsApp/Categories/CBService+Categories.m index 5320467d..61c77c1e 100644 --- a/SiliconLabsApp/Categories/CBService+Categories.m +++ b/SiliconLabsApp/Categories/CBService+Categories.m @@ -27,7 +27,7 @@ - (BOOL)hasOTADataCharacteristic { } - (CBCharacteristic *)otaDataCharacteristic { - return [self characteristicForUUID:[SILUUIDProvider sharedProvider].otaCharacteristicDataUUID]; + return [self characteristicForUUID:[SILUUIDProvider sharedProvider].otaCharacteristicOTADataAttributeUUID]; } - (BOOL)hasOTAControlCharacteristic { @@ -35,7 +35,7 @@ - (BOOL)hasOTAControlCharacteristic { } - (CBCharacteristic *)otaControlCharacteristic { - return [self characteristicForUUID:[SILUUIDProvider sharedProvider].otaCharacteristicControlUUID]; + return [self characteristicForUUID:[SILUUIDProvider sharedProvider].otaCharacteristicOTAControlAttributeUUID]; } @end diff --git a/SiliconLabsApp/Categories/NSString+SILBrowserNotifications.h b/SiliconLabsApp/Categories/NSString+SILBrowserNotifications.h index 808ecd9e..f0e59caa 100644 --- a/SiliconLabsApp/Categories/NSString+SILBrowserNotifications.h +++ b/SiliconLabsApp/Categories/NSString+SILBrowserNotifications.h @@ -20,8 +20,13 @@ extern NSString * const SILNotificationReloadLogTableView; extern NSString * const SILNotificationDisconnectPeripheral; extern NSString * const SILNotificationDeleteDisconnectedPeripheral; extern NSString * const SILNotificationDisconnectAllPeripheral; +extern NSString * const SILNotificationFailedToConnectPeripheral; extern NSString * const SILNotificationCellsForVisibleRows; +extern NSString * const SILNotificationDisplayToastRequest; +extern NSString * const SILNotificationDisplayToastResponse; extern NSString * const SILNotificationKeyIndex; extern NSString * const SILNotificationKeyUUID; extern NSString * const SILNotificationKeyDescription; +extern NSString * const SILNotificationKeyError; +extern NSString * const SILNotificationKeyPeripheralName; diff --git a/SiliconLabsApp/Categories/NSString+SILBrowserNotifications.m b/SiliconLabsApp/Categories/NSString+SILBrowserNotifications.m index 04be4dd9..baa84b77 100644 --- a/SiliconLabsApp/Categories/NSString+SILBrowserNotifications.m +++ b/SiliconLabsApp/Categories/NSString+SILBrowserNotifications.m @@ -19,9 +19,14 @@ NSString * const SILNotificationReloadLogTableView = @"ReloadLogTableView"; NSString * const SILNotificationDisconnectPeripheral = @"DisconnectPeripheral"; NSString * const SILNotificationDeleteDisconnectedPeripheral = @"DeleteDisconnectedPeripheral"; +NSString * const SILNotificationFailedToConnectPeripheral = @"FailedToConnectPeripheral"; NSString * const SILNotificationDisconnectAllPeripheral = @"DisconnectAllPeripheral"; NSString * const SILNotificationCellsForVisibleRows = @"CellsForVisibleRows"; +NSString * const SILNotificationDisplayToastRequest = @"DisplayToastRequest"; +NSString * const SILNotificationDisplayToastResponse = @"DisplayToastResponse"; NSString * const SILNotificationKeyIndex = @"index"; NSString * const SILNotificationKeyUUID = @"uuid"; NSString * const SILNotificationKeyDescription = @"description"; +NSString * const SILNotificationKeyError = @"error"; +NSString * const SILNotificationKeyPeripheralName = @"peripheralName"; diff --git a/SiliconLabsApp/Categories/UIImage+SILImages.h b/SiliconLabsApp/Categories/UIImage+SILImages.h index 016c76fd..0ff97a95 100644 --- a/SiliconLabsApp/Categories/UIImage+SILImages.h +++ b/SiliconLabsApp/Categories/UIImage+SILImages.h @@ -76,6 +76,10 @@ extern NSString * const SILImageConnectOff; extern NSString * const SILImageConnectOn; extern NSString * const SILImageSearchOff; extern NSString * const SILImageSearchOn; +extern NSString * const SILImageFilterOff; +extern NSString * const SILImageFilterOffSelected; +extern NSString * const SILImageFilterOn; +extern NSString * const SILImageFilterOnSelected; extern NSString * const SILImageConnectable; extern NSString * const SILImageRSSI; extern NSString * const SILImageBeacon; diff --git a/SiliconLabsApp/Categories/UIImage+SILImages.m b/SiliconLabsApp/Categories/UIImage+SILImages.m index fb9d1143..51c74127 100644 --- a/SiliconLabsApp/Categories/UIImage+SILImages.m +++ b/SiliconLabsApp/Categories/UIImage+SILImages.m @@ -76,12 +76,16 @@ NSString * const SILImageConnectOn = @"connectOn"; NSString * const SILImageSearchOff = @"searchOff"; NSString * const SILImageSearchOn = @"searchOn"; +NSString * const SILImageFilterOff = @"filterOff"; +NSString * const SILImageFilterOffSelected = @"filterOffSelected"; +NSString * const SILImageFilterOn = @"filterOnActive"; +NSString * const SILImageFilterOnSelected = @"filterOnActiveSelected"; NSString * const SILImageConnectable = @"connectable"; NSString * const SILImageRSSI = @"rssi"; -NSString * const SILImageBeacon = @"beacon"; +NSString * const SILImageBeacon = @"beaconDark"; NSString * const SILImageFavouriteOff = @"favouriteOff"; NSString * const SILImageFavouriteOn = @"favouriteOn"; -NSString * const SILImageLoading = @"BTStrong"; +NSString * const SILImageLoading = @"loading pulse"; NSString * const SILImageEmptyView = @"debug_not_found"; NSString * const SILImageExitView = @"exitView"; NSString * const SILImageChevronCollapsed = @"chevron_collapsed"; diff --git a/SiliconLabsApp/Categories/UIViewController+Toast.swift b/SiliconLabsApp/Categories/UIViewController+Toast.swift new file mode 100644 index 00000000..031a1973 --- /dev/null +++ b/SiliconLabsApp/Categories/UIViewController+Toast.swift @@ -0,0 +1,57 @@ +// +// UIViewController+Toast.swift +// BlueGecko +// +// Created by Kamil Czajka on 11/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation + +@objc +public enum ToastType: Int { + case disconnectionError + case gattPropertiesError +} + +@objc +extension UIViewController { + @objc + func showToast(message : String, toastType: ToastType, completion: @escaping () -> ()) { + let values = displayParameters(for: toastType) + let AnimationDuration = 0.5 + let AnimationDelay = values.delay + let ToastHeight: CGFloat = values.height + let ToastMargin: CGFloat = 16.0 + let ToastBottomSpacing: CGFloat = values.bottomSpacing + let toastLabel = UILabel(frame: CGRect(x: ToastMargin, y: self.view.frame.size.height - ToastBottomSpacing, width: self.view.frame.size.width - 2 * ToastMargin, height: ToastHeight)) + toastLabel.backgroundColor = values.backgroundColor.withAlphaComponent(0.8) + toastLabel.textColor = UIColor.white + toastLabel.font = UIFont.robotoMedium(size: 14.0) + toastLabel.textAlignment = .center + toastLabel.numberOfLines = 0 + toastLabel.text = message + toastLabel.alpha = 1.0 + toastLabel.layer.cornerRadius = CornerRadiusStandardValue + toastLabel.clipsToBounds = true + self.view.addSubview(toastLabel) + UIView.animate(withDuration: AnimationDuration, delay: AnimationDelay, options: .curveEaseOut, animations: { + toastLabel.alpha = 0.0 + }, completion: {(isCompleted) in + toastLabel.removeFromSuperview() + completion() + }) + } + + @nonobjc + private func displayParameters(for toastType: ToastType) -> (delay: Double, height: CGFloat, bottomSpacing: CGFloat, backgroundColor: UIColor) { + switch toastType { + case .disconnectionError: + return (3.0, 60.0, 130.0, UIColor.sil_siliconLabsRed()) + case .gattPropertiesError: + return (3.0, 60.0, 65.0, UIColor.sil_siliconLabsRed()) + @unknown default: + return (0.0, 0.0, 0.0, .white) + } + } +} diff --git a/SiliconLabsApp/Helpers/SILRealmConfiguration.swift b/SiliconLabsApp/Helpers/SILRealmConfiguration.swift new file mode 100644 index 00000000..9005722a --- /dev/null +++ b/SiliconLabsApp/Helpers/SILRealmConfiguration.swift @@ -0,0 +1,77 @@ +// +// SILRealmConfiguration.swift +// BlueGecko +// +// Created by Kamil Czajka on 28/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation +import RealmSwift + +class SILRealmConfiguration : NSObject { + // Initial version of database + static let SchemeVersionEFR_2_0_0: UInt64 = 0 + + // Updated: + // - removed mappings for OTA characteristics, they already have names the same as in document AN1086, page 10 + // - removed mappings for missing services from Generic Access Profile (https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/) + // - removed "search by raw advertising data" from Saved Searches's objects + static let SchemeVersionEFR_2_0_3: UInt64 = 1 + + @objc + static func updateRealmConfigurationIfNeeded() { + let configuration = Realm.Configuration( + schemaVersion: SILRealmConfiguration.SchemeVersionEFR_2_0_3, + migrationBlock: { migration, oldSchemeVersion in + if oldSchemeVersion < SILRealmConfiguration.SchemeVersionEFR_2_0_3 { + SILRealmConfiguration.performUpdateDatabaseForEFR_2_0_3(migration: migration) + } + } + ) + Realm.Configuration.defaultConfiguration = configuration + } + + private static func performUpdateDatabaseForEFR_2_0_3(migration: Migration) { + func migrateServiceMappings() { + let servicesUUIDMappingsToRemove = [ + "1827", + "1826", + "183A", + "1820", + "1828", + "1829" + ] + + migration.enumerateObjects(ofType: "SILServiceMap") { oldObject, _ in + if let oldObject = oldObject, + let uuid = oldObject["uuid"] as? String, + servicesUUIDMappingsToRemove.contains(uuid) { + migration.delete(oldObject) + } + } + } + + func migrateCharacteristicMappings() { + let characteristicsUUIDMappingsToRemove = [ + "F7BF3564-FB6D-4E53-88A4-5E37E0326063", + "984227F3-34FC-4045-A5D0-2C581F81A153", + "4F4A2368-8CCA-451E-BFFF-CF0E2EE23E9F", + "4CC07BCF-0868-4B32-9DAD-BA4CC41E5316", + "25F05C0A-E917-46E9-B2A5-AA2BE1245AFE", + "0D77CC11-4AC1-49F2-BFA9-CD96AC7A92F8" + ] + + migration.enumerateObjects(ofType: "SILCharacteristicMap") { oldObject, _ in + if let oldObject = oldObject, + let uuid = oldObject["uuid"] as? String, + characteristicsUUIDMappingsToRemove.contains(uuid) { + migration.delete(oldObject) + } + } + } + + migrateServiceMappings() + migrateCharacteristicMappings() + } +} diff --git a/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILBitRowModel.m b/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILBitRowModel.m index 4c5b0e0e..0eea175f 100644 --- a/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILBitRowModel.m +++ b/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILBitRowModel.m @@ -47,6 +47,10 @@ - (NSString *)secondaryTitle { return self.fieldModel.name; } +- (void)clearValues { + self.toggleValue = @""; +} + //@discussion current implementation has this called by SILBitFieldFieldModel, which handles correct length - (NSInteger)consumeValue:(NSData *)value fromIndex:(NSInteger)index { diff --git a/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILEnumerationFieldRowModel.m b/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILEnumerationFieldRowModel.m index fdf42855..9509139d 100644 --- a/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILEnumerationFieldRowModel.m +++ b/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILEnumerationFieldRowModel.m @@ -49,6 +49,10 @@ - (NSString *)secondaryTitle { return self.fieldModel.name; } +- (void)clearValues { + [self consumeValue:[[NSData alloc] init] fromIndex:0]; +} + - (NSInteger)consumeValue:(NSData *)value fromIndex:(NSInteger)index { if (self.fieldModel.format) { NSData *fieldData = [[SILCharacteristicFieldValueResolver sharedResolver] subsectionOfData:value fromIndex:index forFormat:self.fieldModel.format]; diff --git a/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILValueFieldRowModel.m b/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILValueFieldRowModel.m index ab878faa..a08dd283 100644 --- a/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILValueFieldRowModel.m +++ b/SiliconLabsApp/Models/AttributeTableModels/FieldRows/SILValueFieldRowModel.m @@ -42,6 +42,10 @@ - (NSString *)secondaryTitle { return self.fieldModel.name; } +- (void)clearValues { + self.primaryValue = @""; +} + - (NSInteger)consumeValue:(NSData *)value fromIndex:(NSInteger)index { SILCharacteristicFieldValueResolver * const valueResolver = [SILCharacteristicFieldValueResolver sharedResolver]; NSData * const fieldData = [valueResolver subsectionOfData:value fromIndex:index forFormat:self.fieldModel.format]; diff --git a/SiliconLabsApp/Models/AttributeTableModels/SILCharacteristicTableModel.h b/SiliconLabsApp/Models/AttributeTableModels/SILCharacteristicTableModel.h index ae54bd9d..6118af0c 100644 --- a/SiliconLabsApp/Models/AttributeTableModels/SILCharacteristicTableModel.h +++ b/SiliconLabsApp/Models/AttributeTableModels/SILCharacteristicTableModel.h @@ -33,5 +33,7 @@ - (void)writeIfAllowedToPeripheral:(CBPeripheral *)peripheral error:(NSError * __autoreleasing *)error; - (NSData *)dataToWriteWithError:(NSError * __autoreleasing *)error; - (void)readCharacteristicIfAllowed; +- (BOOL)clearModel; +- (void)expandFieldIfNeeded; @end diff --git a/SiliconLabsApp/Models/AttributeTableModels/SILCharacteristicTableModel.m b/SiliconLabsApp/Models/AttributeTableModels/SILCharacteristicTableModel.m index 2e33da35..c9650295 100644 --- a/SiliconLabsApp/Models/AttributeTableModels/SILCharacteristicTableModel.m +++ b/SiliconLabsApp/Models/AttributeTableModels/SILCharacteristicTableModel.m @@ -14,6 +14,7 @@ #import "SILUUIDProvider.h" #import "SILLogDataModel.h" #import "BlueGecko.pch" +#import "SILEncodingPseudoFieldRowModel.h" #import @@ -84,6 +85,10 @@ - (void)toggleExpansionIfAllowed { self.isExpanded = !self.isExpanded; } +- (void)expandFieldIfNeeded { + self.isExpanded = YES; +} + - (NSString *)hexUuidString { return [self.characteristic getHexUuidValue]; } @@ -205,4 +210,15 @@ - (void)postRegisterLogNotification:(NSString*)description { [[NSNotificationCenter defaultCenter] postNotificationName:@"RegisterLog" object:self userInfo:@{ @"description" : description}]; } +- (BOOL)clearModel { + if (self.isUnknown) { + return NO; + } + for (id fieldRow in self.fieldTableRowModels) { + [fieldRow clearValues]; + } + + return YES; +} + @end diff --git a/SiliconLabsApp/Models/SILAdTypeCBPeripheralDecoder.swift b/SiliconLabsApp/Models/SILAdTypeCBPeripheralDecoder.swift new file mode 100644 index 00000000..3710cf60 --- /dev/null +++ b/SiliconLabsApp/Models/SILAdTypeCBPeripheralDecoder.swift @@ -0,0 +1,315 @@ +// +// SILAdTypeCBPeripheralDecoder.swift +// BlueGecko +// +// Created by Kamil Czajka on 15/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation + +class SILAdTypeCBPeripheralDecoder : NSObject { + private let peripheral: SILDiscoveredPeripheral + + @objc + init(peripheral: SILDiscoveredPeripheral) { + self.peripheral = peripheral + } + + @objc + func decode() -> [SILAdvertisementDataModel] { + var advertisementDataModels = [SILAdvertisementDataModel]() + + if peripheral.advertisedServiceUUIDs != nil { + advertisementDataModels += decodeAdvertisedSericeUUIDs() + } + + if peripheral.solicitedServiceUUIDs != nil { + advertisementDataModels += decodeSolicitedServiceUUIDs() + } + + if peripheral.txPowerLevel != nil { + if let txPowerLevelModel = SILAdvertisementDataModel(value: decodeTXPowerLevel(), type: .txPowerLevel) { + advertisementDataModels.append(txPowerLevelModel) + } + } + + if peripheral.advertisedLocalName != nil { + if let advertisementLocalNameModel = SILAdvertisementDataModel(value: decodeAdvertisementLocalName(), type: .completeLocalName) { + advertisementDataModels.append(advertisementLocalNameModel) + } + } + + if peripheral.manufacturerData != nil { + if let manufacturerDataModel = SILAdvertisementDataModel(value: decodeManufacturerData(), type: .manufacturerData) { + advertisementDataModels.append(manufacturerDataModel) + } + } + + if peripheral.dataServiceData != nil { + if let dataServiceDataModel = SILAdvertisementDataModel(value: decodeDataServiceData(), type: .dataServiceData) { + advertisementDataModels.append(dataServiceDataModel) + } + } + + if peripheral.beacon.type == .altBeacon { + if let altBeaconDataModel = SILAdvertisementDataModel(value: decodeAltBeaconData(), type: .altBeacon) { + advertisementDataModels.append(altBeaconDataModel) + } + } + + if peripheral.beacon.type == .eddystone { + let eddystoneDecoder = SILAdTypeEddystoneDecoder(eddystoneData: peripheral.beacon.eddystoneData) + let eddystoneDataModel = eddystoneDecoder.decode() + advertisementDataModels.append(eddystoneDataModel) + } + + return advertisementDataModels + } + + private func decodeAdvertisedSericeUUIDs() -> [SILAdvertisementDataModel] { + var advertisedServicesDataModels = [SILAdvertisementDataModel]() + let splitServicesArray = splitServices(services: peripheral.advertisedServiceUUIDs) + + if !splitServicesArray[0].isEmpty { + if let advertisedServiceUUIDsModel = SILAdvertisementDataModel(value: decodeAdvertisedServiceUUIDs16Bit(services16Bit: splitServicesArray[0]), type: .advertisedServiceUUIDs16Bit) { + advertisedServicesDataModels.append(advertisedServiceUUIDsModel) + } + } + + if !splitServicesArray[1].isEmpty { + if let advertisedServiceUUIDsModel = SILAdvertisementDataModel(value: decodeAdvertisedServiceUUIDs32Bit(services32Bit: splitServicesArray[1]), type: .advertisedServiceUUIDs32Bit) { + advertisedServicesDataModels.append(advertisedServiceUUIDsModel) + } + } + + if !splitServicesArray[2].isEmpty { + if let advertisedServiceUUIDsModel = SILAdvertisementDataModel(value: decodeAdvertisedServiceUUIDs128Bit(services128Bit: splitServicesArray[2]), type: .advertisedServiceUUIDs128Bit) { + advertisedServicesDataModels.append(advertisedServiceUUIDsModel) + } + } + + return advertisedServicesDataModels + } + + + private func decodeAdvertisedServiceUUIDs16Bit(services16Bit: [CBUUID]) -> String { + var advertisedServices = "" + var isFirst = true + for service in services16Bit { + if isFirst { + isFirst = false + } else { + advertisedServices += "\n" + } + + let bluetoothModel = SILBluetoothModelManager.shared()?.serviceModel(forUUIDString: service.uuidString) + + advertisedServices += "0x" + advertisedServices += service.uuidString + advertisedServices += " - " + advertisedServices += bluetoothModel?.name ?? "Unknown Service UUID" + } + + return advertisedServices + } + + private func decodeAdvertisedServiceUUIDs32Bit(services32Bit: [CBUUID]) -> String { + return decodeServicesUsingHex(services32Bit) + } + + private func decodeAdvertisedServiceUUIDs128Bit(services128Bit: [CBUUID]) -> String { + return decode128BitServices(services128Bit) + } + + private func decodeSolicitedServiceUUIDs() -> [SILAdvertisementDataModel] { + var solicitedServiceDataModels = [SILAdvertisementDataModel]() + let splitServicesArray = splitServices(services: peripheral.solicitedServiceUUIDs) + + if !splitServicesArray[0].isEmpty { + if let solicitedServiceUUIDsModel = SILAdvertisementDataModel(value: decodeSolicitedServiceUUIDs16Bit(services16Bit: splitServicesArray[0]), type: .solicitedServiceUUIDs16Bit) { + solicitedServiceDataModels.append(solicitedServiceUUIDsModel) + } + } + + if !splitServicesArray[2].isEmpty { + if let solicitedServiceUUIDsModel = SILAdvertisementDataModel(value: decodeSolicitedServiceUUIDs128Bit(services128Bit: splitServicesArray[2]), type: .solicitedServiceUUIDs128Bit) { + solicitedServiceDataModels.append(solicitedServiceUUIDsModel) + } + } + + return solicitedServiceDataModels + } + + private func decodeSolicitedServiceUUIDs16Bit(services16Bit: [CBUUID]) -> String { + return decodeServicesUsingHex(services16Bit) + } + + private func decodeSolicitedServiceUUIDs128Bit(services128Bit: [CBUUID]) -> String { + return decode128BitServices(services128Bit) + } + + private func decodeTXPowerLevel() -> String { + return self.peripheral.txPowerLevel.stringValue + } + + private func decodeAdvertisementLocalName() -> String { + return peripheral.advertisedLocalName + } + + private func decodeManufacturerData() -> String { + var manufacturerDataString = "" + + let parsedBytes = hexEncodedString(data: self.peripheral.manufacturerData) + + if parsedBytes.count < 4 { + manufacturerDataString += "PARSING ERROR: " + manufacturerDataString += parsedBytes + return manufacturerDataString + } + + let companyCodeIndex = parsedBytes.index(parsedBytes.startIndex, offsetBy: 4) + let companyCodeBytes = parsedBytes.prefix(upTo: companyCodeIndex) + let companyCodeSecondByteIndex = companyCodeBytes.index(companyCodeBytes.startIndex, offsetBy: 2) + let companyCodeSecondByte = companyCodeBytes.prefix(upTo: companyCodeSecondByteIndex) + let companyCodeFirstByte = companyCodeBytes.suffix(from: companyCodeSecondByteIndex) + + manufacturerDataString += "Company Code: 0x" + manufacturerDataString += companyCodeFirstByte + manufacturerDataString += companyCodeSecondByte + + if parsedBytes.count == 4 { + return manufacturerDataString + } + + let data = parsedBytes.suffix(from: companyCodeIndex) + + manufacturerDataString += "\nData: 0x" + manufacturerDataString += data + + return manufacturerDataString + } + + private func decodeDataServiceData() -> String { + var dataServiceData = "" + var isFirst = true + for (_, data) in self.peripheral.dataServiceData.enumerated() { + if isFirst { + isFirst = false + } else { + dataServiceData += "\n" + } + + dataServiceData += "UUID: 0x" + dataServiceData += data.key.uuidString + + let parsedBytes = hexEncodedString(data: data.value) + + if parsedBytes.count > 0 { + dataServiceData += " Data: 0x" + dataServiceData += parsedBytes + } + } + + return dataServiceData + } + + private func decodeAltBeaconData() -> String { + var altBeaconData = "" + let altBeacon = self.peripheral.beacon + var isFirst = true + + if let beaconID = altBeacon?.uuidString { + altBeaconData += "Beacon ID: " + altBeaconData += beaconID + isFirst = false + } + + if let manufacturerID = altBeacon?.manufacturerID { + if isFirst { + isFirst = false + } else { + altBeaconData += "\n" + } + + altBeaconData += "Manufacturer ID: " + altBeaconData += manufacturerID + } + + if let referenceRSSI = altBeacon?.refRSSI { + if isFirst { + isFirst = false + } else { + altBeaconData += "\n" + } + + altBeaconData += "Reference RSSI: " + altBeaconData += String(Int(truncating: referenceRSSI)) + altBeaconData += " dBm" + } + + return altBeaconData + } + + fileprivate func hexEncodedString(data: Data) -> String { + let format = "%02hhX" + return data.map { String(format: format, $0) }.joined() + } + + fileprivate func splitServices(services: [CBUUID]) -> [[CBUUID]] { + var services16bit = [CBUUID]() + var services32bit = [CBUUID]() + var services128bit = [CBUUID]() + + for service in services { + switch service.data.count { + case 2: + services16bit.append(service) + case 4: + services32bit.append(service) + case 16: + services128bit.append(service) + default: + break + } + } + + return [services16bit, services32bit, services128bit] + } + + fileprivate func decodeServicesUsingHex(_ services: [CBUUID]) -> String { + var servicesWithHexString = "" + var isFirst = true + + for service in services { + if isFirst { + isFirst = false + } else { + servicesWithHexString += ", " + } + + servicesWithHexString += "0x" + servicesWithHexString += service.uuidString + } + + return servicesWithHexString + } + + fileprivate func decode128BitServices(_ services: [CBUUID]) -> String { + var services128BitString = "" + var isFirst = true + + for service in services { + if isFirst { + isFirst = false + } else { + services128BitString += ", " + } + + services128BitString += service.uuidString + } + + return services128BitString + } +} + diff --git a/SiliconLabsApp/Models/SILAdTypeEddystoneDecoder.swift b/SiliconLabsApp/Models/SILAdTypeEddystoneDecoder.swift new file mode 100644 index 00000000..3792c1e9 --- /dev/null +++ b/SiliconLabsApp/Models/SILAdTypeEddystoneDecoder.swift @@ -0,0 +1,267 @@ +// +// SILAdTypeEddystoneDecoder.swift +// BlueGecko +// +// Created by Kamil Czajka on 18/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation + +class SILAdTypeEddystoneDecoder { + private let eddystoneData: [UInt8] + + private let EddystoneUIDLength = 18 + private let EddystoneURLMinimumLength = 4 + private let EddystoneTLMLength = (encrypted: 18, unencrypted: 14) + private let EddystoneEIDLength = 10 + + init(eddystoneData: Data) { + self.eddystoneData = [UInt8](eddystoneData) + } + + func decode() -> SILAdvertisementDataModel { + let eddystoneDataString: String + + switch self.eddystoneData[0] { + case 0x00: + eddystoneDataString = decodeEddystoneUID() + case 0x10: + eddystoneDataString = decodeEddystoneURL() + case 0x20: + if self.eddystoneData[1] == 0x00 { + eddystoneDataString = decodeEddystoneUnencryptedTLM() + } else if self.eddystoneData[1] == 0x01 { + eddystoneDataString = decodeEddystoneEncryptedTLM() + } else { + eddystoneDataString = "PARSING ERROR: Unknown type of Eddystone-TLM" + } + case 0x30: + eddystoneDataString = decodeEddystoneEID() + default: + eddystoneDataString = "PARSING ERROR: Unknown type of Eddystone: 0x\(self.eddystoneData[0])" + } + + return SILAdvertisementDataModel(value: eddystoneDataString, type: .eddystoneBeacon) + } + + private func decodeEddystoneUID() -> String { + var eddystoneUIDString = "" + + if eddystoneData.count < EddystoneUIDLength { + return "PARSING ERROR: Incomplete data for Eddystone-UID" + } + + eddystoneUIDString += "Calibrated Tx Power at 0 meters: " + eddystoneUIDString += decodeCalibratedTxPowerLevel(self.eddystoneData[1]) + + eddystoneUIDString += "\nUID Namespace: 0x" + let namespaceBytes = eddystoneData[2...11] + eddystoneUIDString += hexEncodedString(data: Array(namespaceBytes)) + + eddystoneUIDString += "\nUID Instance: 0x" + let instanceBytes = eddystoneData[12...17] + eddystoneUIDString += hexEncodedString(data: Array(instanceBytes)) + + return eddystoneUIDString + } + + private func decodeEddystoneURL() -> String { + var eddystoneURLString = "" + + if eddystoneData.count < EddystoneURLMinimumLength { + return "PARSING ERROR: Incomplete data for Eddystone-URL" + } + + eddystoneURLString += "Calibrated Tx Power at 0 meters: " + eddystoneURLString += decodeCalibratedTxPowerLevel(self.eddystoneData[1]) + + eddystoneURLString += "\nURL: " + eddystoneURLString += decodeURLSchemePrefix(self.eddystoneData[2]) + + for eddystoneByte in eddystoneData[3.. String { + var eddystoneUnencryptedTMLString = "" + + if eddystoneData.count < EddystoneTLMLength.unencrypted { + return "PARSING ERROR: Incomplete data for Unencrypted Eddystone-TLM" + } + + eddystoneUnencryptedTMLString += "Version: Unencrypted TLM (0x00)" + + eddystoneUnencryptedTMLString += "\nBattery voltage: " + let batteryVoltage = eddystoneData[2...3] + eddystoneUnencryptedTMLString += decodeBatteryVoltageValue(Array(batteryVoltage)) + eddystoneUnencryptedTMLString += " V" + + eddystoneUnencryptedTMLString += "\nTemperature: " + let beaconTemperature = eddystoneData[4...5] + eddystoneUnencryptedTMLString += decodeBeaconTemperatureValue(Array(beaconTemperature)) + eddystoneUnencryptedTMLString += " °C" + + eddystoneUnencryptedTMLString += "\nAdvertising PDU Count: " + let PDUCount = eddystoneData[6...9] + eddystoneUnencryptedTMLString += decodePDUCountValue(Array(PDUCount)) + + eddystoneUnencryptedTMLString += "\nUptime: " + let uptimeData = eddystoneData[10...13] + let calculatedUpTime = decodeUptime(Array(uptimeData)) + eddystoneUnencryptedTMLString += "\(calculatedUpTime.seconds) seconds (\(calculatedUpTime.days) days)" + + return eddystoneUnencryptedTMLString + } + + private func decodeEddystoneEncryptedTLM() -> String { + var eddystoneEncryptedTMLString = "" + + if eddystoneData.count < EddystoneTLMLength.encrypted { + return "PARSING ERROR: Incomplete data for Encrypted Eddystone-TLM" + } + + eddystoneEncryptedTMLString += "Version: Encrypted TLM (0x01)" + + eddystoneEncryptedTMLString += "\nEncrypted TLM Data: 0x" + let encryptedTMLData = eddystoneData[2...13] + eddystoneEncryptedTMLString += hexEncodedString(data: Array(encryptedTMLData)) + + eddystoneEncryptedTMLString += "\nSalt: 0x" + let saltData = eddystoneData[14...15] + eddystoneEncryptedTMLString += hexEncodedString(data: Array(saltData)) + + eddystoneEncryptedTMLString += "\nMessage Integrity Check: 0x" + let messageIntegrityCheckData = eddystoneData[16...17] + eddystoneEncryptedTMLString += hexEncodedString(data: Array(messageIntegrityCheckData)) + + return eddystoneEncryptedTMLString + } + + private func decodeEddystoneEID() -> String { + var eddystoneEIDString = "" + + if eddystoneData.count < EddystoneEIDLength { + return "PARSING ERROR: Incomplete data for Eddystone-EID" + } + + eddystoneEIDString += "Calibrated Tx Power at 0 meters: " + eddystoneEIDString += decodeCalibratedTxPowerLevel(self.eddystoneData[1]) + + eddystoneEIDString += "\nEphemeral Identifier (EID): 0x" + let ephemeralIDBytes = eddystoneData[2...9] + eddystoneEIDString += hexEncodedString(data: Array(ephemeralIDBytes)) + + return eddystoneEIDString + } + + fileprivate func decodeCalibratedTxPowerLevel(_ txPowerLevelByte: UInt8) -> String { + let DecodingFactorFromU2: UInt8 = 129 + var txPowerLevelString = "" + var txPowerLevel = txPowerLevelByte + if txPowerLevel > 20 { + txPowerLevel = txPowerLevel - DecodingFactorFromU2 + txPowerLevelString += "-" + } + txPowerLevelString += String(txPowerLevel) + txPowerLevelString += " dbm" + return txPowerLevelString + } + + fileprivate func decodeURLSchemePrefix(_ urlSchemePrefixByte: UInt8) -> String { + switch urlSchemePrefixByte { + case 0x00: + return "http://www." + case 0x01: + return "https://www." + case 0x02: + return "http://" + case 0x03: + return "https://" + default: + return "" + } + } + + fileprivate func decodeURLSchemeAppendix(_ urlSchemeAppendixByte: UInt8) -> String { + switch urlSchemeAppendixByte { + case 0x00: + return ".com/" + case 0x01: + return ".org/" + case 0x02: + return ".edu/" + case 0x03: + return ".net/" + case 0x04: + return ".info/" + case 0x05: + return ".biz/" + case 0x06: + return ".gov/" + case 0x07: + return ".com" + case 0x08: + return ".org" + case 0x09: + return ".edu" + case 0x0A: + return ".net" + case 0x0B: + return ".info" + case 0x0C: + return ".biz" + case 0x0D: + return ".gov" + default: + return "" + } + } + + fileprivate func hexEncodedString(data: [UInt8]) -> String { + let format = "%02hhX" + return data.map { String(format: format, $0) }.joined() + } + + fileprivate func decodeBatteryVoltageValue(_ batteryVoltage: [UInt8]) -> String { + let firstByteOfBatteryVoltage = Double(batteryVoltage[0]) + let secondByteOfBatteryVoltage = Double(batteryVoltage[1]) + let batteryVoltage = Double(firstByteOfBatteryVoltage * pow(16, 2) + secondByteOfBatteryVoltage) / pow(10, 3) + return String(batteryVoltage) + } + + fileprivate func decodeBeaconTemperatureValue(_ beaconTemperature: [UInt8]) -> String { + let firstByteOfBeaconTemperature = Double(beaconTemperature[0]) + let secondByteOfBeaconTemperature = Double(beaconTemperature[1]) + let fractorialValue = Double(secondByteOfBeaconTemperature * pow(16, -2)) + return String(firstByteOfBeaconTemperature + fractorialValue) + } + + fileprivate func decodePDUCountValue(_ PDUCount: [UInt8]) -> String { + let firstByteOfPDUCount = Double(PDUCount[0]) * pow(16, 6) + let secondByteOfPDUCount = Double(PDUCount[1]) * pow(16, 4) + let thirdByteOfPDUCount = Double(PDUCount[2]) * pow(16, 2) + let fourthByteOfPDUCount = Double(PDUCount[3]) + let PDUValue = Int(firstByteOfPDUCount + secondByteOfPDUCount + thirdByteOfPDUCount + fourthByteOfPDUCount) + return String(PDUValue) + } + + fileprivate func decodeUptime(_ uptimeData: [UInt8]) -> (seconds: String, days: String) { + let firstByteOfUptimeData = Double(uptimeData[0]) * pow(16, 6) + let secondByteOfUptimeData = Double(uptimeData[1]) * pow(16, 4) + let thirdByteOfUptimeData = Double(uptimeData[2]) * pow(16, 2) + let fourthByteOfUptimeData = Double(uptimeData[3]) + let uptimeDataValue = firstByteOfUptimeData + secondByteOfUptimeData + thirdByteOfUptimeData + fourthByteOfUptimeData + let uptimeDataInSeconds = Int(uptimeDataValue / 10.0) + let OneDayInSeconds = 60.0 * 60.0 * 24.0 + let uptimeDataInDays = Int(uptimeDataValue * ( 1.0 / (OneDayInSeconds * 10.0))) + return (String(uptimeDataInSeconds), String(uptimeDataInDays)) + } +} diff --git a/SiliconLabsApp/Models/SILAdvertisementDataModel.h b/SiliconLabsApp/Models/SILAdvertisementDataModel.h index 8cf102d2..ce0113f8 100644 --- a/SiliconLabsApp/Models/SILAdvertisementDataModel.h +++ b/SiliconLabsApp/Models/SILAdvertisementDataModel.h @@ -9,12 +9,18 @@ #import typedef NS_ENUM(NSInteger, AdModelType) { - AdModelTypeUUID, - AdModelTypeServiceUUID, - AdModelTypeName, - AdModelTypePower, - AdModelTypeMajor, - AdModelTypeMinor + AdModelTypeSolicitedServiceUUIDs16Bit, + AdModelTypeSolicitedServiceUUIDs128Bit, + AdModelTypeAdvertisedServiceUUIDs16Bit, + AdModelTypeAdvertisedServiceUUIDs32Bit, + AdModelTypeAdvertisedServiceUUIDs128Bit, + AdModelTypeCompleteLocalName, + AdModelTypeTXPowerLevel, + AdModelTypeManufacturerData, + AdModelTypeDataServiceData, + AdModelTypeIBeacon, + AdModelTypeAltBeacon, + AdModelTypeEddystoneBeacon }; @interface SILAdvertisementDataModel : NSObject diff --git a/SiliconLabsApp/Models/SILBeacon.h b/SiliconLabsApp/Models/SILBeacon.h index 10702bcf..2424aa07 100644 --- a/SiliconLabsApp/Models/SILBeacon.h +++ b/SiliconLabsApp/Models/SILBeacon.h @@ -17,6 +17,15 @@ typedef NS_ENUM(NSInteger, SILBeaconType) { SILBeaconTypeEddystone }; +typedef NS_ENUM(NSInteger, SILEddystoneBeaconType) { + SILEddystoneBeaconTypeUnspecified, + SILEddystoneBeaconTypeUID, + SILEddystoneBeaconTypeURL, + SILEddystoneBeaconTypeTLMUnencrypted, + SILEddystoneBeaconTypeTLMEncrypted, + SILEddystoneBeaconTypeEID +}; + extern NSString * const SILBeaconUnspecified; extern NSString * const SILBeaconIBeacon; extern NSString * const SILBeaconAltBeacon; @@ -31,15 +40,18 @@ extern NSString * const SILBeaconEddystone; @property (assign, nonatomic) int8_t calibrationPower; @property (strong, nonatomic) NSNumber *txPower; @property (strong, nonatomic) CLBeacon *beacon; //used by iBeacons +@property (strong, nonatomic) NSString *manufacturerID; // used by AltBeacons @property (strong, nonatomic) NSNumber *refRSSI; //used by AltBeacons @property (strong, nonatomic) NSString *beaconNamespace; //used by Eddystone @property (strong, nonatomic) NSString *instance; //used by Eddystone @property (strong, nonatomic) NSURL *url; //used by Eddystone @property (strong, nonatomic) TLMData *tlmData; //used by Eddystone @property (nonatomic) SILBeaconType type; +@property (nonatomic) SILEddystoneBeaconType eddystoneBeaconType; // used by Eddystone +@property (nonatomic) NSData* eddystoneData; // used by Eddystone + (instancetype)beaconWithAdvertisment:(NSDictionary *)advertisement name:(NSString *)name error:(NSError **)error; + (instancetype)beaconWithIBeacon:(CLBeacon *)beacon; -+ (instancetype)beaconWithEddystone:(EddystoneBeacon *)eddystone; ++ (instancetype)beaconWithEddystone:(NSData*)eddystoneServiceData; @end diff --git a/SiliconLabsApp/Models/SILBeacon.m b/SiliconLabsApp/Models/SILBeacon.m index f3a12c3c..d85ae7a9 100644 --- a/SiliconLabsApp/Models/SILBeacon.m +++ b/SiliconLabsApp/Models/SILBeacon.m @@ -14,11 +14,11 @@ uint16_t const kBlueGeckoAltBeaconCode = 0xBEAC; uint16_t const kSilabsMfgId = 0x0047; -uint16_t const kEddystoneBeaconCode = 0xAAFE; +uint16_t const kEddystoneBeaconCode = 0xFEAA; NSString * const SILBeaconUnspecified = @"Unspecified"; NSString * const SILBeaconIBeacon = @"iBeacon"; -NSString * const SILBeaconAltBeacon = @"Alt Beacon"; +NSString * const SILBeaconAltBeacon = @"AltBeacon"; NSString * const SILBeaconEddystone = @"Eddystone"; @implementation SILBeacon @@ -41,9 +41,6 @@ + (instancetype)beaconWithAdvertisment:(NSDictionary *)advertisement name:(NSStr if (beaconCode == kBlueGeckoAltBeaconCode && mfgId == kSilabsMfgId) { beacon = [SILBeacon altBeaconWithManufacturingData:manufacturerData txPower:txPower error:error]; beacon.name = SILBeaconAltBeacon; - } else if (beaconCode == kEddystoneBeaconCode) { - beacon = [SILBeacon eddystoneBeacon]; - beacon.name = SILBeaconEddystone; } else { beacon = [SILBeacon bgBeaconWithManufacturingData:manufacturerData error:error]; beacon.name = SILBeaconUnspecified; @@ -52,14 +49,6 @@ + (instancetype)beaconWithAdvertisment:(NSDictionary *)advertisement name:(NSStr return beacon; } -+ (instancetype)eddystoneBeacon { - SILBeacon* beacon = [[SILBeacon alloc] init]; - beacon.type = SILBeaconTypeEddystone; - beacon.name = SILBeaconEddystone; - - return beacon; -} - + (instancetype)beaconWithIBeacon:(CLBeacon *)iBeacon { if (!iBeacon) { return nil; @@ -77,24 +66,40 @@ + (instancetype)beaconWithIBeacon:(CLBeacon *)iBeacon { return beacon; } -+ (instancetype)beaconWithEddystone:(EddystoneBeacon *)eddystone { - if (!eddystone) { - return nil; - } - - SILBeacon *beacon = [[SILBeacon alloc] init]; - - beacon.UUIDString = [eddystone.namespace stringByAppendingString:eddystone.instance]; - beacon.beaconNamespace = eddystone.namespace; - beacon.instance = eddystone.instance; - beacon.type = SILBeaconTypeEddystone; - beacon.url = eddystone.url; - beacon.tlmData = eddystone.tlmData; - beacon.calibrationPower = eddystone.rssi; - beacon.txPower = @(eddystone.txPower); - // TODO: Replace with actual name. ++ (instancetype)beaconWithEddystone:(NSData *)eddystoneServiceData { + SILBeacon* beacon = [[SILBeacon alloc] init]; + beacon.name = @"Eddystone"; - + beacon.type = SILBeaconTypeEddystone; + + uint8_t *dataPointer = (uint8_t *)eddystoneServiceData.bytes; + + switch (dataPointer[0]) { + case 0x00: + beacon.eddystoneBeaconType = SILEddystoneBeaconTypeUID; + break; + case 0x10: + beacon.eddystoneBeaconType = SILEddystoneBeaconTypeURL; + break; + case 0x20: + if (dataPointer[1] == 0x00) { + beacon.eddystoneBeaconType = SILEddystoneBeaconTypeTLMUnencrypted; + } else if (dataPointer[1] == 0x01) { + beacon.eddystoneBeaconType = SILEddystoneBeaconTypeTLMEncrypted; + } else { + beacon.eddystoneBeaconType = SILEddystoneBeaconTypeUnspecified; + } + break; + case 0x30: + beacon.eddystoneBeaconType = SILEddystoneBeaconTypeEID; + break; + default: + beacon.eddystoneBeaconType = SILEddystoneBeaconTypeUnspecified; + break; + } + + beacon.eddystoneData = eddystoneServiceData; + return beacon; } @@ -165,11 +170,16 @@ + (SILBeacon *)altBeaconWithManufacturingData:(NSData *)data txPower:(NSNumber * } uint8_t *dataPointer = (uint8_t *)data.bytes; - dataPointer += 4; //skip mfg and beacon code + NSMutableString *manufactuterIDString = [[NSMutableString alloc] initWithString:@"0x"]; + [manufactuterIDString appendFormat:@"%02hhX", dataPointer[1]]; + [manufactuterIDString appendFormat:@"%02hhX", dataPointer[0]]; + beacon.manufacturerID = [manufactuterIDString copy]; + + dataPointer += 4; //skip beacon code NSMutableString *mutableUUIDString = [[NSMutableString alloc] initWithString:@"0x"]; for (int i = 0; i < 20; i++) { - [mutableUUIDString appendFormat:@"%02x", dataPointer[0]]; + [mutableUUIDString appendFormat:@"%02hhX", dataPointer[0]]; dataPointer++; } beacon.UUIDString = [mutableUUIDString copy]; diff --git a/SiliconLabsApp/Models/SILBitFieldFieldModel.m b/SiliconLabsApp/Models/SILBitFieldFieldModel.m index cf615fc7..adbf38f1 100644 --- a/SiliconLabsApp/Models/SILBitFieldFieldModel.m +++ b/SiliconLabsApp/Models/SILBitFieldFieldModel.m @@ -69,6 +69,10 @@ - (NSString *)secondaryTitle { return @"Bit field Secondary"; } +- (void)clearValues { + [self consumeValue:[[NSData alloc] init] fromIndex:0]; +} + //Consume a single bit value - (NSInteger)consumeValue:(NSData *)value fromIndex:(NSInteger)index { diff --git a/SiliconLabsApp/Models/SILBrowserConnectionsViewModel.h b/SiliconLabsApp/Models/SILBrowserConnectionsViewModel.h index a4ec19ed..427fe643 100644 --- a/SiliconLabsApp/Models/SILBrowserConnectionsViewModel.h +++ b/SiliconLabsApp/Models/SILBrowserConnectionsViewModel.h @@ -22,6 +22,8 @@ - (void)disconnectAllPeripheral; - (void)updateConnectionsView:(NSInteger)index; - (void)connectionsViewOnDetailsScreen:(BOOL)isDetailsScreen; +- (BOOL)isConnectedPeripheral:(CBPeripheral*)peripheral; +- (void)clearViewModelData; @end diff --git a/SiliconLabsApp/Models/SILBrowserConnectionsViewModel.m b/SiliconLabsApp/Models/SILBrowserConnectionsViewModel.m index 269c21c7..192d8a70 100644 --- a/SiliconLabsApp/Models/SILBrowserConnectionsViewModel.m +++ b/SiliconLabsApp/Models/SILBrowserConnectionsViewModel.m @@ -15,6 +15,8 @@ @interface SILBrowserConnectionsViewModel () @property (strong, nonatomic, readwrite) NSMutableArray* allPeripherals; +@property (strong, nonatomic, readwrite) NSMutableArray* toastsToDisplayList; +@property (strong, nonatomic) NSTimer* toastsToDisplayChecker; @end @@ -36,9 +38,13 @@ - (instancetype)init { if (self) { self.allPeripherals = [[NSMutableArray alloc] init]; self.peripherals = [_allPeripherals copy]; + self.toastsToDisplayList = [[NSMutableArray alloc] init]; + self.toastsToDisplayChecker = [self setupToastToDisplayChecker]; [self addObserverForDisconnectPeripheral]; [self addObserverForDeleteDisconnectedPeripheral]; [self addObserverForDisconnectAllPeripheral]; + [self addObserverForDisplayToastRequest]; + [self addObserverForFailedToConnectPeripheral]; } return self; } @@ -55,6 +61,23 @@ - (void)addObserverForDisconnectAllPeripheral { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(disconnectAllPeripheral) name:SILNotificationDisconnectAllPeripheral object:nil]; } +- (void)addObserverForDisplayToastRequest { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displayToastIfNeeded) name:SILNotificationDisplayToastRequest object:nil]; +} + +- (void)addObserverForFailedToConnectPeripheral { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(addFailedConnectionToastToDisplay:) name:SILNotificationFailedToConnectPeripheral object:nil]; +} + +- (NSTimer*)setupToastToDisplayChecker { + return [NSTimer scheduledTimerWithTimeInterval:1.0f repeats:YES block:^(NSTimer * _Nonnull timer) { + if (self.toastsToDisplayList.count > 0) { + [self displayToastIfNeeded]; + [self.toastsToDisplayChecker invalidate]; + } + }]; +} + - (void)addNewConnectedPeripheral:(CBPeripheral*)peripheral { if ([self isUniquePeripheral:peripheral]) { SILConnectedPeripheralDataModel* connectedPeripheral = [[SILConnectedPeripheralDataModel alloc] initWithPeripheral:peripheral andIsSelected:NO]; @@ -69,10 +92,6 @@ - (void)disconnectAllPeripheral { for (SILConnectedPeripheralDataModel* connectedPeripheral in _allPeripherals) { [_centralManager disconnectFromPeripheral:connectedPeripheral.peripheral]; } - - _allPeripherals = [[NSMutableArray alloc] init]; - _peripherals = [_allPeripherals copy]; - [self postReloadConnectionTableViewNotification]; } - (void)disconnectPeripheral:(NSNotification*)notification { @@ -82,9 +101,6 @@ - (void)disconnectPeripheral:(NSNotification*)notification { SILConnectedPeripheralDataModel* connectedPeripheral = _peripherals[index]; [_centralManager disconnectFromPeripheral:connectedPeripheral.peripheral]; - [_allPeripherals removeObjectAtIndex:index]; - _peripherals = [_allPeripherals copy]; - [self postReloadConnectionTableViewNotification]; } - (void)postReloadConnectionTableViewNotification { @@ -107,11 +123,16 @@ - (void)updateConnectionsView:(NSInteger)index { - (void)deleteDisconnectedPeripheral:(NSNotification*)notification { NSDictionary* userInfo = notification.userInfo; NSString* uuid = (NSString*)userInfo[SILNotificationKeyUUID]; + NSString* errorCodeString = (NSString*)userInfo[SILNotificationKeyError]; + int errorCode = [errorCodeString intValue]; for (SILConnectedPeripheralDataModel* connectedPeripheral in _peripherals) { if ([connectedPeripheral.peripheral.identifier.UUIDString isEqualToString:uuid]) { - [_allPeripherals removeObject:connectedPeripheral]; - _peripherals = [_allPeripherals copy]; + [self.allPeripherals removeObject:connectedPeripheral]; + self.peripherals = [self.allPeripherals copy]; + if (errorCode != 0) { + [self.toastsToDisplayList addObject:[[SILDisconnectionToastModel alloc] initWithPeripheralName:connectedPeripheral.peripheral.name errorCode:errorCode peripheralWasConnected:YES]]; + } } } @@ -134,4 +155,36 @@ - (void)connectionsViewOnDetailsScreen:(BOOL)isDetailsScreen { } } +- (void)clearViewModelData { + self.allPeripherals = [[NSMutableArray alloc] init]; + self.peripherals = [[NSArray alloc] init]; +} + +- (void)displayToastIfNeeded { + if (self.toastsToDisplayList.count > 0) { + SILDisconnectionToastModel* toastToShow = [self.toastsToDisplayList objectAtIndex:0]; + NSString* ErrorMessage = [toastToShow getErrorMessageForToast]; + [self.toastsToDisplayList removeObjectAtIndex:0]; + [[NSNotificationCenter defaultCenter] postNotificationName:SILNotificationDisplayToastResponse + object:self + userInfo: @{ + SILNotificationKeyDescription : ErrorMessage + }]; + } else { + self.toastsToDisplayChecker = [self setupToastToDisplayChecker]; + } +} + +- (BOOL)isConnectedPeripheral:(CBPeripheral*)peripheral { + return ![self isUniquePeripheral:peripheral]; +} + +- (void)addFailedConnectionToastToDisplay:(NSNotification*)notification { + NSDictionary* userInfo = notification.userInfo; + NSString* peripheralName = (NSString*)userInfo[SILNotificationKeyPeripheralName]; + NSString* errorCodeString = (NSString*)userInfo[SILNotificationKeyError]; + int errorCode = [errorCodeString intValue]; + [self.toastsToDisplayList addObject:[[SILDisconnectionToastModel alloc] initWithPeripheralName:peripheralName errorCode:errorCode peripheralWasConnected:NO]]; +} + @end diff --git a/SiliconLabsApp/Models/SILBrowserSavedSearches.h b/SiliconLabsApp/Models/SILBrowserSavedSearches.h index ee4f6234..8a834c62 100644 --- a/SiliconLabsApp/Models/SILBrowserSavedSearches.h +++ b/SiliconLabsApp/Models/SILBrowserSavedSearches.h @@ -14,14 +14,13 @@ @interface SILBrowserSavedSearches : NSObject @property (strong, nonatomic, readonly) NSString *searchByDeviceNameText; -@property (strong, nonatomic, readonly) NSString *searchByRawAdvetisingDataText; @property (nonatomic, readonly) NSInteger dBmValue; @property (strong, nonatomic, readonly) NSArray* beaconTypes; @property (nonatomic, readonly) BOOL isFavourite; @property (nonatomic, readonly) BOOL isConnectable; @property (nonatomic, readonly) BOOL isSelected; -- (instancetype)initWithSearchByDeviceNameText:(NSString*)searchByDeviceNameText searchByRawAdveritisingDataText:(NSString*)searchByRawAdvetisingDataText dBmValue:(NSInteger)dBmValue beaconTypes:(NSArray*)beaconTypes isFavourite:(BOOL)isFavourite isConnectable:(BOOL)isConnectable andIsSelected:(BOOL)isSelected; +- (instancetype)initWithSearchByDeviceNameText:(NSString*)searchByDeviceNameText dBmValue:(NSInteger)dBmValue beaconTypes:(NSArray*)beaconTypes isFavourite:(BOOL)isFavourite isConnectable:(BOOL)isConnectable andIsSelected:(BOOL)isSelected; - (void)setSelection:(BOOL)isSelected; @end diff --git a/SiliconLabsApp/Models/SILBrowserSavedSearches.m b/SiliconLabsApp/Models/SILBrowserSavedSearches.m index ab5d7540..09a6a603 100644 --- a/SiliconLabsApp/Models/SILBrowserSavedSearches.m +++ b/SiliconLabsApp/Models/SILBrowserSavedSearches.m @@ -12,7 +12,6 @@ @interface SILBrowserSavedSearches () @property (strong, nonatomic, readwrite) NSString *searchByDeviceNameText; -@property (strong, nonatomic, readwrite) NSString *searchByRawAdvetisingDataText; @property (nonatomic, readwrite) NSInteger dBmValue; @property (strong, nonatomic, readwrite) NSArray* beaconTypes; @property (nonatomic, readwrite) BOOL isFavourite; @@ -23,11 +22,10 @@ @interface SILBrowserSavedSearches () @implementation SILBrowserSavedSearches : NSObject -- (instancetype)initWithSearchByDeviceNameText:(NSString*)searchByDeviceNameText searchByRawAdveritisingDataText:(NSString*)searchByRawAdvetisingDataText dBmValue:(NSInteger)dBmValue beaconTypes:(NSArray*)beaconTypes isFavourite:(BOOL)isFavourite isConnectable:(BOOL)isConnectable andIsSelected:(BOOL)isSelected { +- (instancetype)initWithSearchByDeviceNameText:(NSString*)searchByDeviceNameText dBmValue:(NSInteger)dBmValue beaconTypes:(NSArray*)beaconTypes isFavourite:(BOOL)isFavourite isConnectable:(BOOL)isConnectable andIsSelected:(BOOL)isSelected { self = [super init]; if (self) { self.searchByDeviceNameText = searchByDeviceNameText; - self.searchByRawAdvetisingDataText = searchByRawAdvetisingDataText; self.dBmValue = dBmValue; self.beaconTypes = beaconTypes; self.isFavourite = isFavourite; diff --git a/SiliconLabsApp/Models/SILDisconnectionToastModel.swift b/SiliconLabsApp/Models/SILDisconnectionToastModel.swift new file mode 100644 index 00000000..fc3daf9e --- /dev/null +++ b/SiliconLabsApp/Models/SILDisconnectionToastModel.swift @@ -0,0 +1,70 @@ +// +// SILDisconnectionToastModel.swift +// BlueGecko +// +// Created by Kamil Czajka on 11/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import CoreBluetooth +import Foundation + +@objc +class SILDisconnectionToastModel : NSObject, SILToastModelType { + let peripheralName: String + let errorCode: Int + let peripheralWasConnected: Bool + var errorDescription: String { + guard let CBErrorCode = CBError.Code(rawValue: errorCode) else { + return "Unspecified error" + } + switch CBErrorCode { + case .unknown: + return "0x0085 GATT Error" + case .invalidParameters: + return "0x0002 The specified parameters are invalid" + case .invalidHandle: + return "0x0002 The specified attribute handle is invalid" + case .notConnected: + return "0x0085 The device isn’t currently connected" + case .outOfSpace: + return "0x0007 The device has run out of space to complete the intended operation" + case .operationCancelled: + return "0x0100 The connection canceled" + case .connectionTimeout: + return "0x0008 The connection timed out" + case .peripheralDisconnected: + return "0x0013 The peripheral disconnected" + case .uuidNotAllowed: + return "0x0085 The specified UUID isn’t permitted" + case .alreadyAdvertising: + return "0x0085 The peripheral is already advertising" + case .connectionFailed: + return "0x003E The connection failed" + case .connectionLimitReached: + return "0x0009 The device already has the maximum number of connections" + case .unkownDevice: + return "0x0085 The device is unknown" + case .operationNotSupported: + return "0x0085 The operation isn’t supported" + @unknown default: + return "Unspecified error" + } + } + + @objc + init(peripheralName: String, errorCode: Int, peripheralWasConnected: Bool) { + self.peripheralName = peripheralName + self.errorCode = errorCode + self.peripheralWasConnected = peripheralWasConnected + } + + @objc + func getErrorMessageForToast() -> String { + if peripheralWasConnected { + return "Device \(peripheralName) has disconnected\nReason: \(errorDescription)" + } else { + return "Failed connecting to: \(peripheralName)\nReason: \(errorDescription)" + } + } +} diff --git a/SiliconLabsApp/Models/SILDiscoveredPeripheralDisplayData.h b/SiliconLabsApp/Models/SILDiscoveredPeripheralDisplayData.h index 35c843d7..aba44eff 100644 --- a/SiliconLabsApp/Models/SILDiscoveredPeripheralDisplayData.h +++ b/SiliconLabsApp/Models/SILDiscoveredPeripheralDisplayData.h @@ -15,7 +15,6 @@ @property (strong, nonatomic) SILDiscoveredPeripheral *discoveredPeripheral; @property (strong, nonatomic, readonly) NSArray *advertisementDataModels; -@property (strong, nonatomic, readonly) NSArray *advertisementDataModelsForDevicesTable; @property (strong, nonatomic, readonly) NSArray *advertisementDataModelsForInfoView; - (instancetype)initWithDiscoveredPeripheral:(SILDiscoveredPeripheral *)discoveredPeripheral; diff --git a/SiliconLabsApp/Models/SILDiscoveredPeripheralDisplayData.m b/SiliconLabsApp/Models/SILDiscoveredPeripheralDisplayData.m index 5a0cf04a..5209dcb5 100644 --- a/SiliconLabsApp/Models/SILDiscoveredPeripheralDisplayData.m +++ b/SiliconLabsApp/Models/SILDiscoveredPeripheralDisplayData.m @@ -15,7 +15,6 @@ @interface SILDiscoveredPeripheralDisplayData () @property (strong, nonatomic, readwrite) NSArray *advertisementDataModels; -@property (strong, nonatomic, readwrite) NSArray *advertisementDataModelsForDevicesTable; @property (strong, nonatomic, readwrite) NSArray *advertisementDataModelsForInfoView; @end @@ -35,13 +34,6 @@ - (instancetype)initWithDiscoveredPeripheral:(SILDiscoveredPeripheral *)discover #pragma mark - Properties -- (NSArray *)advertisementDataModelsForDevicesTable { - if (_advertisementDataModelsForDevicesTable == nil) { - _advertisementDataModelsForDevicesTable = [self advertisementDataModelsExcept:@[@(AdModelTypeUUID), @(AdModelTypeName), @(AdModelTypeServiceUUID)]]; - } - return _advertisementDataModelsForDevicesTable; -} - - (NSArray *)advertisementDataModelsForInfoView { if (_advertisementDataModelsForInfoView == nil) { _advertisementDataModelsForInfoView = [self.advertisementDataModels copy]; @@ -61,58 +53,54 @@ - (NSArray *)advertisementDataModelsForPeripheral:(SILDiscoveredPeripheral *)dev } - (NSArray*)adverisementDataModelsForCBPeripheral:(SILDiscoveredPeripheral*)device { - NSMutableArray *mutableAdvModels = [[NSMutableArray alloc] init]; - - SILAdvertisementDataModel *uuidModel = [[SILAdvertisementDataModel alloc] initWithValue:device.peripheral.identifier.UUIDString type:AdModelTypeUUID]; - [mutableAdvModels addObject:uuidModel]; - - for (CBUUID *serviceUUID in device.advertisedServiceUUIDs) { - SILAdvertisementDataModel *uuidModel = [[SILAdvertisementDataModel alloc] initWithValue:serviceUUID.UUIDString type:AdModelTypeServiceUUID]; - [mutableAdvModels addObject:uuidModel]; - } - - if (device.advertisedLocalName) { - SILAdvertisementDataModel *nameModel = [[SILAdvertisementDataModel alloc] initWithValue:device.advertisedLocalName - type:AdModelTypeName]; - [mutableAdvModels addObject:nameModel]; - } - - if (device.txPowerLevel) { - SILAdvertisementDataModel *powerModel = [[SILAdvertisementDataModel alloc] initWithValue:[device.txPowerLevel stringValue] - type:AdModelTypePower]; - [mutableAdvModels addObject:powerModel]; - } - - return mutableAdvModels; + SILAdTypeCBPeripheralDecoder* decoder = [[SILAdTypeCBPeripheralDecoder alloc] initWithPeripheral:device]; + return [decoder decode]; } - (NSArray*)advertisementDataModelsForCLBeacon:(SILDiscoveredPeripheral*)device { NSMutableArray *mutableAdvModels = [[NSMutableArray alloc] init]; + NSMutableString* iBeaconDataString = [[NSMutableString alloc] init]; SILBeacon* beacon = device.beacon; - - SILAdvertisementDataModel *uuidModel = [[SILAdvertisementDataModel alloc] initWithValue:beacon.UUIDString type:AdModelTypeUUID]; - [mutableAdvModels addObject:uuidModel]; - + BOOL isFirst = YES; + if (beacon.minor) { + [iBeaconDataString appendString:@"Minor: "]; + NSString* minorStringValue = [NSString stringWithFormat:@"%hu", beacon.minor]; + [iBeaconDataString appendString:minorStringValue]; + isFirst = NO; + } if (beacon.major) { + if (isFirst == YES) { + isFirst = NO; + } else { + [iBeaconDataString appendString:@"\n"]; + } + [iBeaconDataString appendString:@"Major: "]; NSString* majorStringValue = [NSString stringWithFormat:@"%hu", beacon.major]; - SILAdvertisementDataModel *majorModel = [[SILAdvertisementDataModel alloc] initWithValue:majorStringValue - type:AdModelTypeMajor]; - [mutableAdvModels addObject:majorModel]; + [iBeaconDataString appendString:majorStringValue]; } - - if (beacon.minor) { - NSString* minorStringValue = [NSString stringWithFormat:@"%hu", beacon.minor]; - SILAdvertisementDataModel *minorModel = [[SILAdvertisementDataModel alloc] initWithValue:minorStringValue - type:AdModelTypeMinor]; - [mutableAdvModels addObject:minorModel]; + if (beacon.UUIDString) { + if (isFirst == YES) { + isFirst = NO; + } else { + [iBeaconDataString appendString:@"\n"]; + } + [iBeaconDataString appendString:@"UUID: "]; + [iBeaconDataString appendString:beacon.UUIDString]; } - if (beacon.name) { - SILAdvertisementDataModel *nameModel = [[SILAdvertisementDataModel alloc] initWithValue:device.advertisedLocalName - type:AdModelTypeName]; - [mutableAdvModels addObject:nameModel]; + if (beacon.beacon.proximity && beacon.beacon.accuracy) { + if (isFirst == YES) { + isFirst = NO; + } else { + [iBeaconDataString appendString:@"\n"]; + } + [iBeaconDataString appendFormat:@"Distance from iBeacon: "]; + [iBeaconDataString appendFormat:@"%ld +/- %.2f meters", (long)beacon.beacon.proximity, beacon.beacon.accuracy]; } - + + SILAdvertisementDataModel* iBeaconModel = [[SILAdvertisementDataModel alloc] initWithValue:iBeaconDataString type:AdModelTypeIBeacon]; + [mutableAdvModels addObject:iBeaconModel]; + return mutableAdvModels; } diff --git a/SiliconLabsApp/Models/SILEncodingPseudoFieldRowModel.m b/SiliconLabsApp/Models/SILEncodingPseudoFieldRowModel.m index e628e6a8..c1fd5b26 100644 --- a/SiliconLabsApp/Models/SILEncodingPseudoFieldRowModel.m +++ b/SiliconLabsApp/Models/SILEncodingPseudoFieldRowModel.m @@ -39,4 +39,8 @@ - (NSString *)secondaryTitle { return @""; } +- (void)clearValues { + +} + @end diff --git a/SiliconLabsApp/Models/SILGattPropertiesErrorToastModel.swift b/SiliconLabsApp/Models/SILGattPropertiesErrorToastModel.swift new file mode 100644 index 00000000..c6c5d85a --- /dev/null +++ b/SiliconLabsApp/Models/SILGattPropertiesErrorToastModel.swift @@ -0,0 +1,71 @@ +// +// SILGattPropertiesErrorToastModel.swift +// BlueGecko +// +// Created by Kamil Czajka on 01/06/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation +import CoreBluetooth + +@objc +class SILGattPropertiesErrorToastModel : NSObject, SILToastModelType { + let peripheralName: String + let errorCode: Int + var errorDescription: String { + guard let CBATTErrorCode = CBATTError.Code(rawValue: errorCode) else { + return "Unspecified error" + } + switch CBATTErrorCode { + case .success: + return "The ATT command or request successfully completed" + case .invalidHandle: + return "0x0001 The attribute handle is invalid on this peripheral" + case .readNotPermitted: + return "0x0002 The permissions prohibit reading the attribute’s value" + case .writeNotPermitted: + return "0x0003 The permissions prohibit writing the attribute’s value" + case .invalidPdu: + return "0x0004 The attribute Protocol Data Unit (PDU) is invalid" + case .insufficientAuthentication: + return "0x0005 Failed for lack of authentication." + case .requestNotSupported: + return "0x0006 The attribute server doesn’t support the request received from the client" + case .invalidOffset: + return "0x0007 The specified offset value was past the end of the attribute’s value" + case .insufficientAuthorization: + return "0x0008 Failed for lack of authorization." + case .prepareQueueFull: + return "0x0009 The prepare queue is full, too many write requests in the queue" + case .attributeNotFound: + return "0x000A The attribute wasn’t found within the specified attribute handle range" + case .attributeNotLong: + return "0x000B The ATT read blob request can’t read or write the attribute" + case .insufficientEncryptionKeySize: + return "0x000C The encryption key size used for encryption is insufficient" + case .invalidAttributeValueLength: + return "0x000D The length of the attribute’s value is invalid" + case .unlikelyError: + return "0x000E The ATT request encountered an unlikely error" + case .insufficientEncryption: + return "0x000F Failed for lack of encryption" + case .unsupportedGroupType: + return "0x0010 The attribute type isn’t a supported grouping attribute" + case .insufficientResources: + return "0x0011 Resources are insufficient to complete the ATT request" + @unknown default: + return "Unspecified error" + } + } + + @objc + init(peripheralName: String, errorCode: Int) { + self.peripheralName = peripheralName + self.errorCode = errorCode + } + + func getErrorMessageForToast() -> String { + return "Failed action on \(peripheralName)\nReason: \(errorDescription)" + } +} diff --git a/SiliconLabsApp/Models/SILOTAFirmwareUpdateManager.m b/SiliconLabsApp/Models/SILOTAFirmwareUpdateManager.m index b4070824..fb1c4766 100644 --- a/SiliconLabsApp/Models/SILOTAFirmwareUpdateManager.m +++ b/SiliconLabsApp/Models/SILOTAFirmwareUpdateManager.m @@ -100,11 +100,15 @@ - (void)didConnectToPeripheral:(NSNotification *)notification { } - (void)didDisconnectFromPeripheral:(NSNotification *)notification { - if (self.expectingToDisconnectFromPeripheral) { - self.expectingToDisconnectFromPeripheral = NO; - } else { - NSError *error = [NSError sil_errorWithCode:SILErrorCodeOTADisconnectedFromPeripheral underlyingError:nil]; - [self.delegate firmwareUpdateManagerDidUnexpectedlyDisconnectFromPeripheral:self withError:error]; + NSString* uuid = (NSString*)notification.userInfo[SILNotificationKeyUUID]; + + if ([uuid isEqualToString:self.peripheral.identifier.UUIDString]) { + if (self.expectingToDisconnectFromPeripheral) { + self.expectingToDisconnectFromPeripheral = NO; + } else { + NSError *error = [NSError sil_errorWithCode:SILErrorCodeOTADisconnectedFromPeripheral underlyingError:nil]; + [self.delegate firmwareUpdateManagerDidUnexpectedlyDisconnectFromPeripheral:self withError:error]; + } } } @@ -134,8 +138,7 @@ - (void)cycleDeviceWithInitiationByteSequence:(BOOL)initiatingByteSequence dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kSILDurationBeforeUpdatingDFUStatusToWaiting * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ progress(SILDFUStatusWaiting); - self.didDiscoverOTADevice = NO; - [self.centralManager addScanForPeripheralsObserver:self selector:@selector(searchHandlerForOTADevice)]; + [self reconnectToOTADevice]; }); } @@ -143,20 +146,9 @@ - (void)endCycleDevice { [self.centralManager removeScanForPeripheralsObserver:self]; } -- (void)searchHandlerForOTADevice { - if (self.didDiscoverOTADevice) { return; } - - for (SILDiscoveredPeripheral *discoveredPeripheral in self.centralManager.discoveredPeripherals) { - NSString * const name = discoveredPeripheral.advertisedLocalName; - - if ([@"OTA" isEqualToString:name]) { - self.didDiscoverOTADevice = YES; - self.peripheral = discoveredPeripheral.peripheral; - [self.centralManager removeScanForPeripheralsObserver:self]; - [self.centralManager connectToDiscoveredPeripheral:discoveredPeripheral]; - break; - } - } +- (void)reconnectToOTADevice { + SILDiscoveredPeripheral* discoveredPeripheral = [self.centralManager discoveredPeripheralForPeripheral:self.peripheral]; + [self.centralManager connectToDiscoveredPeripheral:discoveredPeripheral]; } - (void)uploadFile:(SILOTAFirmwareFile *)file diff --git a/SiliconLabsApp/Models/SILSavedSearchesRealmModel.h b/SiliconLabsApp/Models/SILSavedSearchesRealmModel.h index 0003691e..033810c9 100644 --- a/SiliconLabsApp/Models/SILSavedSearchesRealmModel.h +++ b/SiliconLabsApp/Models/SILSavedSearchesRealmModel.h @@ -18,13 +18,12 @@ RLM_ARRAY_TYPE(SILBeaconTypeRealmModel) @interface SILSavedSearchesRealmModel : RLMObject @property NSString* searchByDeviceName; -@property NSString* searchByAdvertisingData; @property NSInteger dBmValue; @property RLMArray* beaconTypes; @property BOOL isFavouriteSetFilter; @property BOOL isConnectableSetFilter; -- (instancetype)initWithSearchByDeviceNameText:(NSString*)searchByDeviceNameText searchByRawAdveritisingDataText:(NSString*)searchByAdvertisingDataText dBmValue:(NSInteger)dBmValue beaconTypes:(RLMArray*)beaconTypes isFavourite:(BOOL)isFavourite andIsConnectable:(BOOL)isConnectable; +- (instancetype)initWithSearchByDeviceNameText:(NSString*)searchByDeviceNameText dBmValue:(NSInteger)dBmValue beaconTypes:(RLMArray*)beaconTypes isFavourite:(BOOL)isFavourite andIsConnectable:(BOOL)isConnectable; @end diff --git a/SiliconLabsApp/Models/SILSavedSearchesRealmModel.m b/SiliconLabsApp/Models/SILSavedSearchesRealmModel.m index efe8eab6..1fcaab72 100644 --- a/SiliconLabsApp/Models/SILSavedSearchesRealmModel.m +++ b/SiliconLabsApp/Models/SILSavedSearchesRealmModel.m @@ -16,12 +16,11 @@ @interface SILSavedSearchesRealmModel () @implementation SILSavedSearchesRealmModel -- (instancetype)initWithSearchByDeviceNameText:(NSString*)searchByDeviceNameText searchByRawAdveritisingDataText:(NSString*)searchByAdvertisingDataText dBmValue:(NSInteger)dBmValue beaconTypes:(RLMArray*)beaconTypes isFavourite:(BOOL)isFavourite andIsConnectable:(BOOL)isConnectable { +- (instancetype)initWithSearchByDeviceNameText:(NSString*)searchByDeviceNameText dBmValue:(NSInteger)dBmValue beaconTypes:(RLMArray*)beaconTypes isFavourite:(BOOL)isFavourite andIsConnectable:(BOOL)isConnectable { self = [super self]; if (self) { self.searchByDeviceName = searchByDeviceNameText; - self.searchByAdvertisingData = searchByAdvertisingDataText; self.dBmValue = dBmValue; self.beaconTypes = beaconTypes; self.isFavouriteSetFilter = isFavourite; diff --git a/SiliconLabsApp/Models/SILToastModelType.swift b/SiliconLabsApp/Models/SILToastModelType.swift new file mode 100644 index 00000000..68706f13 --- /dev/null +++ b/SiliconLabsApp/Models/SILToastModelType.swift @@ -0,0 +1,17 @@ +// +// SILToastModelType.swift +// BlueGecko +// +// Created by Kamil Czajka on 01/06/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation + +@objc +protocol SILToastModelType { + var errorDescription: String { get } + var peripheralName: String { get } + var errorCode: Int { get } + @objc func getErrorMessageForToast() -> String +} diff --git a/SiliconLabsApp/Models/SILUUIDProvider.h b/SiliconLabsApp/Models/SILUUIDProvider.h index f58727e6..743c1f94 100644 --- a/SiliconLabsApp/Models/SILUUIDProvider.h +++ b/SiliconLabsApp/Models/SILUUIDProvider.h @@ -21,13 +21,13 @@ @interface SILUUIDProvider (OTA) extern NSString * const kSILOtaServiceUUIDString; -extern NSString * const kSILOtaCharacteristicDataUUIDString; -extern NSString * const kSILOtaCharacteristicControlUUIDString; -extern NSString * const kSILOtaCharacteristicFirmwareVersionUUIDString; +extern NSString * const kSILOtaCharacteristicOTADataAttributeUUIDString; +extern NSString * const kSILOtaCharacteristicOTAControlAttributeUUIDString; +extern NSString * const kSILOtaCharacteristicAppLoaderVersionUUIDString; extern NSString * const kSILOtaCharacteristicOtaVersionUUIDString; @property (strong, nonatomic, readonly) CBUUID *otaServiceUUID; -@property (strong, nonatomic, readonly) CBUUID *otaCharacteristicDataUUID; -@property (strong, nonatomic, readonly) CBUUID *otaCharacteristicControlUUID; +@property (strong, nonatomic, readonly) CBUUID *otaCharacteristicOTADataAttributeUUID; +@property (strong, nonatomic, readonly) CBUUID *otaCharacteristicOTAControlAttributeUUID; @end diff --git a/SiliconLabsApp/Models/SILUUIDProvider.m b/SiliconLabsApp/Models/SILUUIDProvider.m index 470cbc6f..8fdbb18f 100644 --- a/SiliconLabsApp/Models/SILUUIDProvider.m +++ b/SiliconLabsApp/Models/SILUUIDProvider.m @@ -11,21 +11,23 @@ @implementation SILUUIDProvider (OTA) NSString * const kSILOtaServiceUUIDString = @"1d14d6ee-fd63-4fa1-bfa4-8f47b42119f0"; -NSString * const kSILOtaCharacteristicDataUUIDString = @"984227f3-34fc-4045-a5d0-2c581f81a153"; -NSString * const kSILOtaCharacteristicControlUUIDString = @"f7bf3564-fb6d-4e53-88a4-5e37e0326063"; -NSString * const kSILOtaCharacteristicFirmwareVersionUUIDString = @"4f4a2368-8cca-451e-bfff-cf0e2ee23e9f"; +NSString * const kSILOtaCharacteristicOTADataAttributeUUIDString = @"984227f3-34fc-4045-a5d0-2c581f81a153"; +NSString * const kSILOtaCharacteristicOTAControlAttributeUUIDString = @"f7bf3564-fb6d-4e53-88a4-5e37e0326063"; +NSString * const kSILOtaCharacteristicAppLoaderVersionUUIDString = @"4f4a2368-8cca-451e-bfff-cf0e2ee23e9f"; NSString * const kSILOtaCharacteristicOtaVersionUUIDString = @"4cc07bcf-0868-4b32-9dad-ba4cc41e5316"; +NSString * const kSILOtaCharacteristicGeckoBootloarderVersionUUIDString = @"25f05c0a-e917-46e9-b2a5-aa2be1245afe"; +NSString * const kSILOtaCharacteristicApplicationVersionUUIDString = @"0d77cc11-4ac1-49f2-bfa9-cd96ac7a92f8"; - (CBUUID *)otaServiceUUID { return [CBUUID UUIDWithString:kSILOtaServiceUUIDString]; } -- (CBUUID *)otaCharacteristicDataUUID { - return [CBUUID UUIDWithString:kSILOtaCharacteristicDataUUIDString]; +- (CBUUID *)otaCharacteristicOTADataAttributeUUID { + return [CBUUID UUIDWithString:kSILOtaCharacteristicOTADataAttributeUUIDString]; } -- (CBUUID *)otaCharacteristicControlUUID { - return [CBUUID UUIDWithString:kSILOtaCharacteristicControlUUIDString]; +- (CBUUID *)otaCharacteristicOTAControlAttributeUUID { + return [CBUUID UUIDWithString:kSILOtaCharacteristicOTAControlAttributeUUIDString]; } @end @@ -65,10 +67,12 @@ - (void)preparePredefinedServicesNames { - (void)preparePredefinedCharacteristicsNames { _predefinedCharacteristicsNames = @{ - kSILOtaCharacteristicDataUUIDString : @"OTA Data", - kSILOtaCharacteristicControlUUIDString : @"OTA Control", - kSILOtaCharacteristicFirmwareVersionUUIDString : @"OTA Firmware Version", - kSILOtaCharacteristicOtaVersionUUIDString : @"OTA Version", + kSILOtaCharacteristicOTADataAttributeUUIDString : @"OTA Data Attribute", + kSILOtaCharacteristicOTAControlAttributeUUIDString : @"OTA Control Attribute", + kSILOtaCharacteristicAppLoaderVersionUUIDString : @"AppLoader version", + kSILOtaCharacteristicOtaVersionUUIDString : @"OTA version", + kSILOtaCharacteristicGeckoBootloarderVersionUUIDString : @"Gecko Bootloarder version", + kSILOtaCharacteristicApplicationVersionUUIDString : @"Application version" }; } diff --git a/SiliconLabsApp/Protocols/SILCharacteristicFieldRow.h b/SiliconLabsApp/Protocols/SILCharacteristicFieldRow.h index 4a5c5f83..c97fc28a 100644 --- a/SiliconLabsApp/Protocols/SILCharacteristicFieldRow.h +++ b/SiliconLabsApp/Protocols/SILCharacteristicFieldRow.h @@ -23,5 +23,6 @@ - (NSString *)secondaryTitle; - (NSInteger)consumeValue:(NSData *)value fromIndex:(NSInteger)index; //return read length - (NSData *)dataForFieldWithError:(NSError * __autoreleasing *)error; +- (void)clearValues; @end diff --git a/SiliconLabsApp/SILAppDelegate.m b/SiliconLabsApp/SILAppDelegate.m index d37e8b57..4d8a20cb 100644 --- a/SiliconLabsApp/SILAppDelegate.m +++ b/SiliconLabsApp/SILAppDelegate.m @@ -20,6 +20,7 @@ @implementation SILAppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { [SILAppearance setupAppearance]; [Fabric with:@[CrashlyticsKit]]; + [SILRealmConfiguration updateRealmConfigurationIfNeeded]; return YES; } diff --git a/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowser.storyboard b/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowser.storyboard index bf5ebb4c..afb4603e 100644 --- a/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowser.storyboard +++ b/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowser.storyboard @@ -49,23 +49,10 @@ - - - @@ -80,9 +67,22 @@ + + + @@ -105,41 +105,33 @@ - + - - - - - - - - @@ -194,7 +186,7 @@ - + @@ -271,7 +263,7 @@ - + @@ -334,7 +326,7 @@ - + @@ -405,15 +397,15 @@ - - + + - + - + @@ -422,16 +414,13 @@ - - - + + @@ -479,7 +469,7 @@ - + @@ -592,7 +582,6 @@ - @@ -753,10 +742,10 @@ - + - + @@ -795,70 +784,16 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - + @@ -965,12 +900,12 @@ - + - + @@ -1013,7 +948,7 @@ - + @@ -1022,7 +957,7 @@ - + - + - + @@ -1124,7 +1059,7 @@ - + @@ -1294,7 +1229,6 @@ - @@ -1302,7 +1236,6 @@ - @@ -1314,8 +1247,6 @@ - - @@ -1637,17 +1568,16 @@ - - - + + - + - + diff --git a/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowserDetails.storyboard b/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowserDetails.storyboard index 241d9636..34c0efed 100644 --- a/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowserDetails.storyboard +++ b/SiliconLabsApp/Storyboards/DevelopApps/SILAppBluetoothBrowserDetails.storyboard @@ -41,28 +41,28 @@ - + - - - - - - - + + + + + + - - + + + - @@ -97,10 +100,10 @@ - + + - @@ -285,7 +288,7 @@ - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/Contents.json similarity index 66% rename from SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/Contents.json rename to SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/Contents.json index 4575bb38..47601f72 100644 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/Contents.json +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon - star - off.png", + "filename" : "MenuIcon.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "icon - star - off@2x.png", + "filename" : "MenuIcon2.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "icon - star - off@3x.png", + "filename" : "MenuIcon2-1.png", "scale" : "3x" } ], diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon.png new file mode 100644 index 00000000..dd698666 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon2-1.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon2-1.png new file mode 100644 index 00000000..84af0035 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon2-1.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon2.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon2.png new file mode 100644 index 00000000..84af0035 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/MenuIcon.imageset/MenuIcon2.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light.png deleted file mode 100644 index 15a425a3..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light@2x.png deleted file mode 100644 index 5b27396c..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light@3x.png deleted file mode 100644 index 482c419f..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/icon - beacon - light@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/Contents.json similarity index 66% rename from SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/Contents.json rename to SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/Contents.json index 4575bb38..e0f0f4bf 100644 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/Contents.json +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon - star - off.png", + "filename" : "icon - beacon.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "icon - star - off@2x.png", + "filename" : "icon - beacon@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "icon - star - off@3x.png", + "filename" : "icon - beacon@3x.png", "scale" : "3x" } ], diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon.png new file mode 100644 index 00000000..3a00b437 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon@2x.png new file mode 100644 index 00000000..953ec771 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon@3x.png new file mode 100644 index 00000000..6492b77d Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconDark.imageset/icon - beacon@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/Contents.json new file mode 100644 index 00000000..47223c10 --- /dev/null +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon - beacon-white.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icon - beacon-white@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "icon - beacon-white@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white.png new file mode 100644 index 00000000..ab3a0b07 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white@2x.png new file mode 100644 index 00000000..0d89126d Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white@3x.png new file mode 100644 index 00000000..2b50bd1c Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/beaconWhite.imageset/icon - beacon-white@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/Contents.json index 0932adee..11b515ea 100644 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/Contents.json +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "connectable.png", + "filename" : "icon - bluetooth.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "connectable@2x.png", + "filename" : "icon - bluetooth@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "connectable@3x.png", + "filename" : "icon - bluetooth@3x.png", "scale" : "3x" } ], diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable.png deleted file mode 100644 index f9c07e64..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable@2x.png deleted file mode 100644 index 91ef3c46..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable@3x.png deleted file mode 100644 index 1eeca65a..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/connectable@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth.png new file mode 100644 index 00000000..eb29c81e Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth@2x.png new file mode 100644 index 00000000..768dfef6 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth@3x.png new file mode 100644 index 00000000..ed2a3851 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/connectable.imageset/icon - bluetooth@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/Contents.json index ddaaacdc..4575bb38 100644 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/Contents.json +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "favourite.png", + "filename" : "icon - star - off.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "favourite@2x.png", + "filename" : "icon - star - off@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "favourite@3x.png", + "filename" : "icon - star - off@3x.png", "scale" : "3x" } ], diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite.png deleted file mode 100644 index e8278d99..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite@2x.png deleted file mode 100644 index d7d22b94..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite@3x.png deleted file mode 100644 index 395d40cb..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/favourite@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off.png new file mode 100644 index 00000000..7ce854e3 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off@2x.png new file mode 100644 index 00000000..cbccf742 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off@3x.png new file mode 100644 index 00000000..f10f0606 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/favouriteOff.imageset/icon - star - off@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/Contents.json new file mode 100644 index 00000000..ceb9be94 --- /dev/null +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "icon - filter - off.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "icon - filter - off@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "icon - filter - off@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off.png new file mode 100644 index 00000000..ef6dfe66 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off@2x.png new file mode 100644 index 00000000..c7943e62 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off@3x.png new file mode 100644 index 00000000..dceb8630 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOff.imageset/icon - filter - off@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/Contents.json similarity index 65% rename from SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/Contents.json rename to SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/Contents.json index b36b848c..2be0fa63 100644 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/Contents.json +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon - wifi - dark.png", + "filename" : "filterOffSelected.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "icon - wifi - dark@2x.png", + "filename" : "filterOffSelected@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "icon - wifi - dark@3x.png", + "filename" : "filterOffSelected@3x.png", "scale" : "3x" } ], diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected.png new file mode 100644 index 00000000..84099b3a Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected@2x.png new file mode 100644 index 00000000..1783730b Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected@3x.png new file mode 100644 index 00000000..bac75725 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOffSelected.imageset/filterOffSelected@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/Contents.json similarity index 62% rename from SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/Contents.json rename to SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/Contents.json index 8ae95f88..9bfd3793 100644 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/Contents.json +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon - beacon - dark.png", + "filename" : "icon_-_filter_-_active3x_20x20.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "icon - beacon - dark@2x.png", + "filename" : "icon - filter - active@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "icon - beacon - dark@3x.png", + "filename" : "icon - filter - active@3x.png", "scale" : "3x" } ], diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon - filter - active@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon - filter - active@2x.png new file mode 100644 index 00000000..d8bae4ca Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon - filter - active@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon - filter - active@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon - filter - active@3x.png new file mode 100644 index 00000000..d1895a9e Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon - filter - active@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon_-_filter_-_active3x_20x20.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon_-_filter_-_active3x_20x20.png new file mode 100644 index 00000000..f7046c92 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActive.imageset/icon_-_filter_-_active3x_20x20.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/Contents.json similarity index 63% rename from SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/Contents.json rename to SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/Contents.json index e8959893..28c98ed6 100644 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/beacon.imageset/Contents.json +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon - beacon - light.png", + "filename" : "icon - filter - active.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "icon - beacon - light@2x.png", + "filename" : "icon - filter - active@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "icon - beacon - light@3x.png", + "filename" : "icon - filter - active@3x.png", "scale" : "3x" } ], diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active.png new file mode 100644 index 00000000..320d96b2 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active@2x.png new file mode 100644 index 00000000..174d73b6 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active@3x.png new file mode 100644 index 00000000..6e42f230 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/filterOnActiveSelected.imageset/icon - filter - active@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark.png deleted file mode 100644 index 36d21b52..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark@2x.png deleted file mode 100644 index 64f248b2..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark@3x.png deleted file mode 100644 index a61f8969..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark-1.imageset/icon - beacon - dark@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/Contents.json deleted file mode 100644 index 8ae95f88..00000000 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "icon - beacon - dark.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "icon - beacon - dark@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "icon - beacon - dark@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark.png deleted file mode 100644 index 36d21b52..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark@2x.png deleted file mode 100644 index 64f248b2..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark@3x.png deleted file mode 100644 index a61f8969..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - dark.imageset/icon - beacon - dark@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/Contents.json deleted file mode 100644 index e8959893..00000000 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "icon - beacon - light.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "icon - beacon - light@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "icon - beacon - light@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light.png deleted file mode 100644 index 15a425a3..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light@2x.png deleted file mode 100644 index 5b27396c..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light@3x.png deleted file mode 100644 index 482c419f..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - beacon - light.imageset/icon - beacon - light@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off.png deleted file mode 100644 index 99613861..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off@2x.png deleted file mode 100644 index b04999df..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off@3x.png deleted file mode 100644 index 7cf744f0..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off-1.imageset/icon - star - off@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off.png deleted file mode 100644 index 99613861..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off@2x.png deleted file mode 100644 index b04999df..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off@3x.png deleted file mode 100644 index 7cf744f0..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - star - off.imageset/icon - star - off@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark.png deleted file mode 100644 index 15e64f2c..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark@2x.png deleted file mode 100644 index e34ca3ba..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark@3x.png deleted file mode 100644 index 218a4de2..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark-1.imageset/icon - wifi - dark@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark.png deleted file mode 100644 index 15e64f2c..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark@2x.png deleted file mode 100644 index e34ca3ba..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark@3x.png deleted file mode 100644 index 218a4de2..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/icon - wifi - dark@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light.png deleted file mode 100644 index 840ab262..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light@2x.png deleted file mode 100644 index a5f3ff2e..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light@2x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light@3x.png deleted file mode 100644 index 8d11d5b0..00000000 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/icon - wifi - light@3x.png and /dev/null differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/Contents.json similarity index 65% rename from SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/Contents.json rename to SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/Contents.json index b36b848c..45a838f1 100644 --- a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - dark.imageset/Contents.json +++ b/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/Contents.json @@ -2,17 +2,17 @@ "images" : [ { "idiom" : "universal", - "filename" : "icon - wifi - dark.png", + "filename" : "loading pulse.png", "scale" : "1x" }, { "idiom" : "universal", - "filename" : "icon - wifi - dark@2x.png", + "filename" : "loading pulse@2x.png", "scale" : "2x" }, { "idiom" : "universal", - "filename" : "icon - wifi - dark@3x.png", + "filename" : "loading pulse@3x.png", "scale" : "3x" } ], diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse.png new file mode 100644 index 00000000..caca380b Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse@2x.png new file mode 100644 index 00000000..8de9e14f Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse@3x.png new file mode 100644 index 00000000..14b5ab80 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/loading pulse.imageset/loading pulse@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light.png index 840ab262..d22487c9 100644 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light.png and b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light@2x.png index a5f3ff2e..b2c88615 100644 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light@2x.png and b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light@3x.png index 8d11d5b0..cec0692f 100644 Binary files a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light@3x.png and b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssi.imageset/icon - wifi - light@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/Contents.json b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/Contents.json similarity index 100% rename from SiliconLabsApp/SupportingFiles/Images.xcassets/icon - wifi - light.imageset/Contents.json rename to SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/Contents.json diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light.png new file mode 100644 index 00000000..d1d13efd Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light@2x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light@2x.png new file mode 100644 index 00000000..20dd2f01 Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light@2x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light@3x.png b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light@3x.png new file mode 100644 index 00000000..335a7b8a Binary files /dev/null and b/SiliconLabsApp/SupportingFiles/Images.xcassets/rssiWhite.imageset/icon - wifi - light@3x.png differ diff --git a/SiliconLabsApp/SupportingFiles/Localizable.strings b/SiliconLabsApp/SupportingFiles/Localizable.strings index 2317068c..38d719e0 100644 --- a/SiliconLabsApp/SupportingFiles/Localizable.strings +++ b/SiliconLabsApp/SupportingFiles/Localizable.strings @@ -6,7 +6,5 @@ Copyright © 2020 SiliconLabs. All rights reserved. */ -"app_info" = "For more information visit:\nsilabs.com/products/wireless\n\nSupport:\nsilabs.com/support\n\nSource code:\ngithub.com/SiliconLabs/EFRConnect-ios\n\nAdditional documentation:\ndocs.silabs.com/bluetooth/latest\n\nAdditional Apps released by Silicon Labs:\napps.apple.com/us/developer/silicon-labs/id555074469"; -"device_is_not_responding" = "Device is not responding."; -"error" = "Error"; -"dismiss" = "Dismiss"; +"app_info" = "For more information visit:\nsilabs.com/products/wireless\n\nSupport:\nsilabs.com/support\n\nSource code:\ngithub.com/SiliconLabs/EFRConnect-ios\n\nEFR Connect User's Guide:\ndocs.silabs.com/bluetooth/latest/miscellaneous/mobile/efr-connect-mobile-app\n\nAdditional documentation:\ndocs.silabs.com/bluetooth/latest\n\nAdditional Apps released by Silicon Labs:\napps.apple.com/us/developer/silicon-labs/id555074469"; +"device_is_not_responding" = "Device is not responding"; diff --git a/SiliconLabsApp/ViewControllers/AppSelection/Info/SILAppSelectionInfoViewController.m b/SiliconLabsApp/ViewControllers/AppSelection/Info/SILAppSelectionInfoViewController.m index 9674e68e..89342533 100644 --- a/SiliconLabsApp/ViewControllers/AppSelection/Info/SILAppSelectionInfoViewController.m +++ b/SiliconLabsApp/ViewControllers/AppSelection/Info/SILAppSelectionInfoViewController.m @@ -40,7 +40,7 @@ - (CGSize)preferredContentSize { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { return CGSizeMake(600, 600); } else { - return CGSizeMake(300, 500); + return CGSizeMake(300, 520); } } diff --git a/SiliconLabsApp/ViewControllers/AppSelection/SILAppSelectionViewController.h b/SiliconLabsApp/ViewControllers/AppSelection/SILAppSelectionViewController.h index 91df2661..d6d33c20 100644 --- a/SiliconLabsApp/ViewControllers/AppSelection/SILAppSelectionViewController.h +++ b/SiliconLabsApp/ViewControllers/AppSelection/SILAppSelectionViewController.h @@ -13,6 +13,7 @@ NS_ASSUME_NONNULL_BEGIN @interface SILAppSelectionViewController : UIViewController @property (strong, nonatomic) NSArray *appsArray; +@property BOOL isDisconnectedIntentionally; @end diff --git a/SiliconLabsApp/ViewControllers/AppSelection/SILAppSelectionViewController.m b/SiliconLabsApp/ViewControllers/AppSelection/SILAppSelectionViewController.m index dae12167..42269e03 100644 --- a/SiliconLabsApp/ViewControllers/AppSelection/SILAppSelectionViewController.m +++ b/SiliconLabsApp/ViewControllers/AppSelection/SILAppSelectionViewController.m @@ -49,7 +49,6 @@ @interface SILAppSelectionViewController () + + + + + + + + + + + Roboto-Regular + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/Menu/SILDebugServicesMenuViewController.swift b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/Menu/SILDebugServicesMenuViewController.swift new file mode 100644 index 00000000..12915800 --- /dev/null +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/Menu/SILDebugServicesMenuViewController.swift @@ -0,0 +1,60 @@ +// +// SILDebugServicesMenuViewController.swift +// BlueGecko +// +// Created by Kamil Czajka on 19/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation + +class SILDebugServicesMenuViewController : UIViewController, UITableViewDataSource, UITableViewDelegate { + @IBOutlet weak var menuOptionTableView: UITableView! + @objc var delegate: SILDebugServicesMenuViewControllerDelegate! + var menuOption = [Int : [String : () -> ()]]() + + let ReuseIdentifier = "DebugServicesMenuCell" + let NibName = "SILDebugServicesMenuTableViewCell" + let ServicesMenuCellHeight: CGFloat = 30.0 + + override func viewDidLoad() { + super.viewDidLoad() + setupMenuOptionTableView() + } + + @objc func addMenuOption(title: String, completion: @escaping () -> ()) { + menuOption[menuOption.count] = [title : completion] + } + + @objc func getMenuOptionHeight() -> CGFloat { + return CGFloat(menuOption.count) * ServicesMenuCellHeight + } + + private func setupMenuOptionTableView() { + self.menuOptionTableView.delegate = self + self.menuOptionTableView.dataSource = self + self.menuOptionTableView.register(UINib(nibName: NibName, bundle: nil), forCellReuseIdentifier: ReuseIdentifier) + self.menuOptionTableView.separatorStyle = .none + } + + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return menuOption.count + } + + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: ReuseIdentifier, for: indexPath) as! SILDebugServicesMenuTableViewCell + cell.menuOptionLabel.text = menuOption[indexPath.row]?.keys.first + cell.selectionStyle = .none + return cell + } + + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + if let completion = menuOption[indexPath.row]?.values.first { + delegate!.performActionForMenuOption(using: completion) + } + } + + func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + return ServicesMenuCellHeight + } +} diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/Menu/SILDebugServicesMenuViewControllerDelegate.swift b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/Menu/SILDebugServicesMenuViewControllerDelegate.swift new file mode 100644 index 00000000..bbb18a0b --- /dev/null +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/Menu/SILDebugServicesMenuViewControllerDelegate.swift @@ -0,0 +1,15 @@ +// +// SILDebugServicesMenuViewControllerDelegate.swift +// BlueGecko +// +// Created by Kamil Czajka on 19/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation + +@objc +protocol SILDebugServicesMenuViewControllerDelegate { + @objc + func performActionForMenuOption(using completion: () -> ()) +} diff --git a/SiliconLabsApp/Views/SILOTAHUDView.h b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAHUDView.h similarity index 87% rename from SiliconLabsApp/Views/SILOTAHUDView.h rename to SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAHUDView.h index a2eb0cf6..8a73a79e 100644 --- a/SiliconLabsApp/Views/SILOTAHUDView.h +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAHUDView.h @@ -18,8 +18,10 @@ @property (weak, nonatomic) IBOutlet UILabel *fileNameLabel; @property (weak, nonatomic) IBOutlet UILabel *uploadTypeLabel; @property (weak, nonatomic) IBOutlet UILabel *fileTotalBytesLabel; -@property (weak, nonatomic) IBOutlet UILabel *peripheralNameLabel; +@property (weak, nonatomic) IBOutlet UILabel *informationLabel; @property (weak, nonatomic) IBOutlet UILabel *peripheralIdentifierLabel; +@property (weak, nonatomic) IBOutlet UILabel *otaStatusLabel; +@property (weak, nonatomic) IBOutlet UIView *mtuView; @property (weak, nonatomic) IBOutlet UILabel *mtuValueLabel; @property (weak, nonatomic) IBOutlet UILabel *fileCountLabel; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *constrainBottomSeparatorBelowFile; diff --git a/SiliconLabsApp/Views/SILOTAHUDView.m b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAHUDView.m similarity index 100% rename from SiliconLabsApp/Views/SILOTAHUDView.m rename to SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAHUDView.m diff --git a/SiliconLabsApp/Views/SILOTAHUDView.xib b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAHUDView.xib similarity index 95% rename from SiliconLabsApp/Views/SILOTAHUDView.xib rename to SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAHUDView.xib index a3894a21..68f2391c 100644 --- a/SiliconLabsApp/Views/SILOTAHUDView.xib +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAHUDView.xib @@ -1,11 +1,9 @@ - - - - + + - + @@ -20,9 +18,11 @@ + + + - @@ -30,21 +30,21 @@ - - + + - + - + - - + - + - + - + - + - + - + diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAProgressViewController.m b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAProgressViewController.m index 2a078ccf..520721a3 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAProgressViewController.m +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAProgressViewController.m @@ -63,7 +63,7 @@ - (void)viewDidLoad { self.doneButton.enabled = NO; self.timerLabel = [[MZTimerLabel alloc] initWithLabel:self.timerDisplayLabel]; self.timerLabel.timeFormat = kSILTimerFormat; - _hudView.peripheralNameLabel.text = [_hudPeripheralViewModel peripheralName]; + _hudView.informationLabel.text = @"OTA Device Firmware Update"; _hudView.peripheralIdentifierLabel.text = [_hudPeripheralViewModel peripheralIdentifier]; _hudView.mtuValueLabel.text = [_hudPeripheralViewModel peripheralMaximumWriteValueLength]; } diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTASetupViewController.m b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTASetupViewController.m index 509f31af..ef4701ea 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTASetupViewController.m +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTASetupViewController.m @@ -62,9 +62,10 @@ - (void)viewDidLoad { [self registerNibs]; [self configureUIForFirmwareUpdateViewModel:self.firmwareUpdateViewModel]; [_hudView stateDependentHidden:YES]; - _hudView.peripheralNameLabel.text = [_hudPeripheralViewModel peripheralName]; + _hudView.informationLabel.text = [_hudPeripheralViewModel peripheralName]; + _hudView.otaStatusLabel.text = @"OTA Device Firmware Update"; _hudView.peripheralIdentifierLabel.text = [_hudPeripheralViewModel peripheralIdentifier]; - _hudView.mtuValueLabel.text = [_hudPeripheralViewModel peripheralMaximumWriteValueLength]; + [_hudView.mtuView setHidden:YES]; } - (void)viewWillDisappear:(BOOL)animated { diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAUICoordinator.m b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAUICoordinator.m index aaca8d0e..5403fa1d 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAUICoordinator.m +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Details/OTA/SILOTAUICoordinator.m @@ -18,8 +18,6 @@ #import "SILPopoverViewController.h" #import "SILOTAProgressViewController.h" -#define OTA_TTL 30 - static NSString * const kSILDFUStatusRebootingString = @"Rebooting..."; static NSString * const kSILDFUStatusWaitingString = @"Waiting..."; static NSString * const kSILDFUStatusConnectingString = @"Attempting Connection..."; @@ -33,6 +31,8 @@ static NSString * const kSILFirmwareUpdateBGErrInvalidFileFormat = @"Invalid file format"; static NSString * const kSILFirmwareUpdateBGErrUnspecified = @"Unspecified error"; static NSString * const kSILFirmwareUpdateBGErrUnknown = @"Unspecified error"; +static NSString * const kSILDeviceIsNotResponding = @"Device is not responding"; +static NSString * const kSILCouldNotFindDeviceAdvertising = @"Could not find device advertising"; static NSString * const kSILDeviceInOTAModeName = @"OTA"; @interface SILOTAUICoordinator () @property (weak, nonatomic) IBOutlet UIButton *searchButton; @property (weak, nonatomic) IBOutlet UIButton *saveButton; @property (weak, nonatomic) IBOutlet UIButton *resetButton; -@property (weak, nonatomic) IBOutlet UITextView *searchByRawAdvertisementDataTextView; @property (weak, nonatomic) IBOutlet UITextView *searchByDeviceNameTextView; @property (weak, nonatomic) IBOutlet UIImageView *clearTextImageByDeviceName; -@property (weak, nonatomic) IBOutlet UIImageView *clearTextImageByAdvertisementData; @property (weak, nonatomic) IBOutlet UILabel *rssiLabel; @property (weak, nonatomic) IBOutlet UILabel *beaconTypeLabel; @property (weak, nonatomic) IBOutlet UILabel *minRangeLabel; @@ -29,8 +27,6 @@ @interface SILBrowserFilterViewController () @property (weak, nonatomic) IBOutlet UILabel *savedSearchesLabel; @property (weak, nonatomic) IBOutlet UISlider *dBmSlider; @property (weak, nonatomic) IBOutlet UIView *seachByDeviceNameView; -@property (weak, nonatomic) IBOutlet UIView *searchByRawAdvertisementDataView; -@property (weak, nonatomic) IBOutlet UITextView *hexTextView; @property (weak, nonatomic) IBOutlet UILabel *favouriteAreaTitleLabel; @property (weak, nonatomic) IBOutlet UISwitch *favouriteSwitch; @property (weak, nonatomic) IBOutlet UIButton *beaconTypeAreaButton; @@ -46,9 +42,7 @@ @interface SILBrowserFilterViewController () @implementation SILBrowserFilterViewController -NSString* const HexTextView = @"0x"; NSString* const SearchByDeviceNamePlaceholder = @"Search by device name"; -NSString* const SearchByRawAdvertisementDataPlaceholder = @"Search by raw advertising data"; NSString* const DiscardKeybordText = @"\n"; NSInteger const ASCIICodeFor0 = 48; NSInteger const ASCIICodeFor9 = 57; @@ -99,36 +93,12 @@ - (void)addObserverForKeyboardHide { #pragma mark - Appearance for Searching View - (void)setAppearanceForSeachingView { - [self setAppearanceForSearchingByRawAdvertisement]; [self setAppearanceForSearchingByDeviceName]; [self setBackgroundAppearance]; [self setupGesturesForClearImages]; [self hideClearButtons]; } -- (void)setAppearanceForSearchingByRawAdvertisement { - [self setAppearanceForRawAdvertisementDataTextView]; - [self setAppearanceForHexTextView]; -} - -- (void)setAppearanceForRawAdvertisementDataTextView { - _searchByRawAdvertisementDataTextView.textContainer.maximumNumberOfLines = 1; - _searchByRawAdvertisementDataTextView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail; - _searchByRawAdvertisementDataTextView.delegate = self; - [_searchByRawAdvertisementDataTextView setFont:[UIFont robotoMediumWithSize:[UIFont getMiddleFontSize]]]; - _searchByRawAdvertisementDataTextView.textColor = [UIColor sil_subtleTextColor]; - _searchByRawAdvertisementDataTextView.text = SearchByRawAdvertisementDataPlaceholder; - _searchByRawAdvertisementDataTextView.autocorrectionType = UITextAutocorrectionTypeNo; -} - -- (void)setAppearanceForHexTextView { - _hexTextView.textContainer.maximumNumberOfLines = 1; - _hexTextView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail; - [_hexTextView setFont:[UIFont robotoBoldWithSize:[UIFont getMiddleFontSize]]]; - _hexTextView.textColor = [UIColor sil_primaryTextColor]; - _hexTextView.text = HexTextView; -} - - (void)setAppearanceForSearchingByDeviceName { _searchByDeviceNameTextView.textContainer.maximumNumberOfLines = 1; _searchByDeviceNameTextView.textContainer.lineBreakMode = NSLineBreakByTruncatingTail; @@ -142,13 +112,10 @@ - (void)setAppearanceForSearchingByDeviceName { - (void)setBackgroundAppearance { _seachByDeviceNameView.backgroundColor = [UIColor sil_backgroundColor]; _seachByDeviceNameView.layer.cornerRadius = 10.0; - _searchByRawAdvertisementDataView.backgroundColor = [UIColor sil_backgroundColor]; - _searchByRawAdvertisementDataView.layer.cornerRadius = 10.0; } - (void)setupGesturesForClearImages { [self setupGestureForClearImageDeviceName]; - [self setupGestureForClearImageAdvertisementData]; } - (void)setupGestureForClearImageDeviceName { @@ -165,41 +132,18 @@ - (void)performClearActionForDeviceNameView:(UIGestureRecognizer*)gestureRecogni [self hideClearImageForDeviceName]; } -- (void)setupGestureForClearImageAdvertisementData { - UITapGestureRecognizer* tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(performClearActionForAdvertisementDataView:)]; - [_clearTextImageByAdvertisementData addGestureRecognizer:tap]; -} - -- (void)performClearActionForAdvertisementDataView:(UIGestureRecognizer*)gestureRecognizer { - _searchByRawAdvertisementDataTextView.text = EmptyText; - _viewModel.searchByRawAdvertisingData = EmptyText; - if ([_searchByRawAdvertisementDataTextView isFirstResponder] == false) { - [self textViewDidEndEditing:_searchByRawAdvertisementDataTextView]; - } - [self hideClearImageForAdvertisementData]; -} - - (void)hideClearButtons { [self hideClearImageForDeviceName]; - [self hideClearImageForAdvertisementData]; } - (void)hideClearImageForDeviceName { [_clearTextImageByDeviceName setHidden:YES]; } -- (void)hideClearImageForAdvertisementData { - [_clearTextImageByAdvertisementData setHidden:YES]; -} - - (void)showClearImageForDeviceName { [_clearTextImageByDeviceName setHidden:NO]; } -- (void)showClearImageForAdvertisementData { - [_clearTextImageByAdvertisementData setHidden:NO]; -} - # pragma mark - TextViewDelegate - (void)textViewDidChange:(UITextView *)textView { @@ -217,10 +161,6 @@ -(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range re return NO; } - if ([textView isEqual:_searchByRawAdvertisementDataTextView]) { - return [self isHexNumberInString:text]; - } - return YES; } @@ -228,9 +168,6 @@ - (void)textViewDidBeginEditing:(UITextView *)textView { if ([textView isEqual:_searchByDeviceNameTextView]) { [self discardPlaceholderIfNeededForDeviceNameTextView]; } - if ([textView isEqual:_searchByRawAdvertisementDataTextView]) { - [self discardPlaceholderIfNeededForRawAdvertisementDataTextView]; - } [self manageClearImageState:textView]; [textView becomeFirstResponder]; @@ -240,9 +177,6 @@ - (void)manageClearImageState:(UITextView*)textView { if ([textView isEqual:_searchByDeviceNameTextView]) { [self manageClearImageStateForDeviceNameTextView]; } - if ([textView isEqual:_searchByRawAdvertisementDataTextView]) { - [self manageClearImageStateForAdvertisementData]; - } } - (void)manageClearImageStateForDeviceNameTextView { @@ -253,33 +187,16 @@ - (void)manageClearImageStateForDeviceNameTextView { } } -- (void)manageClearImageStateForAdvertisementData { - if (([_searchByRawAdvertisementDataTextView.text isEqualToString:EmptyText] || [_searchByRawAdvertisementDataTextView.text isEqualToString:SearchByRawAdvertisementDataPlaceholder]) == false) { - [self showClearImageForAdvertisementData]; - } else { - [self hideClearImageForAdvertisementData]; - } -} - - (void)discardPlaceholderIfNeededForDeviceNameTextView { if ([_searchByDeviceNameTextView.text isEqualToString:SearchByDeviceNamePlaceholder]) { _searchByDeviceNameTextView.text = EmptyText; } } -- (void)discardPlaceholderIfNeededForRawAdvertisementDataTextView { - if ([_searchByRawAdvertisementDataTextView.text isEqualToString:SearchByRawAdvertisementDataPlaceholder]) { - _searchByRawAdvertisementDataTextView.text = EmptyText; - } -} - - (void)textViewDidEndEditing:(UITextView *)textView { if ([textView isEqual:_searchByDeviceNameTextView]) { [self setPlaceholderIfNeededForDeviceNameTextView]; } - if ([textView isEqual:_searchByRawAdvertisementDataTextView]) { - [self setPlaceholderIfNeededForRawAdvertisementDataTextView]; - } [textView resignFirstResponder]; } @@ -290,24 +207,12 @@ - (void)setPlaceholderIfNeededForDeviceNameTextView { } } -- (void)setPlaceholderIfNeededForRawAdvertisementDataTextView { - if ([_searchByRawAdvertisementDataTextView.text isEqualToString:EmptyText]) { - _searchByRawAdvertisementDataTextView.text = SearchByRawAdvertisementDataPlaceholder; - } -} - - (void)updateSearchTextViewModels { if ([self.searchByDeviceNameTextView.text isEqualToString:SearchByDeviceNamePlaceholder]) { self.viewModel.searchByDeviceName = EmptyText; } else { self.viewModel.searchByDeviceName = self.searchByDeviceNameTextView.text; } - - if ([self.searchByRawAdvertisementDataTextView.text isEqualToString:SearchByRawAdvertisementDataPlaceholder]) { - self.viewModel.searchByRawAdvertisingData = EmptyText; - } else { - self.viewModel.searchByRawAdvertisingData = self.searchByRawAdvertisementDataTextView.text; - } } - (void)keyboardDidHide:(NSNotification*)notification { @@ -549,22 +454,11 @@ - (void)updateFilterView { - (void)updateFilterViewValues { _searchByDeviceNameTextView.text = _viewModel.searchByDeviceName; - _searchByRawAdvertisementDataTextView.text = _viewModel.searchByRawAdvertisingData; _dBmSlider.value = _viewModel.dBmValue; _favouriteSwitch.on = _viewModel.isFavouriteFilterSet; _connectableSwitch.on = _viewModel.isConnectableFilterSet; [self textViewDidEndEditing:_searchByDeviceNameTextView]; - [self textViewDidEndEditing:_searchByRawAdvertisementDataTextView]; [self manageClearImageState:_searchByDeviceNameTextView]; - [self manageClearImageState:_searchByRawAdvertisementDataTextView]; -} - -# pragma mark - Hex Number Checker - -- (BOOL)isHexNumberInString:(NSString*)text { - NSString* const HexsNumbersPattern = @"[0-9A-F]"; - NSRange range = [text rangeOfString:HexsNumbersPattern options:NSRegularExpressionSearch]; - return range.location != NSNotFound; } @end diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/Info/SILKeychainInfoViewController.swift b/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/Info/SILKeychainInfoViewController.swift new file mode 100644 index 00000000..f101537e --- /dev/null +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/Info/SILKeychainInfoViewController.swift @@ -0,0 +1,38 @@ +// +// SILKeychainInfoViewController.swift +// BlueGecko +// +// Created by Kamil Czajka on 21/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import UIKit + +class SILKeychainInfoViewController: UIViewController { + @IBOutlet weak var informationsLabel: UILabel! + var delegate: SILKeychainInfoViewContollerDelegate! + + let InfoText = #"The mappings dictionary contains the 128-bit UUIDs for services and characteristics that have been renamed by the user. The main purpose is simple consultation but it is also possible to change or delete them from this view. When deleted, the 128-bit UUIDs will again be shown as "Unknown Service" or "Unknown Characteristic" in the GATT."# + + override func viewDidLoad() { + super.viewDidLoad() + informationsLabel.text = InfoText + } + + override var preferredContentSize: CGSize { + get { + if UIDevice.current.userInterfaceIdiom == .pad { + return CGSize(width: 400, height: 400) + } else { + return CGSize(width: 300, height: 350) + } + } + set { + super.preferredContentSize = newValue + } + } + + @IBAction func didTapOKButton(_ sender: Any) { + delegate!.shouldCloseInfoViewController(self) + } +} diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/Info/SILKeychainInfoViewControllerDelegate.swift b/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/Info/SILKeychainInfoViewControllerDelegate.swift new file mode 100644 index 00000000..a82bdadf --- /dev/null +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/Info/SILKeychainInfoViewControllerDelegate.swift @@ -0,0 +1,13 @@ +// +// SILKeychainInfoViewControllerDelegate.swift +// BlueGecko +// +// Created by Kamil Czajka on 22/05/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import Foundation + +protocol SILKeychainInfoViewContollerDelegate { + func shouldCloseInfoViewController(_ infoViewController: SILKeychainInfoViewController) +} diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/SILKeychainViewController.swift b/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/SILKeychainViewController.swift index fd049bee..0258d2af 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/SILKeychainViewController.swift +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/KeyChains/SILKeychainViewController.swift @@ -18,6 +18,7 @@ class SILKeychainViewController: UIViewController { @IBOutlet weak var tableView: UITableView! @IBOutlet weak var tableLeftInset: NSLayoutConstraint! @IBOutlet weak var tableRightInset: NSLayoutConstraint! + @IBOutlet weak var infoImage: UIImageView! var popoverController: WYPopoverController? var realmCharacteristicsNotificationToken: NotificationToken? = nil @@ -55,8 +56,19 @@ class SILKeychainViewController: UIViewController { super.viewDidLoad() setupNotificationToken() setupTableViewInsets() + setupInfoImage() } + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + addObserverForDisplayToastResponse() + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + NotificationCenter.default.removeObserver(self) + } + private func setupNotificationToken() { if self.characteristics != nil { setupCharacteristicsNotificationTokenIfNeeded() @@ -104,6 +116,30 @@ class SILKeychainViewController: UIViewController { } } + private func setupInfoImage() { + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tappedInfoImage(_:))) + self.infoImage.addGestureRecognizer(tapGesture) + } + + @objc private func tappedInfoImage(_ regognizer: UIGestureRecognizer) { + let storyboard = UIStoryboard(name: "SILKeychain", bundle: nil) + if let infoViewController = storyboard.instantiateViewController(withIdentifier: "KeychainInfo") as? SILKeychainInfoViewController { + infoViewController.delegate = self + self.popoverController = WYPopoverController.sil_presentCenterPopover(withContentViewController: infoViewController, presenting:self, delegate:self as? WYPopoverControllerDelegate, animated:true) + } + } + + private func addObserverForDisplayToastResponse() { + NotificationCenter.default.addObserver(self, selector:#selector(displayToast(_:)), name: NSNotification.Name(rawValue: SILNotificationDisplayToastResponse), object: nil) + } + + @objc private func displayToast(_ notification: Notification) { + let ErrorMessage = notification.userInfo?[SILNotificationKeyDescription] as? String ?? "" + self.showToast(message: ErrorMessage, toastType: .disconnectionError) { + NotificationCenter.default.post(name: NSNotification.Name(rawValue: SILNotificationDisplayToastRequest), object: nil) + } + } + @IBAction func back(_ sender: UIButton) { self.navigationController?.popViewController(animated: true) } @@ -209,3 +245,11 @@ extension SILKeychainViewController : SILDebugPopoverViewControllerDelegate { } } } + +extension SILKeychainViewController : SILKeychainInfoViewContollerDelegate { + func shouldCloseInfoViewController(_ infoViewController: SILKeychainInfoViewController) { + self.popoverController?.dismissPopover(animated: true) { + self.popoverController = nil + } + } +} diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/SILBluetoothBrowserViewController.m b/SiliconLabsApp/ViewControllers/BluetoothBrowser/SILBluetoothBrowserViewController.m index 09970303..f7cdeec5 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/SILBluetoothBrowserViewController.m +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/SILBluetoothBrowserViewController.m @@ -43,7 +43,6 @@ @interface SILBluetoothBrowserViewController () * expandSections; @@ -77,20 +77,20 @@ - (void)viewDidLoad { [self setupBrowserExpandableViewManager]; [self setupButtonsTabBar]; [self setupScanningButton]; - [self registerForApplicationWillResignActiveNotification]; [self setupBrowserViewModel]; [self installViewModelsForExpandableViews]; [self setupBackgroundForScanning:YES]; [self setScanningButtonAppearanceWithScanning:_isScanning]; - [self addObservers]; - [self updateConnectionsButtonTitle]; [self setupBrowserTableViewAppearance]; + [self clearViewModelsForExpandableViews]; } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; self.browserViewModel.observing = YES; [self manageScannerState]; + [self addObservers]; + [self updateConnectionsButtonTitle]; } - (void)viewDidAppear:(BOOL)animated { @@ -105,6 +105,7 @@ - (void)viewWillDisappear:(BOOL)animated { self.browserViewModel.observing = NO; [self setScannerStateWhenControllerIsDisappeared]; [self.browserViewModel clearIsConnectingDirectory]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; } #pragma mark - Setup @@ -149,7 +150,7 @@ - (void)setupBrowserExpandableViewManager { } - (void)setupButtonsTabBar { - [self.browserExpandableViewManager setupButtonsTabBarWithLog:self.logButton connections:self.connectionsButton filter:self.filterButton andActiveFilterImage:self.activeFilterImage]; + [self.browserExpandableViewManager setupButtonsTabBarWithLog:self.logButton connections:self.connectionsButton filter:self.filterButton andFilterIsActive:[self.filterViewModel isFilterActive]]; } - (void)setupScanningButton { @@ -170,11 +171,9 @@ - (void)setupBrowserViewModel { } - (void)installViewModelsForExpandableViews { - SILBrowserLogViewModel* browserLog = [SILBrowserLogViewModel sharedInstance]; self.connectionsViewModel = [SILBrowserConnectionsViewModel sharedInstance]; self.connectionsViewModel.centralManager = self.browserViewModel.centralManager; - [self.connectionsViewModel disconnectAllPeripheral]; - [browserLog clearLogs]; + self.filterViewModel = [SILBrowserFilterViewModel sharedInstance]; } - (void)setupBackgroundForScanning:(BOOL)scanning { @@ -189,6 +188,8 @@ - (void)setupBackgroundForScanning:(BOOL)scanning { - (void)addObservers { [self addObserversForReloadBrowserTableView]; [self addObserverForReloadConnectionsButtonTitle]; + [self addObserverForDisplayToastResponse]; + [self registerForApplicationWillResignActiveNotification]; } - (void)addObserversForReloadBrowserTableView { @@ -210,6 +211,17 @@ - (void)updateConnectionsButtonTitle { [self.browserExpandableViewManager updateConnectionsButtonTitle:connections]; } +- (void)addObserverForDisplayToastResponse { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displayToast:) name:SILNotificationDisplayToastResponse object:nil]; +} + +- (void)displayToast:(NSNotification*)notification { + NSString* ErrorMessage = notification.userInfo[SILNotificationKeyDescription]; + [self showToastWithMessage:ErrorMessage toastType:ToastTypeDisconnectionError completion:^{ + [[NSNotificationCenter defaultCenter] postNotificationName:SILNotificationDisplayToastRequest object:nil]; + }]; +} + #pragma mark - SILDebugDeviceViewModelDelegate - (void)didConnectToPeripheral:(CBPeripheral *)peripheral { @@ -266,10 +278,10 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N } return cell; } else { - SILBrowserServiceViewCell *cell = [tableView + SILBrowserDeviceAdTypeViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SILClassBrowserServiceViewCell forIndexPath:indexPath]; - [self configureServiceCell:cell atIndexPath:indexPath]; + [self configureAdTypeCell:cell atIndexPath:indexPath]; if (@available(iOS 13, *)) {} else { if ([tableView numberOfRowsInSection:indexPath.section]-1 == indexPath.row) { cell.isRounded = YES; @@ -328,11 +340,11 @@ - (void)configureDeviceCell:(SILBrowserDeviceViewCell*)cell atIndexPath:(NSIndex } } -- (void)configureServiceCell:(SILBrowserServiceViewCell*)cell atIndexPath:(NSIndexPath *)indexPath { +- (void)configureAdTypeCell:(SILBrowserDeviceAdTypeViewCell*)cell atIndexPath:(NSIndexPath *)indexPath { SILDiscoveredPeripheralDisplayDataViewModel *discoveredPeripheralViewModel = [self.browserViewModel peripheralViewModelAt:indexPath.section]; SILAdvertisementDataViewModel *detailModel = discoveredPeripheralViewModel.advertisementDataViewModelsForInfoView[indexPath.row-1]; - cell.serviceNameLabel.text = detailModel.typeString; - cell.serviceUUIDLabel.text = detailModel.valueString; + cell.adTypeNameLabel.text = detailModel.typeString; + cell.adTypeValueLabel.text = detailModel.valueString; } - (BOOL)isConnectedPeripheral:(SILDiscoveredPeripheral*)peripheral { @@ -363,7 +375,7 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPa if (indexPath.row == 0) { return 121.0; } - return 76.0; + return UITableViewAutomaticDimension; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { @@ -584,11 +596,7 @@ - (void)searchButtonWasTapped:(SILBrowserFilterViewModel *)filterViewModel { } - (void)manageAppearanceOfActiveFilterImage:(SILBrowserFilterViewModel*)filterViewModel { - if ([filterViewModel isFilterActive]) { - [self.activeFilterImage setHidden:NO]; - } else { - [self.activeFilterImage setHidden:YES]; - } + [self.browserExpandableViewManager updateFilterIsActiveFilter:[filterViewModel isFilterActive]]; } - (void)filterBrowser:(SILBrowserFilterViewModel*)filterViewModel { @@ -605,11 +613,6 @@ - (void)setFilters:(SILBrowserFilterViewModel*)filterViewModel { } else { self.browserViewModel.searchByDeviceName = nil; } - if (![filterViewModel.searchByRawAdvertisingData isEqualToString:EmptyText]) { - self.browserViewModel.searchByAdvertisingData = filterViewModel.searchByRawAdvertisingData; - } else { - self.browserViewModel.searchByAdvertisingData = nil; - } self.browserViewModel.currentMinRSSI = [NSNumber numberWithInteger:filterViewModel.dBmValue]; self.browserViewModel.beaconTypes = filterViewModel.beaconTypes; self.browserViewModel.isFavourite = filterViewModel.isFavouriteFilterSet; @@ -639,6 +642,7 @@ - (void)presentDetailsViewControllerForIndex:(NSInteger)index { detailsVC.centralManager = self.browserViewModel.centralManager; [self updateCellsWithConnecting:connectedPeripheral.peripheral]; [self removeUnfiredTimers]; + [self.browserExpandableViewManager removeExpandingControllerIfNeeded]; [self.navigationController pushViewController:detailsVC animated:YES]; } @@ -650,9 +654,17 @@ - (void)logViewBackButtonPressed { - (IBAction)backToDevelopWasTapped:(id)sender { [self stopScanningAction]; + [self.connectionsViewModel disconnectAllPeripheral]; [self.navigationController popViewControllerAnimated:NO]; } +- (void)clearViewModelsForExpandableViews { + [self.connectionsViewModel clearViewModelData]; + [self.filterViewModel clearViewModelData]; + SILBrowserLogViewModel* browserLog = [SILBrowserLogViewModel sharedInstance]; + [browserLog clearLogs]; +} + - (void)scrollViewDidScroll:(UIScrollView *)scrollView { if ([self isSignificatantScrollToTop:scrollView]) { [self.browserViewModel stopScanningWithVisibleCellsCount:0]; diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILAnimatedUIButton.swift b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILAnimatedUIButton.swift new file mode 100644 index 00000000..7e104a9b --- /dev/null +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILAnimatedUIButton.swift @@ -0,0 +1,28 @@ +// +// SILAnimatedUIButton.swift +// BlueGecko +// +// Created by Kamil Czajka on 01/06/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import UIKit + +class SILAnimatedUIButton: UIButton { + override func awakeFromNib() { + super.awakeFromNib() + self.addTarget(self, action: #selector(buttonClicked(sender:)), for: .touchUpInside) + } + + @objc private func buttonClicked(sender: UIButton) { + UIView.animate(withDuration: 0.1, animations: {() -> Void in + sender.imageView?.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) + sender.alpha = 0.5 + }, completion: {(_ finished: Bool) -> Void in + UIView.animate(withDuration: 0.2, animations: {() -> Void in + sender.imageView?.transform = CGAffineTransform(scaleX: 1, y: 1) + sender.alpha = 1.0 + }) + }) + } +} diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILBluetoothBrowserExpandableViewManager.h b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILBluetoothBrowserExpandableViewManager.h index 11b2a296..153c836e 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILBluetoothBrowserExpandableViewManager.h +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILBluetoothBrowserExpandableViewManager.h @@ -20,12 +20,13 @@ - (void)setReferenceForPresentationView:(UIView*)presentationView andDiscoveredDevicesView:(UIView*)discoveredDevicesView; - (void)setReferenceForExpandableControllerView:(UIView*)expandableControllerView andExpandableControllerHeight:(NSLayoutConstraint*)expandableControllerHeight; - (void)setupButtonsTabBarWithLog:(UIButton*)logButton connections:(UIButton*)connectionsButton; -- (void)setupButtonsTabBarWithLog:(UIButton*)logButton connections:(UIButton*)connectionsButton filter:(UIButton*)filterButton andActiveFilterImage:(UIImageView*)activeImageView; +- (void)setupButtonsTabBarWithLog:(UIButton*)logButton connections:(UIButton*)connectionsButton filter:(UIButton*)filterButton andFilterIsActive:(BOOL)isActive; - (SILBrowserLogViewController*)logButtonWasTappedAction; - (SILBrowserConnectionsViewController*)connectionsButtonWasTappedAction; - (SILBrowserFilterViewController*)filterButtonWasTappedAction; - (void)removeExpandingControllerIfNeeded; - (void)updateConnectionsButtonTitle:(NSUInteger)connections; +- (void)updateFilterIsActiveFilter:(BOOL)isActiveFilter; @end diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILBluetoothBrowserExpandableViewManager.m b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILBluetoothBrowserExpandableViewManager.m index 48a03f4a..1f50bb04 100644 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILBluetoothBrowserExpandableViewManager.m +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Utils/SILBluetoothBrowserExpandableViewManager.m @@ -21,7 +21,6 @@ @interface SILBluetoothBrowserExpandableViewManager () @property (strong, nonatomic) UIButton* logButton; @property (strong, nonatomic) UIButton* connectionsButton; @property (strong, nonatomic) UIButton* filterButton; -@property (strong, nonatomic) UIImageView* activeFilterImageView; @property (strong, nonatomic) NSLayoutConstraint* expandableControllerHeight; @property (strong, nonatomic) UIView* expandableControllerView; @property (strong, nonatomic) UIViewController* expandingViewController; @@ -51,14 +50,13 @@ - (void)setupButtonsTabBarWithLog:(UIButton*)logButton connections:(UIButton*)co [self setupConnectionButton]; } -- (void)setupButtonsTabBarWithLog:(UIButton*)logButton connections:(UIButton*)connectionsButton filter:(UIButton*)filterButton andActiveFilterImage:(UIImageView*)activeImageView { +- (void)setupButtonsTabBarWithLog:(UIButton*)logButton connections:(UIButton*)connectionsButton filter:(UIButton*)filterButton andFilterIsActive:(BOOL)isActive { self.logButton = logButton; self.connectionsButton = connectionsButton; self.filterButton = filterButton; - self.activeFilterImageView = activeImageView; [self setupLogButton]; [self setupConnectionButton]; - [self setupFilterButton]; + [self setupFilterButtonWhereIsFilterActive:isActive]; } - (void)setReferenceForPresentationView:(UIView*)presentationView andDiscoveredDevicesView:(UIView*)discoveredDevicesView { @@ -152,6 +150,14 @@ - (void)updateConnectionsButtonTitle:(NSUInteger)connections { [self.connectionsButton setTitle:connectionsText forState:UIControlStateSelected]; } +- (void)updateFilterIsActiveFilter:(BOOL)isActiveFiter { + if (isActiveFiter) { + [self setupImagesForActiveFilter]; + } else { + [self setupImagesForInactiveFilter]; + } +} + #pragma mark - Private Functions - (void)setupLogButton { @@ -186,13 +192,12 @@ - (void)setupConnectionButton { [self.connectionsButton setTitleColor:[UIColor sil_regularBlueColor] forState:UIControlStateSelected]; } -- (void)setupFilterButton { +- (void)setupFilterButtonWhereIsFilterActive:(BOOL)isFilterActive { UIEdgeInsets const ImageInsetsForFilterButton = {0, 8, 0 ,12}; UIEdgeInsets const TitleEdgeInsetsForFilterButton = {0, 8, 0, 8}; [self.filterButton setTintColor:[UIColor clearColor]]; - [self.filterButton setImage:[[UIImage imageNamed:SILImageSearchOff] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateNormal]; - [self.filterButton setImage:[[UIImage imageNamed:SILImageSearchOn] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateSelected]; + [self updateFilterIsActiveFilter:isFilterActive]; self.filterButton.imageView.contentMode = UIViewContentModeScaleAspectFit; self.filterButton.imageEdgeInsets = ImageInsetsForFilterButton; [self.filterButton setTitleEdgeInsets:TitleEdgeInsetsForFilterButton]; @@ -200,7 +205,17 @@ - (void)setupFilterButton { self.filterButton.titleLabel.font = [UIFont robotoMediumWithSize:[UIFont getMiddleFontSize]]; [self.filterButton setTitleColor:[UIColor sil_primaryTextColor] forState:UIControlStateNormal]; [self.filterButton setTitleColor:[UIColor sil_regularBlueColor] forState:UIControlStateSelected]; - [self.activeFilterImageView setHidden:YES]; + +} + +- (void)setupImagesForInactiveFilter { + [self.filterButton setImage:[[UIImage imageNamed:SILImageFilterOff] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateNormal]; + [self.filterButton setImage:[[UIImage imageNamed:SILImageFilterOffSelected] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateSelected]; +} + +- (void)setupImagesForActiveFilter { + [self.filterButton setImage:[[UIImage imageNamed:SILImageFilterOn] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateNormal]; + [self.filterButton setImage:[[UIImage imageNamed:SILImageFilterOnSelected] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] forState:UIControlStateSelected]; } - (BOOL)isAnyButtonSelected { diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Views/SILBrowserDeviceAdTypeViewCell.swift b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Views/SILBrowserDeviceAdTypeViewCell.swift new file mode 100644 index 00000000..0bce5c5b --- /dev/null +++ b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Views/SILBrowserDeviceAdTypeViewCell.swift @@ -0,0 +1,22 @@ +// +// SILBrowserDeviceAdTypeViewCell.swift +// BlueGecko +// +// Created by Jan Wisniewski on 03/02/2020. +// Copyright © 2020 SiliconLabs. All rights reserved. +// + +import UIKit + +class SILBrowserDeviceAdTypeViewCell: SILCell { + + @IBOutlet weak var adTypeNameLabel: UILabel! + @IBOutlet weak var adTypeValueLabel: UILabel! + + override func prepareForReuse() { + super.prepareForReuse() + adTypeNameLabel.text = "" + adTypeValueLabel.text = "" + } + +} diff --git a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Views/SILBrowserServiceViewCell.swift b/SiliconLabsApp/ViewControllers/BluetoothBrowser/Views/SILBrowserServiceViewCell.swift deleted file mode 100644 index c36ca32c..00000000 --- a/SiliconLabsApp/ViewControllers/BluetoothBrowser/Views/SILBrowserServiceViewCell.swift +++ /dev/null @@ -1,22 +0,0 @@ -// -// SILBrowserServiceViewCell.swift -// BlueGecko -// -// Created by Jan Wisniewski on 03/02/2020. -// Copyright © 2020 SiliconLabs. All rights reserved. -// - -import UIKit - -class SILBrowserServiceViewCell: SILCell { - - @IBOutlet weak var serviceNameLabel: UILabel! - @IBOutlet weak var serviceUUIDLabel: UILabel! - - override func prepareForReuse() { - super.prepareForReuse() - serviceNameLabel.text = "" - serviceUUIDLabel.text = "" - } - -} diff --git a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicEncodingFieldTableViewCell.h b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicEncodingFieldTableViewCell.h index 334f059e..13321080 100644 --- a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicEncodingFieldTableViewCell.h +++ b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicEncodingFieldTableViewCell.h @@ -13,4 +13,5 @@ @property(weak, nonatomic) IBOutlet UILabel *asciiValueLabel; @property(weak, nonatomic) IBOutlet UILabel *decimalValueLabel; @property(weak, nonatomic) IBOutlet UILabel* editLabel; +- (void)clearValues; @end diff --git a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicEncodingFieldTableViewCell.m b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicEncodingFieldTableViewCell.m index 499a392a..cfc28dd6 100644 --- a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicEncodingFieldTableViewCell.m +++ b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicEncodingFieldTableViewCell.m @@ -30,4 +30,10 @@ - (void)awakeFromNib { } } +- (void)clearValues { + self.hexValueLabel.text = @""; + self.asciiValueLabel.text = @""; + self.decimalValueLabel.text = @""; +} + @end diff --git a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicTableViewCell.m b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicTableViewCell.m index 989ac979..40f42877 100644 --- a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicTableViewCell.m +++ b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugCharacteristicTableViewCell.m @@ -24,7 +24,6 @@ @interface SILDebugCharacteristicTableViewCell() @property (weak, nonatomic) IBOutlet UIStackView *propertyButtonsStackView; @property (weak, nonatomic) IBOutlet UILabel *characteristicNameLabel; @property (weak, nonatomic) IBOutlet UILabel *characteristicUuidLabel; -@property (weak, nonatomic) IBOutlet UIImageView *viewMoreChevron; @property (weak, nonatomic) IBOutlet NSLayoutConstraint *iPadBottomDividerLeadingConstraint; @property (weak, nonatomic) IBOutlet UILabel *descriptorsTextLabel; @property (weak, nonatomic) IBOutlet UIView *descriptorsView; @@ -43,8 +42,6 @@ @interface SILDebugCharacteristicTableViewCell() @implementation SILDebugCharacteristicTableViewCell -NSString * const KVONotifyingName = @"notifying"; - - (void)awakeFromNib { [super awakeFromNib]; self.selectionStyle = UITableViewCellSelectionStyleNone; @@ -52,7 +49,6 @@ - (void)awakeFromNib { } - (void)configureWithCharacteristicModel:(SILCharacteristicTableModel *)characteristicModel { - [self updateChevronImageForExpanded:characteristicModel.isExpanded]; self.characteristicTableModel = characteristicModel; self.characteristic = characteristicModel.characteristic; [self.nameEditButton setHidden:!characteristicModel.isMappable]; @@ -65,10 +61,9 @@ - (void)configureWithCharacteristicModel:(SILCharacteristicTableModel *)characte self.descriptorsTextLabel.text = [self getDescriptorsText:characteristicModel.descriptorModels]; } self.topSeparatorView.hidden = characteristicModel.hideTopSeparator; - [self configureAsExpandable:[characteristicModel canExpand] || [characteristicModel isUnknown]]; self.allActiveProperties = [SILDebugProperty getActivePropertiesFrom:characteristicModel.characteristic.properties]; [self configurePropertyViewsForProperties:self.allActiveProperties]; - [self togglePropertyEnabledIfExpanded]; + [self toggleProperties]; [self layoutIfNeeded]; } @@ -107,10 +102,6 @@ - (void)configureWithHomeKitCharacteristicModel:(SILHomeKitCharacteristicTableMo } #endif -- (void)configureAsExpandable:(BOOL)canExpand { - self.viewMoreChevron.hidden = !canExpand; -} - - (void)configurePropertyViewsForProperties:(NSArray *)properties { [self layoutIfNeeded]; @@ -137,70 +128,48 @@ - (void)configurePropertyViewsForProperties:(NSArray *)properties { #pragma mark - SILGenericAttributeTableCell - (void)expandIfAllowed:(BOOL)isExpanding { - [self togglePropertyEnabledIfExpanded]; - [self updateChevronImageForExpanded:isExpanding]; + [self toggleProperties]; } -- (void)updateChevronImageForExpanded:(BOOL)expanded { - self.viewMoreChevron.image = [UIImage imageNamed: expanded ? SILImageChevronExpanded : SILImageChevronCollapsed]; -} - -- (void)togglePropertyEnabledIfExpanded { - BOOL expanded = self.characteristicTableModel.isExpanded; - BOOL isNotifying = [[self.characteristic valueForKey:KVONotifyingName] boolValue]; +- (void)toggleProperties { + BOOL isNotifying = [self.characteristic isNotifying]; for (SILDebugProperty *property in self.allActiveProperties) { if ([property.keysForActivation.firstObject isEqual:@(CBCharacteristicPropertyRead)]) { - [self.readPropertyButton setUserInteractionEnabled:expanded]; - [self readButtonAppearanceWithCondition:expanded]; + [self readButtonAppearance]; } else if ([property.keysForActivation.firstObject isEqual:@(CBCharacteristicPropertyWrite)]) { - [self.writePropertyButton setUserInteractionEnabled:expanded]; - [self writeButtonAppearanceWithCondition:expanded]; + [self writeButtonAppearance]; } else if ([property.keysForActivation.firstObject isEqual:@(CBCharacteristicPropertyWriteWithoutResponse)]) { - [self.writeNoResponsePropertyButton setUserInteractionEnabled:expanded]; - [self writeNoResponseButtonAppearanceWithCondition:expanded]; + [self writeNoResponseButtonAppearance]; } else if ([property.keysForActivation.firstObject isEqual:@(CBCharacteristicPropertyIndicate)]) { - [self.indicatePropertyButton setUserInteractionEnabled:expanded]; - [self indicateButtonAppearanceWithCondition:(expanded && isNotifying)]; + [self indicateButtonAppearanceWithCondition:isNotifying]; } else if ([property.keysForActivation.firstObject isEqual:@(CBCharacteristicPropertyNotify)]) { - [self.notifyPropertyButton setUserInteractionEnabled:expanded]; - [self notifyButtonAppearanceWithCondition:(expanded && isNotifying)]; + [self notifyButtonAppearanceWithCondition:isNotifying]; } } } #pragma mark - Buttons Appearance -- (void)readButtonAppearanceWithCondition:(BOOL)condition { - NSString *readImageString = condition ? SILImageNamePropertyRead : SILImageNamePropertyReadDisabled; + +- (void)readButtonAppearance { + NSString *readImageString = SILImageNamePropertyReadDisabled; self.readPropertyButton.imageView.contentMode = UIViewContentModeScaleAspectFit; [self.readPropertyButton setImage:[UIImage imageNamed:readImageString] forState:UIControlStateNormal]; - if (condition) { - [self.readPropertyButton setTitleColor:[UIColor sil_regularBlueColor] forState:UIControlStateNormal]; - } else { - [self.readPropertyButton setTitleColor:[UIColor sil_primaryTextColor] forState:UIControlStateNormal]; - } + [self.readPropertyButton setTitleColor:[UIColor sil_primaryTextColor] forState:UIControlStateNormal]; } -- (void)writeButtonAppearanceWithCondition:(BOOL)condition { - NSString *writeImageString = condition ? SILImageNamePropertyWrite : SILImageNamePropertyWriteDisabled; +- (void)writeButtonAppearance { + NSString *writeImageString = SILImageNamePropertyWriteDisabled; self.writePropertyButton.imageView.contentMode = UIViewContentModeScaleAspectFit; [self.writePropertyButton setImage:[UIImage imageNamed:writeImageString] forState:UIControlStateNormal]; - if (condition) { - [self.writePropertyButton setTitleColor:[UIColor sil_regularBlueColor] forState:UIControlStateNormal]; - } else { - [self.writePropertyButton setTitleColor:[UIColor sil_primaryTextColor] forState:UIControlStateNormal]; - } + [self.writePropertyButton setTitleColor:[UIColor sil_primaryTextColor] forState:UIControlStateNormal]; } -- (void)writeNoResponseButtonAppearanceWithCondition:(BOOL)condition { - NSString *writeImageString = condition ? SILImageNamePropertyWriteNoResponse : SILImageNamePropertyWriteNoResponseDisabled; +- (void)writeNoResponseButtonAppearance { + NSString *writeImageString = SILImageNamePropertyWriteNoResponseDisabled; self.writeNoResponsePropertyButton.imageView.contentMode = UIViewContentModeScaleAspectFit; [self.writeNoResponsePropertyButton setImage:[UIImage imageNamed:writeImageString] forState:UIControlStateNormal]; - if (condition) { - [self.writeNoResponsePropertyButton setTitleColor:[UIColor sil_regularBlueColor] forState:UIControlStateNormal]; - } else { - [self.writeNoResponsePropertyButton setTitleColor:[UIColor sil_primaryTextColor] forState:UIControlStateNormal]; - } + [self.writeNoResponsePropertyButton setTitleColor:[UIColor sil_primaryTextColor] forState:UIControlStateNormal]; } - (void)indicateButtonAppearanceWithCondition:(BOOL)condition { @@ -228,27 +197,36 @@ - (void)notifyButtonAppearanceWithCondition:(BOOL)condition { #pragma mark - Button Actions - (IBAction)handleReadViewTap:(id)sender { + [self.characteristicTableModel expandFieldIfNeeded]; [self.delegate cell:self didRequestReadForCharacteristic:self.characteristic]; } - (IBAction)handleWriteViewTap:(id)sender { + [self.characteristicTableModel expandFieldIfNeeded]; [self.delegate cell:self didRequestWriteForCharacteristic:self.characteristic]; } - (IBAction)handleWriteNoResponseViewTap:(id)sender { + [self.characteristicTableModel expandFieldIfNeeded]; [self.delegate cell:self didRequestWriteNoResponseForCharacteristic:self.characteristic]; } - (IBAction)handleIndicateViewTap:(id)sender { - BOOL newNotifyingValue = ![[self.characteristic valueForKey:KVONotifyingName] boolValue]; - [self.delegate cell:self didRequestIndicateForCharacteristic:self.characteristic withValue:newNotifyingValue]; + BOOL newNotifyingValue = ![self.characteristic isNotifying]; [self indicateButtonAppearanceWithCondition:newNotifyingValue]; + if (newNotifyingValue) { + [self.characteristicTableModel expandFieldIfNeeded]; + } + [self.delegate cell:self didRequestIndicateForCharacteristic:self.characteristic withValue:newNotifyingValue]; } - (IBAction)handleNotifyViewTap:(id)sender { - BOOL newNotifyingValue = ![[self.characteristic valueForKey:KVONotifyingName] boolValue]; - [self.delegate cell:self didRequestNotifyForCharacteristic:self.characteristic withValue:newNotifyingValue]; + BOOL newNotifyingValue = ![self.characteristic isNotifying]; [self notifyButtonAppearanceWithCondition:newNotifyingValue]; + if (newNotifyingValue) { + [self.characteristicTableModel expandFieldIfNeeded]; + } + [self.delegate cell:self didRequestNotifyForCharacteristic:self.characteristic withValue:newNotifyingValue]; } - (IBAction)editName:(UIButton *)sender { diff --git a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugServicesViewController.m b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugServicesViewController.m index 34c4c0bb..45748d38 100644 --- a/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugServicesViewController.m +++ b/SiliconLabsApp/ViewControllers/DebugApp/ServicesTable/SILDebugServicesViewController.m @@ -59,7 +59,7 @@ static float kTableRefreshInterval = 1; -@interface SILDebugServicesViewController () +@interface SILDebugServicesViewController () @property (weak, nonatomic) IBOutlet UILabel *deviceNameLabel; @property (weak, nonatomic) IBOutlet UILabel *rssiLabel; @@ -77,7 +77,7 @@ @interface SILDebugServicesViewController () *)touches withEvent:(UIEvent *)event { + [super touchesBegan:touches withEvent:event]; + [self hideMenu]; +} + +- (void)showMenu { + [self.menuContainer setHidden:NO]; + self.tableView.userInteractionEnabled = NO; +} + +- (void)hideMenu { + [self.menuContainer setHidden:YES]; + self.tableView.userInteractionEnabled = YES; +} + #pragma mark - Expandable Controllers - (IBAction)connectionsButtonTapped:(id)sender { @@ -253,6 +306,11 @@ - (void)handleRefreshServices: (UIRefreshControl *)sender { - (void)otaUICoordinatorDidFishishOTAFlow:(SILOTAUICoordinator *)coordinator { [self.navigationController popViewControllerAnimated:YES]; + self.isUpdatingFirmware = NO; +} + +- (void)otaUICoordinatorDidCancelOTAFlow:(SILOTAUICoordinator *)coordinator { + self.isUpdatingFirmware = NO; } #pragma mark - Notifications @@ -268,11 +326,26 @@ - (void)addObserverForUpdateConnectionsButtonTitle { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateConnectionsButtonTitle) name:SILNotificationReloadConnectionsTableView object:nil]; } +- (void)addObserverForDisplayToastResponse { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(displayToast:) name:SILNotificationDisplayToastResponse object:nil]; +} + +- (void)displayToast:(NSNotification*)notification { + NSString* ErrorMessage = notification.userInfo[SILNotificationKeyDescription]; + [self showToastWithMessage:ErrorMessage toastType:ToastTypeDisconnectionError completion:^{ + [[NSNotificationCenter defaultCenter] postNotificationName:SILNotificationDisplayToastRequest object:nil]; + }]; +} + #pragma mark - Notification Methods - (void)didDisconnectPeripheralNotifcation:(NSNotification *)notification { - if (!self.isUpdatingFirmware) { - [self.navigationController popViewControllerAnimated:YES]; + NSString* uuid = (NSString*)notification.userInfo[SILNotificationKeyUUID]; + + if ([uuid isEqualToString:self.peripheral.identifier.UUIDString]) { + if (!self.isUpdatingFirmware) { + [self.navigationController popViewControllerAnimated:YES]; + } } } @@ -352,7 +425,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { if ([[tableView cellForRowAtIndexPath:indexPath] isKindOfClass:[SILDebugCharacteristicTableViewCell class]]) { SILCharacteristicTableModel *characteristicModel = self.modelsToDisplay[indexPath.row]; - [characteristicModel readCharacteristicIfAllowed]; if ([characteristicModel isUnknown]) { [characteristicModel toggleExpansionIfAllowed]; id cell = [tableView cellForRowAtIndexPath:indexPath]; @@ -625,10 +697,33 @@ - (void)editNameForCharacteristic:(SILCharacteristicTableModel*)model { #pragma mark - SILDebugCharacteristicCellDelegate - (void)cell:(SILDebugCharacteristicTableViewCell *)cell didRequestReadForCharacteristic:(CBCharacteristic *)characteristic { + BOOL isPerformed = [cell.characteristicTableModel clearModel]; + if (!isPerformed) { + [self performManualClearingValuesIntoEncodingFieldTableViewCell:characteristic]; + } else { + [self refreshTable]; + } [self.peripheral readValueForCharacteristic:characteristic]; } +- (void)performManualClearingValuesIntoEncodingFieldTableViewCell:(CBCharacteristic*)characteristic { + for (id model in self.modelsToDisplay) { + if ([model isKindOfClass:[SILCharacteristicTableModel class]]) { + SILCharacteristicTableModel* characteristicModel = (SILCharacteristicTableModel*)model; + if ([characteristicModel isUnknown] && characteristicModel.characteristic == characteristic) { + NSUInteger index = [self.modelsToDisplay indexOfObject:model] + 1; + SILDebugCharacteristicTableViewCell* cell = [self.tableView cellForRowAtIndexPath:[NSIndexPath indexPathForRow:index inSection:0]]; + if ([cell isKindOfClass:[SILDebugCharacteristicEncodingFieldTableViewCell class]]) { + SILDebugCharacteristicEncodingFieldTableViewCell* encodingCell = (SILDebugCharacteristicEncodingFieldTableViewCell*)cell; + [encodingCell clearValues]; + } + } + } + } +} + - (void)cell:(SILDebugCharacteristicTableViewCell *)cell didRequestWriteForCharacteristic:(CBCharacteristic *)characteristic { + [self refreshTable]; if (cell.characteristicTableModel.isUnknown) { SILEncodingPseudoFieldRowModel *model = [[SILEncodingPseudoFieldRowModel alloc]initForCharacteristicModel:cell.characteristicTableModel]; [self displayCharacteristicEncoding:model.parentCharacteristicModel canEdit:model.parentCharacteristicModel.canWrite]; @@ -694,7 +789,7 @@ - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForServi - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { [CrashlyticsKit setObjectValue:peripheral.name forKey:@"peripheral"]; [self addOrUpdateModelForCharacteristic:characteristic forService:characteristic.service]; - [self markTableForUpdate]; + [self refreshTable]; [self postRegisterLogNotification:[SILLogDataModel prepareLogDescription:@"didUpdateValueForCharacteristic: " andCharacteristic:characteristic andPeripheral:peripheral andError:error]]; } @@ -734,6 +829,20 @@ - (void)peripheral:(CBPeripheral *)peripheral didReadRSSI:(NSNumber *)RSSI error self.rssiLabel.text = rssiDescription; } +- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error { + NSLog(@"%@", error); + if (error == nil) { + [self postRegisterLogNotification:[SILLogDataModel prepareLogDescription:@"didUpdateNotificationStateForCharacteristic: Successful! " andCharacteristic:characteristic andPeripheral:peripheral andError:error]]; + } else { + [self postRegisterLogNotification:[SILLogDataModel prepareLogDescription:@"didUpdateNotificationStateForCharacteristic: Failed! " andCharacteristic:characteristic andPeripheral:peripheral andError:error]]; + + SILGattPropertiesErrorToastModel* errorToast = [[SILGattPropertiesErrorToastModel alloc] initWithPeripheralName:peripheral.name errorCode:error.code]; + NSString* ErrorMessage = [errorToast getErrorMessageForToast]; + [self showToastWithMessage:ErrorMessage toastType:ToastTypeGattPropertiesError completion:^{}]; + } + [self refreshTable]; +} + #pragma mark - Add or Update Attribute Models - (BOOL)addOrUpdateModelForService:(CBService *)service { @@ -914,9 +1023,9 @@ - (void)refreshTable { - (void)configureOtaButtonWithPeripheral:(CBPeripheral *)peripheral { if ([peripheral hasOTAService]) { - [self.otaButton setHidden:NO]; + [self.menuButton setHidden:NO]; } else { - [self.otaButton setHidden:YES]; + [self.menuButton setHidden:YES]; } } @@ -948,6 +1057,7 @@ - (void)presentDetailsViewControllerForIndex:(NSInteger)index { self.peripheral = connectedPeripheral.peripheral; [self.refreshControl removeFromSuperview]; self.refreshControl = nil; + self.allServiceModels = nil; [self viewDidLoad]; [self viewWillAppear:YES]; [self viewDidAppear:YES]; diff --git a/SiliconLabsApp/ViewModels/DebugDeviceViewModel.swift b/SiliconLabsApp/ViewModels/DebugDeviceViewModel.swift index 6f4e4a7d..7608fd56 100644 --- a/SiliconLabsApp/ViewModels/DebugDeviceViewModel.swift +++ b/SiliconLabsApp/ViewModels/DebugDeviceViewModel.swift @@ -80,7 +80,7 @@ final class DebugDeviceViewModel: NSObject { var peripheralDisconnectedMessage: String? { guard let peripheral = connectedPeripheral else { return nil } - let peripheralName = peripheral.name ?? "Unknown" + let peripheralName = peripheral.name ?? DefaultDeviceName return "Disconnected from \(peripheralName)" } diff --git a/SiliconLabsApp/ViewModels/SILAdvertisementDataViewModel.m b/SiliconLabsApp/ViewModels/SILAdvertisementDataViewModel.m index fb7d5954..7b148849 100644 --- a/SiliconLabsApp/ViewModels/SILAdvertisementDataViewModel.m +++ b/SiliconLabsApp/ViewModels/SILAdvertisementDataViewModel.m @@ -9,11 +9,18 @@ #import "SILAdvertisementDataViewModel.h" #import "SILBluetoothModelManager.h" -NSString * const kAdModelTypeUUID = @"UUID"; -NSString * const kAdModelTypeName = @"LOCAL NAME"; -NSString * const kAdModelTypePower = @"POWER LEVEL"; -NSString * const kAdModelTypeMajor = @"MAJOR"; -NSString * const kAdModelTypeMinor = @"MINOR"; +NSString * const kAdModelTypeAdvertisedServiceUUIDs16Bit = @"List of 16-bit Advertised Service UUIDs"; +NSString * const kAdModelTypeAdvertisedServiceUUIDs32Bit = @"List of 32-bit Advertised Service UUIDs"; +NSString * const kAdModelTypeAdvertisedServiceUUIDs128Bit = @"List of 128-bit Advertised Service UUIDs"; +NSString * const kAdModelTypeSolicitedServiceUUIDs16Bit = @"List of 16-bit Solicited Service UUIDs"; +NSString * const kAdModelTypeSolicitedServiceUUIDs128Bit = @"List of 128-bit Solicited Service UUIDs"; +NSString * const kAdModelTypeName = @"Complete Local Name"; +NSString * const kAdModelTypeTXPowerLevel = @"TX Power Level"; +NSString * const kAdModelTypeManufacturerData = @"Manufacturer Specific Data"; +NSString * const kAdModelTypeDataServiceData = @"Data Service Data"; +NSString * const kAdModelTypeIBeacon = @"iBeacon Data"; +NSString * const kAdModelTypeAltBeacon = @"AltBeacon Data"; +NSString * const kAdModelTypeEddystoneBeacon = @"Eddystone Data"; @interface SILAdvertisementDataViewModel () @@ -55,34 +62,48 @@ - (NSString *)typeString { - (NSString *)valueStringForType:(AdModelType)type { NSString *valueString; - if (type == AdModelTypeServiceUUID) { - valueString = [NSString stringWithFormat:@"0X%@", _advertisementDataModel.value]; - } else { - valueString = _advertisementDataModel.value; - } + valueString = _advertisementDataModel.value; return valueString; } - (NSString *)typeStringForType:(AdModelType)type { NSString *typeString; switch (type) { - case AdModelTypeName: + case AdModelTypeCompleteLocalName: typeString = kAdModelTypeName; break; - case AdModelTypeMajor: - typeString = kAdModelTypeMajor; + case AdModelTypeSolicitedServiceUUIDs16Bit: + typeString = kAdModelTypeSolicitedServiceUUIDs16Bit; + break; + case AdModelTypeSolicitedServiceUUIDs128Bit: + typeString = kAdModelTypeSolicitedServiceUUIDs128Bit; + break; + case AdModelTypeTXPowerLevel: + typeString = kAdModelTypeTXPowerLevel; + break; + case AdModelTypeManufacturerData: + typeString = kAdModelTypeManufacturerData; + break; + case AdModelTypeAdvertisedServiceUUIDs16Bit: + typeString = kAdModelTypeAdvertisedServiceUUIDs16Bit; break; - case AdModelTypeUUID: - typeString = kAdModelTypeUUID; + case AdModelTypeAdvertisedServiceUUIDs32Bit: + typeString = kAdModelTypeAdvertisedServiceUUIDs32Bit; break; - case AdModelTypePower: - typeString = kAdModelTypePower; + case AdModelTypeAdvertisedServiceUUIDs128Bit: + typeString = kAdModelTypeAdvertisedServiceUUIDs128Bit; break; - case AdModelTypeMinor: - typeString = kAdModelTypeMinor; + case AdModelTypeDataServiceData: + typeString = kAdModelTypeDataServiceData; break; - case AdModelTypeServiceUUID: - typeString = [self typeStringForServiceUUIDValue:_advertisementDataModel.value]; + case AdModelTypeIBeacon: + typeString = kAdModelTypeIBeacon; + break; + case AdModelTypeAltBeacon: + typeString = kAdModelTypeAltBeacon; + break; + case AdModelTypeEddystoneBeacon: + typeString = kAdModelTypeEddystoneBeacon; break; default: break; @@ -90,9 +111,5 @@ - (NSString *)typeStringForType:(AdModelType)type { return typeString; } -- (NSString *)typeStringForServiceUUIDValue:(NSString *)value { - NSString *typeString = [[SILBluetoothModelManager sharedManager] serviceModelForUUIDString:value].name; - return typeString != nil ? typeString : @"UNKNOWN SERVICE"; -} - @end + diff --git a/SiliconLabsApp/ViewModels/SILBrowserFilterViewModel.h b/SiliconLabsApp/ViewModels/SILBrowserFilterViewModel.h index 7676cc6a..049b42ce 100644 --- a/SiliconLabsApp/ViewModels/SILBrowserFilterViewModel.h +++ b/SiliconLabsApp/ViewModels/SILBrowserFilterViewModel.h @@ -15,7 +15,6 @@ NS_ASSUME_NONNULL_BEGIN @interface SILBrowserFilterViewModel : NSObject @property (strong, nonatomic, readwrite) NSString *searchByDeviceName; -@property (strong, nonatomic, readwrite) NSString *searchByRawAdvertisingData; @property (nonatomic, readwrite) NSInteger dBmValue; @property (nonatomic, readwrite) BOOL isBeaconTypeExpanded; @property (nonatomic, readwrite) BOOL isFavouriteFilterSet; diff --git a/SiliconLabsApp/ViewModels/SILBrowserFilterViewModel.m b/SiliconLabsApp/ViewModels/SILBrowserFilterViewModel.m index a0a6effd..b0b6451a 100644 --- a/SiliconLabsApp/ViewModels/SILBrowserFilterViewModel.m +++ b/SiliconLabsApp/ViewModels/SILBrowserFilterViewModel.m @@ -53,7 +53,6 @@ - (void)installRealmDatabase { - (void)setDefaultValues { self.searchByDeviceName = EmptyText; - self.searchByRawAdvertisingData = EmptyText; self.dBmValue = DefaultDBMValue; self.isBeaconTypeExpanded = NO; self.isFavouriteFilterSet = NO; @@ -69,7 +68,6 @@ - (void)setDefaultValues { - (void)clearViewModelData { self.searchByDeviceName = EmptyText; - self.searchByRawAdvertisingData = EmptyText; self.dBmValue = DefaultDBMValue; self.isConnectableFilterSet = NO; self.isFavouriteFilterSet = NO; @@ -81,7 +79,6 @@ - (void)clearViewModelData { - (void)returnStateFrom:(SILBrowserSavedSearches*)savedSearch { self.searchByDeviceName = savedSearch.searchByDeviceNameText; - self.searchByRawAdvertisingData = savedSearch.searchByRawAdvetisingDataText; self.dBmValue = savedSearch.dBmValue; self.isFavouriteFilterSet = savedSearch.isFavourite; self.isConnectableFilterSet = savedSearch.isConnectable; @@ -168,13 +165,6 @@ - (void)setSearchByDeviceName:(NSString *)searchByDeviceName { } } -- (void)setSearchByRawAdvertisingData:(NSString *)searchByRawAdvertisingData { - if (_searchByRawAdvertisingData != searchByRawAdvertisingData) { - _searchByRawAdvertisingData = searchByRawAdvertisingData; - [self changeStateOfIsActiveFilterFromSavedSearchesIfNeeded]; - } -} - - (void)setDBmValue:(NSInteger)dBmValue { if (_dBmValue != dBmValue) { _dBmValue = dBmValue; @@ -206,7 +196,7 @@ - (void)changeStateOfIsActiveFilterFromSavedSearchesIfNeeded { #pragma mark - Saving Search - (void)saveCurrentFilterDataToSavedSearches { - SILBrowserSavedSearches* saveSearch = [[SILBrowserSavedSearches alloc] initWithSearchByDeviceNameText:_searchByDeviceName searchByRawAdveritisingDataText:_searchByRawAdvertisingData dBmValue:_dBmValue beaconTypes:_beaconTypes isFavourite:_isFavouriteFilterSet isConnectable:_isConnectableFilterSet andIsSelected:NO]; + SILBrowserSavedSearches* saveSearch = [[SILBrowserSavedSearches alloc] initWithSearchByDeviceNameText:_searchByDeviceName dBmValue:_dBmValue beaconTypes:_beaconTypes isFavourite:_isFavouriteFilterSet isConnectable:_isConnectableFilterSet andIsSelected:NO]; if ([self isUniqueSavedSearches:saveSearch]) { [_savedSearches addObject:saveSearch]; [self updateSavedSearches:[_savedSearches count] - 1]; @@ -220,7 +210,7 @@ - (void)saveCurrentFilterDataToSavedSearches { - (void)saveSearchInRealmDatabase:(SILBrowserSavedSearches*)savedSearch { SILSavedSearchesRealmModel* saveSearchRealm = [[SILSavedSearchesRealmModel alloc] init]; saveSearchRealm.searchByDeviceName = savedSearch.searchByDeviceNameText; - saveSearchRealm.searchByAdvertisingData = savedSearch.searchByRawAdvetisingDataText; + // saveSearchRealm.searchByAdvertisingData = savedSearch.searchByRawAdvetisingDataText; saveSearchRealm.dBmValue = savedSearch.dBmValue; saveSearchRealm.isFavouriteSetFilter = savedSearch.isFavourite; saveSearchRealm.isConnectableSetFilter = savedSearch.isConnectable; @@ -247,9 +237,6 @@ - (BOOL)isEqualTwoSavedSearches:(SILBrowserSavedSearches*)savedSearch andSecond: if (![savedSearch.searchByDeviceNameText isEqualToString:savedSearch2.searchByDeviceNameText]) { return NO; } - if (![savedSearch.searchByRawAdvetisingDataText isEqualToString:savedSearch2.searchByRawAdvetisingDataText]) { - return NO; - } if (savedSearch.dBmValue != savedSearch2.dBmValue) { return NO; } @@ -327,7 +314,7 @@ - (SILBrowserSavedSearches*)getSavedSearchRealmObject:(SILSavedSearchesRealmMode SILBrowserBeaconType* beacon = [[SILBrowserBeaconType alloc] initWithName:savedSearchBeacon.beaconName andSelection:savedSearchBeacon.isSelected]; [beaconTypes addObject:beacon]; } - SILBrowserSavedSearches* browserSavedSearch = [[SILBrowserSavedSearches alloc] initWithSearchByDeviceNameText:savedSearchRealm.searchByDeviceName searchByRawAdveritisingDataText:savedSearchRealm.searchByAdvertisingData dBmValue:savedSearchRealm.dBmValue beaconTypes:beaconTypes isFavourite:savedSearchRealm.isFavouriteSetFilter isConnectable:savedSearchRealm.isConnectableSetFilter andIsSelected:NO]; + SILBrowserSavedSearches* browserSavedSearch = [[SILBrowserSavedSearches alloc] initWithSearchByDeviceNameText:savedSearchRealm.searchByDeviceName dBmValue:savedSearchRealm.dBmValue beaconTypes:beaconTypes isFavourite:savedSearchRealm.isFavouriteSetFilter isConnectable:savedSearchRealm.isConnectableSetFilter andIsSelected:NO]; return browserSavedSearch; } @@ -337,9 +324,6 @@ - (BOOL)isFilterActive { if (![_searchByDeviceName isEqual:EmptyText]) { return YES; } - if (![_searchByRawAdvertisingData isEqual:EmptyText]) { - return YES; - } if (_dBmValue != DefaultDBMValue) { return YES; } @@ -389,14 +373,7 @@ - (NSString*)getStringRepresentationForObjectAtIndex:(NSUInteger)index { [stringRepresentation appendString:savedSearches.searchByDeviceNameText]; [stringRepresentation appendString:QuoteText]; } - - if (![savedSearches.searchByRawAdvetisingDataText isEqual:EmptyText]) { - [stringRepresentation appendString:SearchByPacketContent]; - [stringRepresentation appendString:QuoteText]; - [stringRepresentation appendString:savedSearches.searchByRawAdvetisingDataText]; - [stringRepresentation appendString:QuoteText]; - } - + if (savedSearches.isFavourite) { [stringRepresentation appendString:OnlyFavouritesTitle]; } diff --git a/SiliconLabsApp/ViewModels/SILDiscoveredPeripheralDisplayDataViewModel.h b/SiliconLabsApp/ViewModels/SILDiscoveredPeripheralDisplayDataViewModel.h index b9bad1be..6afa069d 100644 --- a/SiliconLabsApp/ViewModels/SILDiscoveredPeripheralDisplayDataViewModel.h +++ b/SiliconLabsApp/ViewModels/SILDiscoveredPeripheralDisplayDataViewModel.h @@ -15,7 +15,6 @@ @property (strong, nonatomic, readonly) SILDiscoveredPeripheralDisplayData *discoveredPeripheralDisplayData; @property (strong, nonatomic, readonly) NSArray *advertisementDataViewModels; -@property (strong, nonatomic, readonly) NSArray *advertisementDataViewModelsForDevicesTable; @property (strong, nonatomic, readonly) NSArray *advertisementDataViewModelsForInfoView; - (instancetype)initWithDiscoveredPeripheralDisplayData:(SILDiscoveredPeripheralDisplayData *)discoveredPeripheralDisplayData; diff --git a/SiliconLabsApp/ViewModels/SILDiscoveredPeripheralDisplayDataViewModel.m b/SiliconLabsApp/ViewModels/SILDiscoveredPeripheralDisplayDataViewModel.m index 884749ef..daccfee9 100644 --- a/SiliconLabsApp/ViewModels/SILDiscoveredPeripheralDisplayDataViewModel.m +++ b/SiliconLabsApp/ViewModels/SILDiscoveredPeripheralDisplayDataViewModel.m @@ -14,7 +14,6 @@ @interface SILDiscoveredPeripheralDisplayDataViewModel () @property (strong, nonatomic, readwrite) SILDiscoveredPeripheralDisplayData *discoveredPeripheralDisplayData; @property (strong, nonatomic, readwrite) NSArray *advertisementDataViewModels; -@property (strong, nonatomic, readwrite) NSArray *advertisementDataViewModelsForDevicesTable; @property (strong, nonatomic, readwrite) NSArray *advertisementDataViewModelsForInfoView; @end @@ -34,13 +33,6 @@ - (instancetype)initWithDiscoveredPeripheralDisplayData:(SILDiscoveredPeripheral #pragma mark - Properties -- (NSArray *)advertisementDataViewModelsForDevicesTable { - if (_advertisementDataViewModelsForDevicesTable == nil) { - _advertisementDataViewModelsForDevicesTable = [self advertisementDataViewModelsForadvertisementDataModels:_discoveredPeripheralDisplayData.advertisementDataModelsForDevicesTable]; - } - return _advertisementDataViewModelsForDevicesTable; -} - - (NSArray *)advertisementDataViewModelsForInfoView { if (_advertisementDataViewModelsForInfoView == nil) { _advertisementDataViewModelsForInfoView = [self advertisementDataViewModelsForadvertisementDataModels:_discoveredPeripheralDisplayData.advertisementDataModelsForInfoView]; diff --git a/SiliconLabsApp/Views/SILAlertBarView.h b/SiliconLabsApp/Views/SILAlertBarView.h deleted file mode 100644 index 7615528c..00000000 --- a/SiliconLabsApp/Views/SILAlertBarView.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// SILAlertBarView.h -// SiliconLabsApp -// -// Created by Eric Peterson on 10/25/15. -// Copyright © 2015 SiliconLabs. All rights reserved. -// - -#import -#import - -@interface SILAlertBarView : UIView - -@property (nonatomic) BOOL isAnimating; - -- (void)configureLabel:(UILabel *)label revealConstraint:(NSLayoutConstraint *)revealConstraint hideConstraint:(NSLayoutConstraint *)hideConstraint; -///@discussion displayTime of 0 or less means the message should stay revealed indefinitely -- (void)revealAlertBarWithMessage:(NSString *)message revealTime:(CGFloat)revealTime displayTime:(CGFloat)displayTime; -///@discussion hides the bar if revealed indefinitely, will interrupt any animations that would otherwise hide it -- (void)hideBarIfRevealed:(CGFloat)hideTime; - -@end diff --git a/SiliconLabsApp/Views/SILAlertBarView.m b/SiliconLabsApp/Views/SILAlertBarView.m deleted file mode 100644 index a707f272..00000000 --- a/SiliconLabsApp/Views/SILAlertBarView.m +++ /dev/null @@ -1,76 +0,0 @@ -// -// SILAlertBarView.m -// SiliconLabsApp -// -// Created by Eric Peterson on 10/25/15. -// Copyright © 2015 SiliconLabs. All rights reserved. -// - -#import "SILAlertBarView.h" -#import "UIColor+SILColors.h" - -const CGFloat kActivePriority = 999; -const CGFloat kMainPriority = 998; -const CGFloat kInactivePriority = 1; - -@interface SILAlertBarView() - -@property (weak, nonatomic) UILabel *alertMessageLabel; -@property (weak, nonatomic) NSLayoutConstraint *alertBarHideConstraint; -@property (weak, nonatomic) NSLayoutConstraint *alertBarRevealConstraint; - -@end - -@implementation SILAlertBarView - -- (void)awakeFromNib { - [super awakeFromNib]; - self.backgroundColor = [UIColor sil_siliconLabsRedColor]; -} - -- (void)configureLabel:(UILabel *)label revealConstraint:(NSLayoutConstraint *)revealConstraint hideConstraint:(NSLayoutConstraint *)hideConstraint { - self.alertMessageLabel = label; - self.alertBarRevealConstraint = revealConstraint; - self.alertBarHideConstraint = hideConstraint; - - self.alertBarHideConstraint.priority = kMainPriority; - self.alertBarRevealConstraint.priority = kInactivePriority; -} - -- (void)revealAlertBarWithMessage:(NSString *)message revealTime:(CGFloat)revealTime displayTime:(CGFloat)displayTime { - self.alertMessageLabel.text = message; - [self layoutIfNeeded]; - __weak SILAlertBarView *weakSelf = self; - if (!self.isAnimating) { - self.isAnimating = YES; - [UIView animateWithDuration:revealTime animations:^{ - weakSelf.alertBarRevealConstraint.priority = kActivePriority; - [weakSelf layoutIfNeeded]; - } completion:^(BOOL finished) { - if (displayTime > 0) { - [weakSelf hideBarAnimation:weakSelf duration:revealTime delay:displayTime]; - } else { - weakSelf.isAnimating = NO; - } - }]; - } -} - -- (void)hideBarIfRevealed:(CGFloat)hideTime { - [self.layer removeAllAnimations]; - [self layoutIfNeeded]; - [self hideBarAnimation:self duration:hideTime delay:0]; -} - -- (void)hideBarAnimation:(SILAlertBarView *)alertBarView duration:(CGFloat)duration delay:(CGFloat)delayTime { - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayTime * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ - [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveLinear animations:^{ - alertBarView.alertBarRevealConstraint.priority = kInactivePriority; - [alertBarView layoutIfNeeded]; - } completion:^(BOOL finished){ - alertBarView.isAnimating = NO; - }]; - }); -} - -@end diff --git a/SiliconLabsApp/XML/services/org.bluetooth.service.fitness_machine.xml b/SiliconLabsApp/XML/services/org.bluetooth.service.fitness_machine.xml new file mode 100644 index 00000000..2b100178 --- /dev/null +++ b/SiliconLabsApp/XML/services/org.bluetooth.service.fitness_machine.xml @@ -0,0 +1,338 @@ + + + + + This service exposes training-related data in the sports and fitness environment, which allows a Server (e.g., a fitness machine) to send training-related data to a Client. + The Fitness Machine Service (FTMS) exposes training-related data in the sports and fitness environment, which allows a Client to collect training data while a user is exercising with a fitness machine (Server). + + + This service has no dependencies on other GATT-based services. + + + Mandatory + Mandatory + C.1 + Optional + + C1: Mandatory if the Fitness Machine Control Point is supported, otherwise Optional. + + true + true + true + + + + + Mandatory + + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + + + Optional + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + + Optional + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + + Optional + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + + Optional + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + + Optional + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + + Optional + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + + Optional + + Mandatory + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + + C1 + + C1: Mandatory if the Speed Target Setting feature is supported; otherwise Optional. + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + + + C2 + + C2: Mandatory if the Inclination Target Setting feature is supported; otherwise Optional. + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + + + C3 + + C3: Mandatory if the Resistance Target Setting feature is supported; otherwise Optional. + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + + + C4 + + C4: Mandatory if the Power Target Setting feature is supported; otherwise Optional. + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + + + C5 + + C5: Mandatory if the Heart Rate Target Setting feature is supported; otherwise Optional. + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + + + + Optional + + Excluded + Mandatory + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + + C6 + + C6: Mandatory if the Fitness Machine Control Point is supported; otherwise Optional. + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + diff --git a/SiliconLabsApp/XML/services/org.bluetooth.service.insulin_delivery.xml b/SiliconLabsApp/XML/services/org.bluetooth.service.insulin_delivery.xml new file mode 100644 index 00000000..5e7e45d9 --- /dev/null +++ b/SiliconLabsApp/XML/services/org.bluetooth.service.insulin_delivery.xml @@ -0,0 +1,292 @@ + + + + + + This service exposes the control capability, the status of an Insulin Delivery Device (IDD) running an insulin infusion therapy, and historical therapy data to be used in the personal and professional healthcare industry. + + + The Insulin Delivery service is instantiated as a Primary Service. + + + + This service is not dependent upon any other services. + + + Mandatory + Mandatory + Mandatory + Mandatory + Mandatory + + + false + true + + + + + + + + + The IDD Status Changed characteristic is comprised of status changes of the insulin therapy and the insulin delivery device. + + Mandatory + + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + + + Authorization + + + + Mandatory + + Mandatory + Mandatory + + + + + + + The IDD Status characteristic is comprised of status values of the insulin delivery device and the insulin therapy. + + Mandatory + + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + + + Authorization + + + + Mandatory + + Mandatory + Mandatory + + + + + + + The IDD Annunciation Status characteristic is a variable length structure comprising of messages that describe state changes of the insulin delivery device and in the therapy relevant functions. + + Mandatory + + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + + + Authorization + + + + Mandatory + + Mandatory + Mandatory + + + + + + + The IDD Features characteristic shall be used to describe the supported features of the Server. + + Mandatory + + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + Authorization + + + + + The IDD Status Reader Control Point provides insulin therapy relevant status information (e.g., currently running boluses or current basal rate). + + Mandatory + + Excluded + Mandatory + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + + + Authorization + + + + Mandatory + + Mandatory + Mandatory + + + + + + + The IDD Command Control Point provides procedures to support the insulin therapy by adapting therapy parameters to operate the insulin therapy remotely and to perform a remote operation of the device maintenance. + + Optional + + Excluded + Mandatory + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + + + Authorization + + + + Mandatory + + Mandatory + Mandatory + + + + + + + The IDD Command Data characteristic is comprised of response records from executed procedures of the IDD Command Control Point. + + Conditional + + + Mandatory if the optional IDD Command Control Point is included, otherwise excluded. + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + Authorization + + + + Mandatory + + Mandatory + Mandatory + + + + + + + The IDD Record Access Control Point (IDD RACP) is based on the Record Access Control Point (RACP). The IDD RACP is used for basic management and access of the history database of the Server including historical data of the insulin therapy, device state changes, and annunciations. + + Optional + + Excluded + Mandatory + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + Authorization + + + + Read Property: Readable with no authentication or authorization already defined in Bluetooth Core Specification v4.0 as amended by CSA3 and CSS v2 or later + Mandatory + + Mandatory + Mandatory + + + + + + + The IDD History Data characteristic is comprised of response records from executed procedures of the Record Access Control Point. + + Conditional + + + Mandatory if the optional IDD Record Access Control Point is included, otherwise excluded. + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + Authorization + + + + Mandatory + + Mandatory + Mandatory + + + + + + diff --git a/SiliconLabsApp/XML/services/org.bluetooth.service.internet_protocol_support.xml b/SiliconLabsApp/XML/services/org.bluetooth.service.internet_protocol_support.xml new file mode 100644 index 00000000..94f76f29 --- /dev/null +++ b/SiliconLabsApp/XML/services/org.bluetooth.service.internet_protocol_support.xml @@ -0,0 +1,22 @@ + + + + + + When in a GAP Discoverable Mode for an initial connection to a Router, the Node will include the IP Support Service UUID 0x1820 in the Service UUIDs AD type field + of the advertising data. This enhances the user experience as a Node may be identified by the Router before initiating a connection. + + This service does not define any characteristics + + + + This service has no dependencies on other GATT-based services. + + + + false + true + + + diff --git a/SiliconLabsApp/XML/services/org.bluetooth.service.mesh_provisioning.xml b/SiliconLabsApp/XML/services/org.bluetooth.service.mesh_provisioning.xml new file mode 100644 index 00000000..a068f459 --- /dev/null +++ b/SiliconLabsApp/XML/services/org.bluetooth.service.mesh_provisioning.xml @@ -0,0 +1,64 @@ + + + + + + The Mesh Provisioning Service allows a Provisioning Client to provision a Provisioning Server to allow it to participate in the mesh network. + + + + + This service has no dependencies on other GATT-based services. + + + Mandatory + Mandatory + Mandatory + + + false + true + + + + The Mesh Provisioning Data In characteristic can be written to send a Proxy PDU message containing Provisioning PDU to the Provisioning Server. The characteristic value is 66 octets long to accommodate the longest known Proxy PDU containing Provisioning PDU. + Mandatory + + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + + + The Mesh Provisioning Data Out characteristic can be notified to send a Proxy PDU message containing Provisioning PDU from a Provisioning Server to a Provisioning Client. The characteristic value is 66 octets long to accommodate the longest known Proxy PDU message containing Provisioning PDU. + Mandatory + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + diff --git a/SiliconLabsApp/XML/services/org.bluetooth.service.mesh_proxy.xml b/SiliconLabsApp/XML/services/org.bluetooth.service.mesh_proxy.xml new file mode 100644 index 00000000..8188455c --- /dev/null +++ b/SiliconLabsApp/XML/services/org.bluetooth.service.mesh_proxy.xml @@ -0,0 +1,64 @@ + + + + + + The Mesh Proxy Service is used to enable a server to send and receive Proxy PDUs with a client. + + + + + This service has no dependencies on other GATT-based services. + + + Mandatory + Mandatory + Mandatory + + + false + true + + + + The Mesh Proxy Data In characteristic is used by the client to send Proxy PDUs to the server. + Mandatory + + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + Excluded + Excluded + Excluded + + + + + The Mesh Proxy Data Out characteristic is used by the server to send Proxy PDUs to the client. The Mesh Proxy Data Out characteristic shall support Proxy PDU messages containing Network PDUs, mesh beacon, and proxy configuration messages and shall not support other Proxy PDU type messages. + Mandatory + + Excluded + Excluded + Excluded + Excluded + Excluded + Mandatory + Excluded + Excluded + Excluded + + + + Mandatory + + Mandatory + Mandatory + + + + + + diff --git a/SiliconLabsApp/XML/services/org.bluetooth.service.reconnection_configuration.xml b/SiliconLabsApp/XML/services/org.bluetooth.service.reconnection_configuration.xml new file mode 100644 index 00000000..392800d2 --- /dev/null +++ b/SiliconLabsApp/XML/services/org.bluetooth.service.reconnection_configuration.xml @@ -0,0 +1,13 @@ + + This GATT-based service enables the control of certain communication parameters of a Bluetooth Low Energy peripheral device. + This service is not dependent upon any other services but is intended to be used together with other services.MandatoryC1: Mandatory if Ready for Disconnect is supported, otherwise Optional.C2: Mandatory if Reconnection Configuration Control Point (RCCP) procedures are supported, otherwise Excluded.MandatoryMandatoryfalsetrue + The RC Features characteristic shall be used to describe the supported features of the Reconnection Configuration server. + MandatoryMandatoryExcludedExcludedExcludedExcludedExcludedExcludedExcludedExcludedExcluded + The RC Settings characteristic shall be used to both read and notify supported features on the Reconnection Configuration server. + C1 + C1: Mandatory if device supports one or more of the following features: "Ready for Disconnect", "Advertisement Configuration", "Upgrade to LESC Only", "Next Pairing OOB", "Limited Access", otherwise Excluded. + + Notify is Mandatory if device supports "Enable Disconnect" feature, otherwise Optional. + MandatoryExcludedExcludedExcludedExcludedOptionalExcludedExcludedExcludedExcludedC2: Mandatory if device supports "Ready for Disconnect" feature, otherwise Excluded.MandatoryMandatoryC3 + C3: Mandatory if device supports one or more of the following features: "Enable Disconnect", "Propose Reconnection Timeout", "Propose Connection Interval", "Propose Slave Latency", "Propose Supervision Timeout", "Propose Advertisement Interval", "Propose Advertisement Count", "Propose Advertisement Repetition Time", "Advertisement Configuration 1", "Advertisement Configuration 2", "Advertisement Configuration 3", "Advertisement Configuration 4", "Upgrade to LESC Only", "Next Pairing OOB", "Use of White List", "Limited Access", otherwise Excluded. + MandatoryMandatoryExcludedExcludedExcludedExcludedMandatoryExcludedExcludedExcludedC3: Mandatory if device supports one or more of the following features: "Enable Disconnect", "Propose Reconnection Timeout", "Propose Connection Interval", "Propose Slave Latency", "Propose Supervision Timeout", "Propose Advertisement Interval", "Propose Advertisement Count", "Propose Advertisement Repetition Time", "Advertisement Configuration 1", "Advertisement Configuration 2", "Advertisement Configuration 3", "Advertisement Configuration 4", "Upgrade to LESC Only", "Next Pairing OOB", "Use of White List", "Limited Access", otherwise Excluded.MandatoryMandatory \ No newline at end of file