Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
DrAma999 committed Jan 5, 2025
2 parents e10591e + 0bde676 commit 46d9502
Show file tree
Hide file tree
Showing 17 changed files with 113 additions and 245 deletions.
260 changes: 62 additions & 198 deletions LittleBlueTooth.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
<key>IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded</key>
<false/>
</dict>
</plist>
</plist>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
LastUpgradeVersion = "1620"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1200"
LastUpgradeVersion = "1620"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
7 changes: 3 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// swift-tools-version:5.4
// swift-tools-version: 6.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription
Expand All @@ -25,7 +25,7 @@ let package = Package(
// Dependencies declare other packages that this package depends on.
.package(name: "CoreBluetoothMock",
url: "https://github.com/NordicSemiconductor/IOS-CoreBluetooth-Mock.git",
.upToNextMinor(from: "0.14.0")),
.upToNextMinor(from: "0.18.0")),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand All @@ -46,6 +46,5 @@ let package = Package(
dependencies: ["LittleBlueToothForTest","CoreBluetoothMock"],
exclude: ["Info.plist"]
)
],
swiftLanguageVersions: [.v5]
]
)
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ An instance of LittleBluetooth can control only one peripheral, you can use more

The library is still on development so use at own you risk.

[!NOTE]
While the 1.0.0 compile fine on swift 6 even with complete concurrency check, it doesn't mean is thread safe. CoreBluetooth is not yet and is very difficult to make it fully compliant. That is why exposed classes arre marked as `@unchecked Sendable`. For previous swift version is possible to resolve versione `0.8.0`.

