Skip to content

Commit 73533c8

Browse files
authored
Merge pull request #53 from SomaticLabs/multiple-device-types
Added support for multiple hardware versions
2 parents bf76a95 + aa82d28 commit 73533c8

37 files changed

+1169
-281
lines changed

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,25 +46,27 @@ $ brew install carthage
4646
To integrate SwiftyZorb into your Xcode project using Carthage, specify it in your `Cartfile`:
4747

4848
```ogdl
49-
github "SomaticLabs/SwiftyZorb" ~> 2.0
49+
github "SomaticLabs/SwiftyZorb" ~> 3.0
5050
```
5151

5252
Run `carthage update` to build the framework and drag the built `SwiftyZorb.framework` into your Xcode project.
5353

54-
You must also drag the built dependencies `Alamofire.framework`, `SwiftyBluetooth.framework`, and `SwiftyJSON.framework` into your project.
54+
You must also drag the built dependencies `Alamofire.framework`, `SwiftyBluetooth.framework`, `SwiftyJSON.framework`, and `SwiftProtobuf.framework` into your project.
5555

5656
## Single Device Usage
5757

5858
There are two ways to use this libary. If you intend to connect and reconnect to one Zorb peripheral device, use the following methods.
5959

6060
### Connecting
6161

62-
Before being able to communicate with a Zorb peripheral device, you must establish a Bluetooth LE connection with your device.
62+
Before being able to communicate with a Zorb peripheral device, you must establish a Bluetooth LE connection with your device.
63+
64+
The `withVersion` parameter is used to specify which version of Zorb hardware you are using. If you are unsure which hardware you have, please [contact us](mailto:developers@somaticlabs.io).
6365

