Skip to content

Commit

Permalink
Adding mock peripheral
Browse files Browse the repository at this point in the history
  • Loading branch information
philips77 committed Nov 17, 2023
1 parent 98ca20e commit aea1640
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 0 deletions.
12 changes: 12 additions & 0 deletions MockingExample.xcodeproj/project.pbxproj
Expand Up @@ -30,6 +30,7 @@
F0A6C9E5299B95BF00FA75EB /* Data+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0A6C9E4299B95BF00FA75EB /* Data+String.swift */; };
F0CC18AB29C0914300077C3E /* CoreBluetoothMock in Frameworks */ = {isa = PBXBuildFile; productRef = F0CC18AA29C0914300077C3E /* CoreBluetoothMock */; };
F0CC18AD29C092E000077C3E /* Aliases.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0CC18AC29C092E000077C3E /* Aliases.swift */; };
F0CC18B029C099EB00077C3E /* Blinky.swift in Sources */ = {isa = PBXBuildFile; fileRef = F0CC18AF29C099EB00077C3E /* Blinky.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -78,6 +79,7 @@
F0A6C9E1299649A500FA75EB /* ForEachWithIndex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForEachWithIndex.swift; sourceTree = "<group>"; };
F0A6C9E4299B95BF00FA75EB /* Data+String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Data+String.swift"; sourceTree = "<group>"; };
F0CC18AC29C092E000077C3E /* Aliases.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Aliases.swift; sourceTree = "<group>"; };
F0CC18AF29C099EB00077C3E /* Blinky.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Blinky.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -130,6 +132,7 @@
F0A6C9942992752700FA75EB /* MockingExample */ = {
isa = PBXGroup;
children = (
F0CC18AE29C099D300077C3E /* Mocks */,
F0A6C9E3299671F600FA75EB /* Screens */,
F0A6C9D229944BA500FA75EB /* Model */,
F0A6C9D129944B9400FA75EB /* Views */,
Expand Down Expand Up @@ -212,6 +215,14 @@
path = Screens;
sourceTree = "<group>";
};
F0CC18AE29C099D300077C3E /* Mocks */ = {
isa = PBXGroup;
children = (
F0CC18AF29C099EB00077C3E /* Blinky.swift */,
);
path = Mocks;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -358,6 +369,7 @@
F0A6C9D429944BCF00FA75EB /* Colors.swift in Sources */,
F0A6C9D02993D45800FA75EB /* DetailsView.swift in Sources */,
F0A6C9E5299B95BF00FA75EB /* Data+String.swift in Sources */,
F0CC18B029C099EB00077C3E /* Blinky.swift in Sources */,
F0A6C9E2299649A500FA75EB /* ForEachWithIndex.swift in Sources */,
F0A6C9982992752700FA75EB /* ScannerScreen.swift in Sources */,
F0A6C9CE2993D3F600FA75EB /* ServicesView.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions MockingExample/MockingExampleApp.swift
Expand Up @@ -13,6 +13,7 @@ struct MockingExampleApp: App {

init() {
CBMCentralManagerMock.simulateInitialState(.poweredOn)
CBMCentralManagerMock.simulatePeripherals([blinky])
}

var body: some Scene {
Expand Down
135 changes: 135 additions & 0 deletions MockingExample/Mocks/Blinky.swift
@@ -0,0 +1,135 @@
//
// Mocks.swift
// MockingExample
//
// Created by Aleksander Nowakowski on 14/02/2023.
//

import Foundation
import CoreBluetoothMock

// MARK: - Constants

extension CBMUUID {
static let nordicBlinkyService = CBMUUID(string: "00001523-1212-EFDE-1523-785FEABCD123")
static let buttonCharacteristic = CBMUUID(string: "00001524-1212-EFDE-1523-785FEABCD123")
static let ledCharacteristic = CBMUUID(string: "00001525-1212-EFDE-1523-785FEABCD123")
}

// MARK: - Services

extension CBMCharacteristicMock {

static let buttonCharacteristic = CBMCharacteristicMock(
type: .buttonCharacteristic,
properties: [.notify, .read],
descriptors: CBMClientCharacteristicConfigurationDescriptorMock()
)

static let ledCharacteristic = CBMCharacteristicMock(
type: .ledCharacteristic,
properties: [.write, .read]
)

}

extension CBMServiceMock {

static let blinkyService = CBMServiceMock(
type: .nordicBlinkyService,
primary: true,
characteristics:
.buttonCharacteristic,
.ledCharacteristic
)

}

// MARK: - Blinky Implementation

/// The delegate implements the behavior of the mocked device.
private class BlinkyCBMPeripheralSpecDelegate: CBMPeripheralSpecDelegate {

// MARK: States

/// State of the LED.
private var ledEnabled: Bool = false
/// State of the Button.
private var buttonPressed: Bool = false

// MARK: Encoders

/// LED state encoded as Data.
///
/// - 0x01 - LED is ON.
/// - 0x00 - LED is OFF.
private var ledData: Data {
return ledEnabled ? Data([0x01]) : Data([0x00])
}

/// Button state encoded as Data.
///
/// - 0x01 - Button is pressed.
/// - 0x00 - Button is released.
private var buttonData: Data {
return buttonPressed ? Data([0x01]) : Data([0x00])
}

// MARK: Event handlers

func reset() {
ledEnabled = false
buttonPressed = false
}

func peripheral(_ peripheral: CBMPeripheralSpec,
didReceiveReadRequestFor characteristic: CBMCharacteristicMock)
-> Result<Data, Error> {
if characteristic.uuid == .ledCharacteristic {
return .success(ledData)
} else {
return .success(buttonData)
}
}

func peripheral(_ peripheral: CBMPeripheralSpec,
didReceiveWriteRequestFor characteristic: CBMCharacteristicMock,
data: Data) -> Result<Void, Error> {
if data.count > 0 {
ledEnabled = data[0] != 0x00
}
return .success(())
}
}

// MARK: - Blinky Definition

/// This device will advertise with 2 different types of packets, as nRF Blinky and an iBeacon (with a name).
/// As iOS prunes the iBeacon manufacturer data, only the name is available.
let blinky = CBMPeripheralSpec
.simulatePeripheral(proximity: .immediate)
.advertising(
advertisementData: [
CBAdvertisementDataIsConnectable : true as NSNumber,
CBAdvertisementDataLocalNameKey : "Blinky"
],
withInterval: 2.0,
delay: 5.0,
alsoWhenConnected: false
)
.advertising(
advertisementData: [
CBAdvertisementDataIsConnectable : false as NSNumber,
CBAdvertisementDataLocalNameKey : "iBeacon",
//CBAdvertisementDataManufacturerDataKey:
],
withInterval: 4.0,
delay: 2.0,
alsoWhenConnected: false
)
.connectable(
name: "nRF Blinky",
services: [.blinkyService],
delegate: BlinkyCBMPeripheralSpecDelegate()
)
.build()

0 comments on commit aea1640

Please sign in to comment.