Skip to content

Commit 19f468a

Browse files
authored
Merge pull request #163 from nordicsemi/spec
Added UART Spec Delegate + CBMPeripheralMockError type
2 parents ece38d2 + dc34479 commit 19f468a

1 file changed

Lines changed: 147 additions & 0 deletions

File tree

CoreBluetoothMock/Specs/UART.swift

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
* Copyright (c) 2026, Nordic Semiconductor
3+
* All rights reserved.
4+
*
5+
* Redistribution and use in source and binary forms, with or without modification,
6+
* are permitted provided that the following conditions are met:
7+
*
8+
* 1. Redistributions of source code must retain the above copyright notice, this
9+
* list of conditions and the following disclaimer.
10+
*
11+
* 2. Redistributions in binary form must reproduce the above copyright notice, this
12+
* list of conditions and the following disclaimer in the documentation and/or
13+
* other materials provided with the distribution.
14+
*
15+
* 3. Neither the name of the copyright holder nor the names of its contributors may
16+
* be used to endorse or promote products derived from this software without
17+
* specific prior written permission.
18+
*
19+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22+
* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23+
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24+
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25+
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26+
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28+
* POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
import Foundation
32+
33+
// MARK: - UART
34+
35+
public class UART {
36+
37+
// MARK: Private
38+
39+
private var isNotificationEnabled: Bool
40+
private var messageCounter: Int
41+
42+
// MARK: Properties
43+
44+
public let name: String
45+
46+
// MARK: init
47+
48+
init(name: String = "Nordic_UART") {
49+
self.isNotificationEnabled = false
50+
self.messageCounter = 0
51+
self.name = name
52+
}
53+
54+
// MARK: spec
55+
56+
public private(set) lazy var spec = CBMPeripheralSpec
57+
.simulatePeripheral(proximity: .far)
58+
.advertising(
59+
advertisementData: [
60+
CBMAdvertisementDataIsConnectable : true as NSNumber,
61+
CBMAdvertisementDataLocalNameKey : name,
62+
CBMAdvertisementDataServiceUUIDsKey : [CBMUUID.uart]
63+
],
64+
withInterval: 2.0,
65+
delay: 5.0,
66+
alsoWhenConnected: false
67+
)
68+
.connectable(
69+
name: name,
70+
services: [.uart],
71+
delegate: self,
72+
connectionInterval: 0.02,
73+
)
74+
.build()
75+
}
76+
77+
// MARK: - UARTCBMPeripheralSpecDelegate
78+
79+
extension UART: CBMPeripheralSpecDelegate {
80+
81+
public func peripheral(_ peripheral: CBMPeripheralSpec,
82+
didReceiveWriteRequestFor characteristic: CBMCharacteristicMock,
83+
data: Data) -> Result<Void, Error> {
84+
switch characteristic.uuid {
85+
case CBMUUID.uartRx:
86+
if (isNotificationEnabled) {
87+
let receivedMessage = String(data: data, encoding: .utf8)
88+
messageCounter += 1
89+
let reply = "Received message #\(messageCounter):\n\(receivedMessage ?? "<empty>")"
90+
let replyData = reply.data(using: .utf8) ?? Data()
91+
peripheral.simulateValueUpdate(replyData, for: CBMCharacteristicMock.uartTx)
92+
return .success(())
93+
}
94+
return .failure(CBMATTError(.requestNotSupported))
95+
default:
96+
return .failure(CBMATTError(.writeNotPermitted))
97+
}
98+
}
99+
100+
public func peripheral(_ peripheral: CBMPeripheralSpec, didReceiveSetNotifyRequest enabled: Bool, for characteristic: CBMCharacteristicMock) -> Result<Void, Error> {
101+
switch characteristic.uuid {
102+
case .uartTx:
103+
isNotificationEnabled = enabled
104+
default:
105+
return .failure(CBMATTError(.requestNotSupported))
106+
}
107+
108+
return .success(())
109+
}
110+
111+
public func peripheral(_ peripheral: CBMPeripheralSpec, didReceiveReadRequestFor characteristic: CBMCharacteristicMock) -> Result<Data, any Error> {
112+
return .failure(CBMATTError(.readNotPermitted))
113+
}
114+
}
115+
116+
// MARK: - CoreBluetoothMock
117+
118+
private extension CBMUUID {
119+
static let uart: CBMUUID! = CBMUUID(string: "6E400001-B5A3-F393-E0A9-E50E24DCCA9E")
120+
static let uartRx: CBMUUID! = CBMUUID(string: "6E400002-B5A3-F393-E0A9-E50E24DCCA9E")
121+
static let uartTx: CBMUUID! = CBMUUID(string: "6E400003-B5A3-F393-E0A9-E50E24DCCA9E")
122+
123+
static let cccd = CBMUUID(string: "2902")
124+
}
125+
126+
private extension CBMDescriptorMock {
127+
static let cccd = CBMDescriptorMock(type: .cccd)
128+
}
129+
130+
private extension CBMCharacteristicMock {
131+
132+
static let uartTx = CBMCharacteristicMock(
133+
type: .uartTx, properties: .notify, descriptors: .cccd
134+
)
135+
136+
static let uartRx = CBMCharacteristicMock(
137+
type: .uartRx, properties: [.write],
138+
)
139+
}
140+
141+
private extension CBMServiceMock {
142+
143+
static let uart = CBMServiceMock(
144+
type: .uart, primary: true,
145+
characteristics: .uartRx, .uartTx,
146+
)
147+
}

0 commit comments

Comments
 (0)