Skip to content

Commit

Permalink
Merge branch 'feature/CBManager_CBPeripheral_extraction' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
DrAma999 committed Aug 13, 2020
2 parents f253851 + ac8499e commit e06041b
Show file tree
Hide file tree
Showing 14 changed files with 555 additions and 131 deletions.
20 changes: 19 additions & 1 deletion LittleBlueTooth.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
/* End PBXAggregateTarget section */

/* Begin PBXBuildFile section */
654BCE8B24E03544002FC7A4 /* Extraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654BCE8A24E03544002FC7A4 /* Extraction.swift */; };
654BCE8E24E077DC002FC7A4 /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654BCE8D24E077DC002FC7A4 /* Helper.swift */; };
654BCE8F24E07804002FC7A4 /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 654BCE8D24E077DC002FC7A4 /* Helper.swift */; };
655330DD24BF159D007D299B /* CentralRestorer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 655330DC24BF159D007D299B /* CentralRestorer.swift */; };
655F49E224CF3DA400C24461 /* StateRestoration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 655330DE24BF5446007D299B /* StateRestoration.swift */; };
658A75C224BB74FC00F874EF /* CoreBluetoothTypeAliases.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_28 /* CoreBluetoothTypeAliases.swift */; };
Expand Down Expand Up @@ -88,6 +91,8 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
654BCE8A24E03544002FC7A4 /* Extraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extraction.swift; sourceTree = "<group>"; };
654BCE8D24E077DC002FC7A4 /* Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Helper.swift; sourceTree = "<group>"; };
655330DC24BF159D007D299B /* CentralRestorer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CentralRestorer.swift; sourceTree = "<group>"; };
655330DE24BF5446007D299B /* StateRestoration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StateRestoration.swift; sourceTree = "<group>"; };
6590D38124D0030000BEE864 /* WriteWithoutResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WriteWithoutResponse.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -153,6 +158,14 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
654BCE8C24E077B3002FC7A4 /* Extension */ = {
isa = PBXGroup;
children = (
654BCE8D24E077DC002FC7A4 /* Helper.swift */,
);
path = Extension;
sourceTree = "<group>";
};
65AD4BEF24D438AD00C0CBE6 /* Frameworks */ = {
isa = PBXGroup;
children = (
Expand All @@ -163,6 +176,7 @@
OBJ_11 /* Classes */ = {
isa = PBXGroup;
children = (
654BCE8C24E077B3002FC7A4 /* Extension */,
OBJ_12 /* Error */,
OBJ_14 /* Model */,
OBJ_19 /* Proxies */,
Expand Down Expand Up @@ -242,6 +256,7 @@
OBJ_40 /* WriteReadTest.swift */,
655330DE24BF5446007D299B /* StateRestoration.swift */,
6590D38124D0030000BEE864 /* WriteWithoutResponse.swift */,
654BCE8A24E03544002FC7A4 /* Extraction.swift */,
);
name = LittleBlueToothTests;
path = Tests/LittleBlueToothTests;
Expand Down Expand Up @@ -445,6 +460,7 @@
65AD4BDB24D437B700C0CBE6 /* CentralRestorer.swift in Sources */,
65A6B35124DD29070068FE1C /* Loggable.swift in Sources */,
65AD4BDC24D437B700C0CBE6 /* CBCentralManagerDelegateProxy.swift in Sources */,
654BCE8F24E07804002FC7A4 /* Helper.swift in Sources */,
65AD4BDD24D437B700C0CBE6 /* CBPeripheralProxy.swift in Sources */,
65AD4BDE24D437B700C0CBE6 /* ReplaySubject.swift in Sources */,
65AD4BDF24D437B700C0CBE6 /* ReplaySubjectSubscription.swift in Sources */,
Expand All @@ -468,6 +484,7 @@
655330DD24BF159D007D299B /* CentralRestorer.swift in Sources */,
65A6B35024DD29000068FE1C /* Loggable.swift in Sources */,
OBJ_57 /* CBCentralManagerDelegateProxy.swift in Sources */,
654BCE8E24E077DC002FC7A4 /* Helper.swift in Sources */,
OBJ_58 /* CBPeripheralProxy.swift in Sources */,
OBJ_59 /* ReplaySubject.swift in Sources */,
OBJ_60 /* ReplaySubjectSubscription.swift in Sources */,
Expand All @@ -494,6 +511,7 @@
OBJ_82 /* ConnectionTest.swift in Sources */,
655F49E224CF3DA400C24461 /* StateRestoration.swift in Sources */,
OBJ_83 /* ListenTest.swift in Sources */,
654BCE8B24E03544002FC7A4 /* Extraction.swift in Sources */,
OBJ_84 /* LittleBlueToothTests.swift in Sources */,
OBJ_85 /* MockPeripherals.swift in Sources */,
6590D38224D0030000BEE864 /* WriteWithoutResponse.swift in Sources */,
Expand Down Expand Up @@ -1125,7 +1143,7 @@
repositoryURL = "https://github.com/NordicSemiconductor/IOS-CoreBluetooth-Mock.git";
requirement = {
kind = upToNextMinorVersion;
minimumVersion = 0.11.0;
minimumVersion = 0.11.1;
};
};
/* End XCRemoteSwiftPackageReference section */
Expand Down
21 changes: 17 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The library is still on development so use at own you risk.
Add the following to your Cartfile:

```
github "DrAma999/LittleBlueTooth" ~> 0.3.0
github "DrAma999/LittleBlueTooth" ~> 0.4.0
```
Since the framework supports most of the Apple devices, you probably want to to build for a specific platform by adding the option `--platform` after the `carthage update` command. For instance:
```
Expand All @@ -35,7 +35,7 @@ The library has a sub-dependency with Nordic library [Core Bluetooth Mock](https
### Swift Package Manager
Add the following dependency to your Package.swift file:
```
.package(url: "https://github.com/DrAma999/LittleBlueTooth.git", from: "0.3.0")
.package(url: "https://github.com/DrAma999/LittleBlueTooth.git", from: "0.4.0")
```
Or simply add the URL from XCode menu Swift packages.

Expand Down Expand Up @@ -520,13 +520,26 @@ Note:
* Restoration can happen in background and foreground
* The Peripheral object returned can be in different state depending on what has been restored. If a peripheral has been disconnected and an `autoconnectionHandler` is provided LittleBluetooth will try to re-establish a connection.

### CBCentralManager CBPeripheral extraction
Sometimes it could be uselful to extract an already connected peripheral and a central manger and pass them to another framework. For instance if you need to make an OTA firmware update using the nordic library this would be required.
The extraction is made exaclty for this purpuse.
```
let extractedState = littleBT.extract()
```
Before extraction you need to stop listen to all the characteristics you where listening to.
The extracted state is a tuple `(central: CBCentralManager, peripheral: CBPeripheral?)` that contains the used `CBCentralManger` and a `CBPeripheral` if connected.
You can also *restart* LittleBlueTooth instance by passing the same object that you have extracted.
```
self.littleBT.restart(with: extractedState.central, peripheral: extractedState.peripheral)
```

## ROADMAP
- [x] SwiftPM support
- [x] State preservation and state restoration
- [ ] Improve code coverage
- [ ] `CBManager` and `CBPeripheral` extraction
- [ ] Add multiple peripheral support
- [x] `CBManager` and `CBPeripheral` extraction
- [x] Add support to: **macOS**, **watchOS**, **tvOS**, **macOS catalyst**
- [] Implement custom operator

## ISSUES
Please use Gihub, explaining what you did, how you did, what you expect and what you get.
Expand Down
56 changes: 56 additions & 0 deletions Sources/LittleBlueTooth/Classes/Extension/Helper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//
// Helper.swift
// LittleBlueTooth
//
// Created by Andrea Finollo on 09/08/2020.
//

import Foundation
import Combine
import os.log
#if TEST
import CoreBluetoothMock
#else
import CoreBluetooth
#endif

extension AnyCancellable {
func store(in dictionary: inout [UUID : AnyCancellable],
for key: UUID) {
dictionary[key] = self
}
}
extension Publisher {

func flatMapLatest<T: Publisher>(_ transform: @escaping (Self.Output) -> T) -> AnyPublisher<T.Output, T.Failure> where T.Failure == Self.Failure {
return map(transform).switchToLatest().eraseToAnyPublisher()
}
}

extension TimeInterval {
var dispatchInterval: DispatchTimeInterval {
let microseconds = Int64(self * TimeInterval(USEC_PER_SEC)) // perhaps use nanoseconds, though would more often be > Int.max
return microseconds < Int.max ? DispatchTimeInterval.microseconds(Int(microseconds)) : DispatchTimeInterval.seconds(Int(self))
}
}

extension OSLog {
public static var Subsystem = "it.vanillagorilla.LittleBlueTooth"
public static var General = "General"
public static var CentralManager = "CentralManager"
public static var Peripheral = "Peripheral"
public static var Restore = "Restore"

public static let LittleBT_Log_General = OSLog(subsystem: Subsystem, category: General)
public static let LittleBT_Log_CentralManager = OSLog(subsystem: Subsystem, category: CentralManager)
public static let LittleBT_Log_Peripheral = OSLog(subsystem: Subsystem, category: Peripheral)
public static let LittleBT_Log_Restore = OSLog(subsystem: Subsystem, category: Restore)

}
#if TEST
extension CBMPeripheral {
public var description: String {
return "Test peripheral"
}
}
#endif
19 changes: 19 additions & 0 deletions Sources/LittleBlueTooth/Classes/Model/Peripheral.swift
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,25 @@ public class Peripheral: Identifiable {
return discovery
}

func readRSSI() -> AnyPublisher<Int, LittleBluetoothError> {
let readRSSI =
peripheralProxy.peripheralRSSIPublisher
.tryMap { (value) -> Int in
switch value {
case let (_, error?):
throw error
case let (rssi, _):
return rssi
}
}
.mapError {$0 as! LittleBluetoothError}
.eraseToAnyPublisher()
defer {
cbPeripheral.readRSSI()
}
return readRSSI
}

func read(from charateristicUUID: CBUUID, of serviceUUID: CBUUID) -> AnyPublisher<Data?, LittleBluetoothError> {
let read = discoverCharacteristic(charateristicUUID, fromService: serviceUUID)
.flatMap { characteristic -> AnyPublisher<CBCharacteristic, LittleBluetoothError> in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ extension PeripheralDiscovery: CustomDebugStringConvertible {
return """
Name: \(name ?? "not available")
CB Peripheral: \(cbPeripheral)
Adv: \(advertisement)
Adv: \(advertisement.debugDescription)
RSSI: \(rssi)
"""
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ extension CBCentralManagerDelegateProxy: CBCentralManagerDelegate {

func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
log("CBCMD WillRestoreState %{public}@",
log: OSLog.LittleBT_Log_CentralManager,
log: OSLog.LittleBT_Log_Restore,
type: .debug,
arg: dict.description)
_willRestoreStatePublisher.send(CentralRestorer(centralManager: central, restoredInfo: dict))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ extension CBPeripheralDelegateProxy: CBPeripheralDelegate {
}

// MARK: - Descriptors
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?){}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor descriptor: CBDescriptor, error: Error?){}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?){}
// func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?){}
// func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor descriptor: CBDescriptor, error: Error?){}
// func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?){}
}

extension CBPeripheralDelegateProxy: Loggable {}
Loading

0 comments on commit e06041b

Please sign in to comment.