## TOC
[Features](#features)

Expand Down Expand Up @@ -85,7 +88,7 @@ The library is still on development so use at own you risk.
Add the following to your Cartfile:

```
github "DrAma999/LittleBlueTooth" ~> 0.7.1
github "DrAma999/LittleBlueTooth" ~> 1.0.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 Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ extension Publisher where Self.Failure == LittleBluetoothError {
public func startListen<T: Readable>(for littleBluetooth: LittleBlueTooth,
from charact: LittleBlueToothCharacteristic) -> AnyPublisher<T, LittleBluetoothError> {

func startListen<T: Readable, Upstream: Publisher>(upstream: Upstream,
func startListen<Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
from charact: LittleBlueToothCharacteristic) -> AnyPublisher<T, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ extension Publisher where Self.Failure == LittleBluetoothError {
public func read<T: Readable>(for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic) -> AnyPublisher<T, LittleBluetoothError> {

func read<T: Readable, Upstream: Publisher>(upstream: Upstream,
func read<Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic) -> AnyPublisher<T, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
return upstream
Expand Down Expand Up @@ -70,7 +70,7 @@ extension Publisher where Self.Failure == LittleBluetoothError {
value: T,
response: Bool = true) -> AnyPublisher<Void, LittleBluetoothError> {

func write<T: Writable, Upstream: Publisher>(upstream: Upstream,
func write<Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
to characteristic: LittleBlueToothCharacteristic,
value: T,
Expand All @@ -97,7 +97,7 @@ extension Publisher where Self.Failure == LittleBluetoothError {
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,
func writeAndListen<Upstream: Publisher>(upstream: Upstream,
for littleBluetooth: LittleBlueTooth,
from characteristic: LittleBlueToothCharacteristic,
value: W) -> AnyPublisher<R, LittleBluetoothError> where Upstream.Failure == LittleBluetoothError {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ extension Publisher where Self.Failure == LittleBluetoothError {
/// - error: An error to be returned if the publisher times out, by default `LittleBluetoothError.connectionTimeout`
/// - Returns: A publisher that terminates if the specified interval elapses with no events received from the upstream publisher.
public func timeout<S>(_ interval: S.SchedulerTimeType.Stride, scheduler: S, options: S.SchedulerOptions? = nil, error: LittleBluetoothError = .operationTimeout) -> AnyPublisher<Self.Output, LittleBluetoothError> where S: Scheduler {
func timeout<Upstream: Publisher, S>(upsstream: Upstream,_ interval: S.SchedulerTimeType.Stride, scheduler: S, options: S.SchedulerOptions? = nil, error: LittleBluetoothError = .operationTimeout) -> AnyPublisher<Upstream.Output, LittleBluetoothError> where S: Scheduler, Upstream.Failure == LittleBluetoothError {
func timeout<Upstream: Publisher>(upsstream: Upstream,_ interval: S.SchedulerTimeType.Stride, scheduler: S, options: S.SchedulerOptions? = nil, error: LittleBluetoothError = .operationTimeout) -> AnyPublisher<Upstream.Output, LittleBluetoothError> where S: Scheduler, Upstream.Failure == LittleBluetoothError {
return upsstream
.timeout(interval, scheduler: scheduler, options: options, customError: {error})
.eraseToAnyPublisher()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@

import Foundation
#if TEST
import CoreBluetoothMock
@preconcurrency import CoreBluetoothMock
#else
import CoreBluetooth
@preconcurrency import CoreBluetooth
#endif


/// Collection of errors that can be returned by LittleBlueTooth
public enum LittleBluetoothError: Error {
case bluetoothPoweredOff
Expand All @@ -38,7 +40,7 @@ public enum LittleBluetoothError: Error {
case peripheralAlreadyConnectedOrConnecting(Peripheral)
case peripheralNotConnectedOrAlreadyDisconnected
case peripheralNotFound
case peripheralDisconnected(PeripheralIdentifier,Error?)
case peripheralDisconnected(PeripheralIdentifier, Error?)
case fullfillConditionNotRespected
case deserializationFailedDataOfBounds(start: Int, length: Int, count: Int)
}
10 changes: 5 additions & 5 deletions Sources/LittleBlueTooth/Classes/Extension/Helper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ extension TimeInterval {
}

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 Subsystem = "it.vanillagorilla.LittleBlueTooth"
public static let General = "General"
public static let CentralManager = "CentralManager"
public static let Peripheral = "Peripheral"
public static let Restore = "Restore"

public static let LittleBT_Log_General = OSLog(subsystem: Subsystem, category: General)
public static let LittleBT_Log_CentralManager = OSLog(subsystem: Subsystem, category: CentralManager)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,19 +95,19 @@ extension LittleBlueToothCharacteristic: Equatable, Hashable {

public extension LittleBlueToothCharacteristic {
/// Permitted operations on the characteristic they already exist in CBCharacteristic need to remap when initialized from CBCharacteristic
struct Properties: OptionSet {
struct Properties: OptionSet, Sendable {
public let rawValue: UInt8

public static var broadcast = Properties(rawValue: 1 << 0)
public static var read = Properties(rawValue: 1 << 1)
public static var writeWithoutResponse = Properties(rawValue: 1 << 2)
public static var write = Properties(rawValue: 1 << 3)
public static var notify = Properties(rawValue: 1 << 4)
public static var indicate = Properties(rawValue: 1 << 5)
public static var authenticatedSignedWrites = Properties(rawValue: 1 << 6)
public static var extendedProperties = Properties(rawValue: 1 << 7)
public static var notifyEncryptionRequired = Properties(rawValue: 1 << 8)
public static var indicateEncryptionRequired = Properties(rawValue: 1 << 9)
public static let broadcast = Properties(rawValue: 1 << 0)
public static let read = Properties(rawValue: 1 << 1)
public static let writeWithoutResponse = Properties(rawValue: 1 << 2)
public static let write = Properties(rawValue: 1 << 3)
public static let notify = Properties(rawValue: 1 << 4)
public static let indicate = Properties(rawValue: 1 << 5)
public static let authenticatedSignedWrites = Properties(rawValue: 1 << 6)
public static let extendedProperties = Properties(rawValue: 1 << 7)
public static let notifyEncryptionRequired = Properties(rawValue: 1 << 8)
public static let indicateEncryptionRequired = Properties(rawValue: 1 << 9)

public init(rawValue: UInt8) {
self.rawValue = rawValue
Expand Down
9 changes: 4 additions & 5 deletions Sources/LittleBlueTooth/Classes/Model/Peripheral.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import CoreBluetoothMock
import CoreBluetooth
#endif


/// An enumeration that represent the changes in peripheral services or name
public enum PeripheralChanges {
/// The name has been changed
Expand All @@ -24,7 +25,7 @@ public enum PeripheralChanges {
}

/// The state of the peripheral
public enum PeripheralState {
public enum PeripheralState: Sendable {
/// Peripheral is disconnected
case disconnected
/// Peripheral is connecting
Expand Down Expand Up @@ -54,7 +55,7 @@ public enum PeripheralState {
}

/// It represents a peripheral along with its properties
public class Peripheral: Identifiable {
public final class Peripheral: Identifiable, @unchecked Sendable {
/// An identifier for the peripheral it is the same as the wrapped `CBPeripheral`
public var id: UUID {
cbPeripheral.identifier
Expand All @@ -70,8 +71,6 @@ public class Peripheral: Identifiable {

/// The wrapped `CBPeripheral`
public let cbPeripheral: CBPeripheral
/// The rssi value of the peripheral
public var rssi: Int?

/// Logging on the peripheral can be disable or enabled acting of that property
var isLogEnabled: Bool {
Expand Down Expand Up @@ -115,6 +114,7 @@ public class Peripheral: Identifiable {
init(_ peripheral: CBPeripheral) {
self.cbPeripheral = peripheral
self.cbPeripheral.delegate = self.peripheralProxy

#if !TEST
self.peripheralStatePublisher = self.cbPeripheral.publisher(for: \.state)
.map{ (state) -> PeripheralState in
Expand Down Expand Up @@ -591,7 +591,6 @@ extension Peripheral: CustomDebugStringConvertible {
Id: \(id)
Name: \(name ?? "Not available")
CBPeripheral: \(cbPeripheral)
RSSI: \(rssi?.description ?? "Not available")
"""
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,19 @@

import Foundation
#if TEST
import CoreBluetoothMock
@preconcurrency import CoreBluetoothMock
#else
import CoreBluetooth
@preconcurrency import CoreBluetooth
#endif



public protocol PeripheralIdentifiable: Identifiable {
var id: UUID {get set}
var name: String? {get set}
}
/// An object that contains the unique identifier of the `CBPeripheral` and the name of it (if present)
public struct PeripheralIdentifier: PeripheralIdentifiable {
public struct PeripheralIdentifier: PeripheralIdentifiable, @unchecked Sendable {
/// The `UUID`of the peripheral
public var id: UUID
/// The name of the peripheral
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public enum BluetoothState {
}
}

class CBCentralManagerDelegateProxy: NSObject {
final class CBCentralManagerDelegateProxy: NSObject {

let centralDiscoveriesPublisher = PassthroughSubject<PeripheralDiscovery, Never>()
let connectionEventPublisher = PassthroughSubject<ConnectionEvent, Never>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import CoreBluetoothMock
import CoreBluetooth
#endif

class CBPeripheralDelegateProxy: NSObject {
final class CBPeripheralDelegateProxy: NSObject {

let peripheralChangesPublisher = PassthroughSubject<PeripheralChanges, Never>()
let peripheralRSSIPublisher = PassthroughSubject<(Int, LittleBluetoothError?), Never>()
Expand Down
6 changes: 3 additions & 3 deletions Sources/LittleBlueTooth/LittleBlueTooth.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ import Foundation
import Combine
import os.log
#if TEST
import CoreBluetoothMock
@preconcurrency import CoreBluetoothMock
#else
import CoreBluetooth
@preconcurrency import CoreBluetooth
#endif

public protocol Readable {
Expand All @@ -28,7 +28,7 @@ public protocol Writable {
Please note that Apple do not enacourage the use of more `CBCentralManger` instances, due to resurce hits.
[Link](https://developer.apple.com/forums/thread/20810)
*/
public class LittleBlueTooth: Identifiable {
public final class LittleBlueTooth: Identifiable, @unchecked Sendable {

// MARK: - Public variables
/// LittleBlueTooth instance identifier
Expand Down

0 comments on commit 46d9502

Please sign in to comment.