Skip to content

Commit

Permalink
Merge pull request #9 from DrAma999/develop
Browse files Browse the repository at this point in the history
Added Custom operator
Tests passes
  • Loading branch information
DrAma999 authored Aug 29, 2020
2 parents 88c649c + 3977652 commit 3f6951a
Show file tree
Hide file tree
Showing 20 changed files with 1,147 additions and 138 deletions.
72 changes: 54 additions & 18 deletions LittleBlueTooth.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

20 changes: 15 additions & 5 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.4.1
github "DrAma999/LittleBlueTooth" ~> 0.5.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.4.0")
.package(url: "https://github.com/DrAma999/LittleBlueTooth.git", from: "0.5.0")
```
Or simply add the URL from XCode menu Swift packages.

Expand All @@ -60,7 +60,13 @@ All `LittleBluetoothConfiguration` properties are optional.
littleBT = LittleBlueTooth(with: littleBTConf)
```
### Scan
You can scan with or without a timeout, after a timeout you receive a `.scanTimeout` error. Note that each peripheral found is published to the subscribers chain until you stop the scan request or you connect to a device (when you connect scan is automatically suspended.
You can scan with or without a timeout, after a timeout you receive a `.scanTimeout` error.
You can set up your timeout for each sort of operation, for instance for a scan:
```
anycanc = littleBT.startDiscovery(withServices: [littleChar.service])
.timeout(DispatchQueue.SchedulerTimeType.Stride(timeout.dispatchInterval), scheduler: DispatchQueue.main, options: nil, error: .scanTimeout)
```
Note that each peripheral found is published to the subscribers chain until you stop the scan request or you connect to a device (when you connect scan is automatically suspended.

_Scan and stop_:

Expand Down Expand Up @@ -470,7 +476,6 @@ Unexpected can be due for different reasons: device reset, device out of range e

Indipendently if it is unexpected or explicit `LittleBlueTooth` will clean up everything after registering a disconnection.


### Connection event observer
_Connection event observer_:

Expand Down Expand Up @@ -533,13 +538,18 @@ You can also *restart* LittleBlueTooth instance by passing the same object that
self.littleBT.restart(with: extractedState.central, peripheral: extractedState.peripheral)
```

## CUSTOM COMBINE OPERATOR
Most of the functionalities are also wrapped inside custom operators. I'm not very happy about the implemetation: you must be very sure that you are passing the correct type of data or some inner forced casts will make your application crash, read the documentation above each custom operator. to know the correct types I hope to find a more reliable solution that will involve type checking using the compilator.

### Connect

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

## ISSUES
Please use Github, explaining what you did, how you did, what you expect and what you get.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//
// JustLittleBlueTooth.swift
// LittleBlueTooth
//
// Created by Andrea Finollo on 28/08/2020.
//

import Foundation
import Combine

public let StartLittleBlueTooth = Just(()).setFailureType(to: LittleBluetoothError.self)
85 changes: 85 additions & 0 deletions Sources/LittleBlueTooth/Classes/CustomOperator/Listen.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//
// Listen.swift
// LittleBlueTooth
//
// Created by Andrea Finollo on 26/08/2020.
//

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


// MARK: - Listen

extension Publisher where Self.Failure == LittleBluetoothError {

/// Returns a publisher with the `LittleBlueToothCharacteristic` where the notify command has been activated.
/// After starting the listen command you should subscribe to the `listenPublisher` to be notified.
/// - parameter littleBluetooth: the `LittleBlueTooth` instance
/// - parameter characteristic: Characteristc you want to be notified.
/// - returns: A publisher with the `LittleBlueToothCharacteristic` where the notify command has been activated.
/// - important: This publisher only activate the notification on a specific characteristic, it will not send notified values.
/// After starting the listen command you should subscribe to the `listenPublisher` to be notified.
public func enableListen(for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic) -> AnyPublisher<LittleBlueToothCharacteristic, LittleBluetoothError> {

func enableListen<Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic) -> AnyPublisher<LittleBlueToothCharacteristic, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
.flatMapLatest { _ in
littleBluetooth.enableListen(from: characteristic)
}
}

return enableListen(upstream: self,
for: littleBluetooth,
from: characteristic)
}

/// Returns a shared publisher for listening to a specific characteristic.
/// - parameter littleBluetooth: the `LittleBlueTooth` instance
/// - parameter characteristic: Characteristc you want to be notified.
/// - returns: A shared publisher that will send out values of the type defined by the generic type.
/// - important: The type of the value must be conform to `Readable`
public func startListen<T: Readable>(for littleBluetooth: LittleBlueTooth,
from charact: LittleBlueToothCharacteristic) -> AnyPublisher<T, LittleBluetoothError> {

func startListen<T: Readable, Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
from charact: LittleBlueToothCharacteristic) -> AnyPublisher<T, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
.flatMapLatest { _ in
littleBluetooth.startListen(from: charact)
}
}

return startListen(upstream: self,
for: littleBluetooth,
from: charact)
}

/// Disable listen from a specific characteristic
/// - parameter characteristic: characteristic you want to stop listen
/// - returns: A publisher with that informs you about the successful or failed task
public func disableListen(for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic) -> AnyPublisher<LittleBlueToothCharacteristic, LittleBluetoothError> {
func disableListen<Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic) -> AnyPublisher<LittleBlueToothCharacteristic, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
.flatMapLatest { _ in
littleBluetooth.disableListen(from: characteristic)
}
}
return disableListen(upstream: self,
for: littleBluetooth,
from: characteristic)
}
}
117 changes: 117 additions & 0 deletions Sources/LittleBlueTooth/Classes/CustomOperator/ReadAndWrite.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
//
// ReadAndWrite.swift
// LittleBlueTooth
//
// Created by Andrea Finollo on 26/08/2020.
//

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

extension Publisher where Self.Failure == LittleBluetoothError {
// MARK: - RSSI
/// Returns a publisher with the `Int`value of the RSSI.
/// - parameter littleBluetooth: the `LittleBlueTooth` instance
/// - returns: A publisher with the `Int` value of the RSSI..
public func readRSSI(for littleBluetooth: LittleBlueTooth) -> AnyPublisher<Int, LittleBluetoothError> {

func readRSSI<Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth) -> AnyPublisher<Int, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
.flatMapLatest { _ in
littleBluetooth.readRSSI()
}
}
return readRSSI(upstream: self,
for: littleBluetooth)
}

// MARK: - Read

/// Read a value from a specific charteristic
/// - parameter littleBluetooth: the `LittleBlueTooth` instance
/// - parameter characteristic: characteristic where you want to read
/// - returns: A publisher with the value you want to read.
/// - important: The type of the value must be conform to `Readable`
public func read<T: Readable>(for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic) -> AnyPublisher<T, LittleBluetoothError> {

func read<T: Readable, Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic) -> AnyPublisher<T, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
.flatMapLatest { _ in
littleBluetooth.read(from: characteristic)
}
}

return read(upstream: self,
for: littleBluetooth,
from: characteristic)
}

// MARK: - Write

/// Write a value to a specific charteristic
/// - parameter littleBluetooth: the `LittleBlueTooth` instance
/// - parameter characteristic: characteristic where you want to write
/// - parameter value: The value you want to write
/// - parameter response: An optional `Bool` value that will look for error after write operation
/// - returns: A publisher with that informs you about eventual error
/// - important: The type of the value must be conform to `Writable`
public func write<T: Writable>(for littleBluetooth: LittleBlueTooth,
to characteristic: LittleBlueToothCharacteristic,
value: T,
response: Bool = true) -> AnyPublisher<Void, LittleBluetoothError> {

func write<T: Writable, Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
to characteristic: LittleBlueToothCharacteristic,
value: T,
response: Bool = true) -> AnyPublisher<Void, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
.flatMapLatest { _ in
littleBluetooth.write(to: characteristic, value: value, response: response)
}
}

return write(upstream: self,
for: littleBluetooth,
to: characteristic,
value: value,
response: response)
}

/// Write a value to a specific charteristic and wait for a response
/// - parameter littleBluetooth: the `LittleBlueTooth` instance
/// - parameter characteristic: characteristic where you want to write and listen
/// - parameter value: The value you want to write must conform to `Writable`
/// - returns: A publisher with that post and error or the response of the write requests.
/// - important: Written value must conform to `Writable`, response must conform to `Readable`
public func writeAndListen<W: Writable, R: Readable>(for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic,
value: W) -> AnyPublisher<R, LittleBluetoothError> {
func writeAndListen<W: Writable, R: Readable, Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic,
value: W) -> AnyPublisher<R, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
.flatMapLatest { _ in
littleBluetooth.writeAndListen(from: characteristic,
value: value)
}
}
return writeAndListen(upstream: self,
for: littleBluetooth,
from: characteristic,
value: value)
}

}

Loading

0 comments on commit 3f6951a

Please sign in to comment.