6466
```swift
6567
import SwiftyZorb
6668

67-
SwiftyZorb.connect { result in
69+
SwiftyZorb.connect(withVersion: .V2) { result in
6870
switch result {
6971
case .success:
7072
// Connected succeeded
@@ -193,7 +195,7 @@ If you would like to manage connections with multiple Zorb peripheral devices, y
193195

194196
```swift
195197
// Retrieves a list all available devices as an array of `ZorbDevice` objects.
196-
SwiftyZorb.retrieveAvailableDevices { result in
198+
SwiftyZorb.retrieveAvailableDevices(withVersion: .V2) { result in
197199
switch result {
198200
case .success(let devices):
199201
// Retrieval succeeded

SwiftyZorb/Info.plist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
<key>CFBundlePackageType</key>
1616
<string>FMWK</string>
1717
<key>CFBundleShortVersionString</key>
18-
<string>2.4.0</string>
18+
<string>3.0.0</string>
1919
<key>CFBundleVersion</key>
2020
<string>$(CURRENT_PROJECT_VERSION)</string>
2121
<key>NSPrincipalClass</key>

SwiftyZorb/Internal/BluetoothManager.swift

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,19 @@ final internal class BluetoothManager: NSObject {
4949
/**
5050
Called to initiate connection with Zorb peripheral, handles reconnection process based on this logical diagram: ![Reconnection flow chart](https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/Art/ReconnectingToAPeripheral_2x.png "Reconnection workflow")
5151
*/
52-
func connect(completion: @escaping ConnectPeripheralCallback) {
52+
func connect(withVersion version: ZorbDevice.Version, completion: @escaping ConnectPeripheralCallback) {
5353
// Identifier and services for device of interest
5454
var uuid: UUID?
5555
let services: [CBUUID]
5656

5757
// Check if we have connected to this peripheral before, and get it's UUID and associated services
5858
uuid = Settings.getZorbPeripheral()
59-
services = Identifiers.AdvertisedServices
59+
switch version {
60+
case .V1:
61+
services = Identifiers.V1.AdvertisedServices
62+
case .V2:
63+
services = Identifiers.V2.AdvertisedServices
64+
}
6065

6166
// If we do, try to connect to it
6267
if let uuid = uuid {
@@ -75,7 +80,7 @@ final internal class BluetoothManager: NSObject {
7580
}
7681

7782
// Update internal `ZorbDevice` and handle in completion
78-
self.device = ZorbDevice(with: peripheral)
83+
self.device = ZorbDevice(with: peripheral, andVersion: version)
7984
completion(.success(value))
8085
case .failure(let error):
8186
// Treat as error and handle in completion
@@ -104,7 +109,7 @@ final internal class BluetoothManager: NSObject {
104109
Settings.saveZorbPeripheral(with: peripheral.identifier)
105110

106111
// Update internal `ZorbDevice` and handle in completion
107-
self.device = ZorbDevice(with: peripheral)
112+
self.device = ZorbDevice(with: peripheral, andVersion: version)
108113
completion(.success(value))
109114
case .failure(let error):
110115
// Treat as error and handle in completion
@@ -150,7 +155,7 @@ final internal class BluetoothManager: NSObject {
150155
}
151156

152157
// Update internal `ZorbDevice` and handle in completion
153-
self.device = ZorbDevice(with: peripheral)
158+
self.device = ZorbDevice(with: peripheral, andVersion: version)
154159
completion(.success(value))
155160
case .failure(let error):
156161
// Treat as error and handle in completion
@@ -173,18 +178,24 @@ final internal class BluetoothManager: NSObject {
173178
/**
174179
Scans for and retrieves a collection of available Zorb devices
175180
*/
176-
func retrieveAvailableDevices(completion: @escaping (Result<[ZorbDevice]>) -> Void) {
181+
func retrieveAvailableDevices(withVersion version: ZorbDevice.Version, completion: @escaping (Result<[ZorbDevice]>) -> Void) {
177182
// Initialize collection of available peripherals
178183
var peripherals: [ZorbDevice] = []
179184

180185
// Get associated Zorb device services
181-
let services = Identifiers.AdvertisedServices
186+
let services: [CBUUID]
187+
switch version {
188+
case .V1:
189+
services = Identifiers.V1.AdvertisedServices
190+
case .V2:
191+
services = Identifiers.V2.AdvertisedServices
192+
}
182193

183194
// First add any already connected peripherals to our collection
184195
let connectedPeripherals = central.retrieveConnectedPeripherals(withServiceUUIDs: services)
185196
for peripheral in connectedPeripherals {
186197
if Constants.deviceNames.contains(peripheral.name ?? "Unknown") {
187-
peripherals.append(ZorbDevice(with: peripheral))
198+
peripherals.append(ZorbDevice(with: peripheral, andVersion: version))
188199
}
189200
}
190201

@@ -203,7 +214,7 @@ final internal class BluetoothManager: NSObject {
203214

204215
// Check if found peripheral is the one we're trying to connect to
205216
if Constants.deviceNames.contains(peripheral.name ?? "Unknown") {
206-
peripherals.append(ZorbDevice(with: peripheral))
217+
peripherals.append(ZorbDevice(with: peripheral, andVersion: version))
207218
}
208219
case .scanStopped(let error):
209220
// The scan stopped, an error is passed if the scan stopped unexpectedly

SwiftyZorb/Internal/Identifiers.swift

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,7 @@ internal struct Identifiers {
2626
/// `CBUUID` for identifying the serial number string characteristic
2727
static let SerialNumberStringCharacteristicUUID = CBUUID(string: "2A25")
2828

29-
// MARK: - Zorb Specific Bluetooth Service UUIDs
30-
31-
/// Array of `CBUUID`s representing all services that Zorb device should advertise
32-
static let AdvertisedServices = [CBUUID]() // FIXME: Eventually replace with [HapticTimelineServiceUUID]
33-
34-
/// `CBUUID` that advertises the haptic timeline service
35-
static let HapticTimelineServiceUUID = CBUUID(string: "A28E9217-E9B5-4C0A-9217-1C64D051D762")
36-
37-
/// `CBUUID` that advertises the setttings characteristic
38-
static let SettingsCharacteristicUUID = CBUUID(string: "A28EFC07-E9B5-4C0A-9217-1C64D051D762")
39-
40-
/// `CBUUID` for identifying the basic actuator control characteristic
41-
static let ActuatorCharacteristicUUID = CBUUID(string: "A28EFC05-E9B5-4C0A-9217-1C64D051D762")
42-
43-
/// `CBUUID` for identifying the pattern trigger characteristic
44-
static let PatternTriggerCharacteristicUUID = CBUUID(string: "A28EFC08-E9B5-4C0A-9217-1C64D051D762")
29+
// MARK: - UART Service UUIDs
4530

4631
/// `CBUUID` for identifying the Nordic UART service
4732
static let NordicUARTServiceUUID = CBUUID(string: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
@@ -52,4 +37,42 @@ internal struct Identifiers {
5237
/// `CBUUID` for identifying the Nordic UART RX characteristic
5338
static let NordicUARTRXCharacteristicUUID = CBUUID(string: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
5439

40+
// MARK: - Zorb Specific Bluetooth Service UUIDs
41+
42+
// Identifiers for hardware V1 devices
43+
struct V1 {
44+
/// Arrays of `CBUUID`s representing all services that Zorb device should advertise
45+
static let AdvertisedServices = [CBUUID]() // FIXME: Eventually replace with [HapticTimelineServiceUUID_V1]
46+
47+
/// `CBUUID`s that advertises the haptic timeline service
48+
static let HapticTimelineServiceUUID = CBUUID(string: "A28E9217-E9B5-4C0A-9217-1C64D051D762")
49+
50+
/// `CBUUID`s that advertises the setttings characteristic
51+
static let SettingsCharacteristicUUID = CBUUID(string: "A28EFC07-E9B5-4C0A-9217-1C64D051D762")
52+
53+
/// `CBUUID` for identifying the basic actuator control characteristic
54+
static let ActuatorCharacteristicUUID = CBUUID(string: "A28EFC05-E9B5-4C0A-9217-1C64D051D762")
55+
56+
/// `CBUUID` for identifying the pattern trigger characteristic
57+
static let PatternTriggerCharacteristicUUID = CBUUID(string: "A28EFC08-E9B5-4C0A-9217-1C64D051D762")
58+
}
59+
60+
// Identifiers for hardware V2 devices
61+
struct V2 {
62+
/// Arrays of `CBUUID`s representing all services that Zorb device should advertise
63+
static let AdvertisedServices = [CBUUID]() // FIXME: Eventually replace with [HapticTimelineServiceUUID_V2]
64+
65+
/// `CBUUID`s that advertises the haptic timeline service
66+
static let HapticTimelineServiceUUID = CBUUID(string: "D6E59217-D763-47FA-A092-C24EE6DF29D3")
67+
68+
/// `CBUUID`s that advertises the setttings characteristic
69+
static let SettingsCharacteristicUUID = CBUUID(string: "D6E5FC07-D763-47FA-A092-C24EE6DF29D3")
70+
71+
/// `CBUUID` for identifying the basic actuator control characteristic
72+
static let ActuatorCharacteristicUUID = CBUUID(string: "D6E5FC05-D763-47FA-A092-C24EE6DF29D3")
73+
74+
/// `CBUUID` for identifying the pattern trigger characteristic
75+
static let PatternTriggerCharacteristicUUID = CBUUID(string: "D6E5FC08-D763-47FA-A092-C24EE6DF29D3")
76+
}
77+
5578
}

SwiftyZorb/Public/SwiftyZorb.swift

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import SwiftyJSON
1313
// MARK: Bluetooth Management Methods
1414

1515
/**
16-
Scans for and retrieves a collection of available Zorb devices.
16+
Scans for and retrieves a collection of available Zorb devices with a given hardware version (either V1 or V2) as enumerated in `ZorbDevice.Version`.
1717

1818
Usage Example:
1919

2020
```swift
2121
// Retrieves a list all available devices as an array of `ZorbDevice` objects.
22-
SwiftyZorb.retrieveAvailableDevices { result in
22+
SwiftyZorb.retrieveAvailableDevices(withVersion: .V2) { result in
2323
switch result {
2424
case .success(let devices):
2525
// Retrieval succeeded
@@ -32,12 +32,58 @@ import SwiftyJSON
3232
}
3333
```
3434
*/
35+
public func retrieveAvailableDevices(withVersion version: ZorbDevice.Version, completion: @escaping (SwiftyBluetooth.Result<[ZorbDevice]>) -> Void) {
36+
bluetoothManager.retrieveAvailableDevices(withVersion: version) { result in completion(result) }
37+
}
38+
39+
/**
40+
Maintaining backwares compatibility, scans for and retrieves a collection of available Zorb devices with V1 hardware.
41+
42+
Usage Example:
43+
44+
```swift
45+
// Retrieves a list all available devices as an array of `ZorbDevice` objects.
46+
SwiftyZorb.retrieveAvailableDevices(withVersion: .V2) { result in
47+
switch result {
48+
case .success(let devices):
49+
// Retrieval succeeded
50+
for device in devices {
51+
// Do something with devices
52+
}
53+
case .failure(let error):
54+
// An error occurred during retrieval
55+
}
56+
}
57+
```
58+
*/
59+
@available(*, deprecated, message: "Please specify hardware version with `withVersion` parameter.")
3560
public func retrieveAvailableDevices(completion: @escaping (SwiftyBluetooth.Result<[ZorbDevice]>) -> Void) {
36-
bluetoothManager.retrieveAvailableDevices { result in completion(result) }
61+
bluetoothManager.retrieveAvailableDevices(withVersion: .V1) { result in completion(result) }
62+
}
63+
64+
/**
65+
Initiates a connection to an advertising Zorb device with a given hardware version (either V1 or V2) as enumerated in` ZorbDevice.Version`.
66+
67+
Usage Example:
68+
69+
```swift
70+
// Attempts connection to an advertising device
71+
SwiftyZorb.connect(withVersion: .V2) { result in
72+
switch result {
73+
case .success:
74+
// Connect succeeded
75+
case .failure(let error):
76+
// An error occurred during connection
77+
}
78+
}
79+
```
80+
*/
81+
public func connect(withVersion version: ZorbDevice.Version, completion: @escaping ConnectPeripheralCallback) {
82+
bluetoothManager.connect(withVersion: version) { result in completion(result) }
3783
}
3884

3985
/**
40-
Initiates a connection to an advertising Zorb device.
86+
Maintaining backwares compatibility, initiates a connection to an advertising Zorb device with V1 hardware.
4187

4288
Usage Example:
4389

@@ -53,8 +99,9 @@ public func retrieveAvailableDevices(completion: @escaping (SwiftyBluetooth.Resu
5399
}
54100
```
55101
*/
102+
@available(*, deprecated, message: "Please specify hardware version with `withVersion` parameter.")
56103
public func connect(completion: @escaping ConnectPeripheralCallback) {
57-
bluetoothManager.connect { result in completion(result) }
104+
bluetoothManager.connect(withVersion: .V1) { result in completion(result) }
58105
}
59106

60107
/**

SwiftyZorb/Public/ZorbDevice.swift

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,17 @@ import Alamofire
1717
*/
1818
final public class ZorbDevice {
1919

20+
// MARK: - Version Enumeration
21+
22+
/// Differentiates between different hardware versions
23+
public enum Version: Int {
24+
// First hardware iteration
25+
case V1 = 1
26+
27+
// Second hardware iteration
28+
case V2 = 2
29+
}
30+
2031
// MARK: - Class Properties
2132

2233
/// `SwiftyBluetooth` peripheral for device
@@ -25,16 +36,20 @@ final public class ZorbDevice {
2536
/// `PacketQueue` for storing Javascript packets to be sent
2637
private var packetQueue: PacketQueue
2738

39+
/// `Version` of hardware for a given device
40+
private let hardwareVersion: Version
41+
2842
// MARK: - Initialization
2943

3044
/**
31-
Public initializer, only requires peripheral associated with given device
45+
Internal initializer, only requires peripheral associated with given device
3246

3347
- Parameter peripheral:
3448
*/
35-
internal init(with peripheral: Peripheral) {
49+
internal init(with peripheral: Peripheral, andVersion version: Version) {
3650
self.peripheral = peripheral
3751
self.packetQueue = PacketQueue()
52+
self.hardwareVersion = version
3853
}
3954

4055
// MARK: - Private Connection Management Methods
@@ -47,8 +62,17 @@ final public class ZorbDevice {
4762
- Parameter characteristic: The `UUID` of the characteristic being written to
4863
*/
4964
private func writeBytes(_ bytes: Data, to characteristic: CBUUID, completion: @escaping WriteRequestCallback) {
65+
// Get appropriate CBUUID
66+
let hapticTimelineServiceUUID: CBUUID
67+
switch self.hardwareVersion {
68+
case .V1:
69+
hapticTimelineServiceUUID = Identifiers.V1.HapticTimelineServiceUUID
70+
case .V2:
71+
hapticTimelineServiceUUID = Identifiers.V2.HapticTimelineServiceUUID
72+
}
73+
5074
// Write data to settings characteristic
51-
peripheral.writeValue(ofCharacWithUUID: characteristic, fromServiceWithUUID: Identifiers.HapticTimelineServiceUUID, value: bytes) { result in
75+
peripheral.writeValue(ofCharacWithUUID: characteristic, fromServiceWithUUID: hapticTimelineServiceUUID, value: bytes) { result in
5276
completion(result)
5377
}
5478
}
@@ -319,13 +343,22 @@ final public class ZorbDevice {
319343
- Parameter bottomRight: Intensity, in a range from 0 to 100, for the bottom right actuator to be set at.
320344
*/
321345
public func writeActuators(duration: UInt16, topLeft: UInt8, topRight: UInt8, bottomLeft: UInt8, bottomRight: UInt8, completion: @escaping WriteRequestCallback) {
346+
// Get appropriate CBUUID
347+
let actuatorCharacteristicUUID: CBUUID
348+
switch self.hardwareVersion {
349+
case .V1:
350+
actuatorCharacteristicUUID = Identifiers.V1.ActuatorCharacteristicUUID
351+
case .V2:
352+
actuatorCharacteristicUUID = Identifiers.V2.ActuatorCharacteristicUUID
353+
}
354+
322355
// Determine data to send
323356
let duration0: UInt8 = UInt8(duration & 0x00FF)
324357
let duration1: UInt8 = UInt8(duration >> 8)
325358
let data = Data(bytes: [duration0, duration1, topLeft, topRight, bottomLeft, bottomRight])
326359

327360
// Write actuator data to Zorb device
328-
self.writeBytes(data, to: Identifiers.ActuatorCharacteristicUUID) { result in completion(result) }
361+
self.writeBytes(data, to: actuatorCharacteristicUUID) { result in completion(result) }
329362
}
330363

331364
/**
@@ -521,8 +554,18 @@ final public class ZorbDevice {
521554
- Parameter pattern: The `Trigger` enumeration option of the given preloaded pattern to trigger
522555
*/
523556
public func triggerPattern(_ pattern: Trigger, completion: @escaping WriteRequestCallback) {
557+
// Get appropriate CBUUID
558+
let patternTriggerCharacteristicUUID: CBUUID
559+
switch self.hardwareVersion {
560+
case .V1:
561+
patternTriggerCharacteristicUUID = Identifiers.V1.PatternTriggerCharacteristicUUID
562+
case .V2:
563+
patternTriggerCharacteristicUUID = Identifiers.V2.PatternTriggerCharacteristicUUID
564+
}
565+
566+
// Send byte for associated pattern
524567
let byte = Data(pattern.rawValue.utf8.map{ UInt8($0) })
525-
self.writeBytes(byte, to: Identifiers.PatternTriggerCharacteristicUUID) {
568+
self.writeBytes(byte, to: patternTriggerCharacteristicUUID) {
526569
result in completion(result)
527570
}
528571
}

0 commit comments

Comments
 (0)