@mentra/bluetooth-sdk 3.2.1-beta.480 → 3.2.1-beta.498
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/src/main/java/com/mentra/bluetoothsdk/GeneratedReleaseMetadata.kt +5 -5
- package/build/generated/releaseMetadata.js +5 -5
- package/build/generated/releaseMetadata.js.map +1 -1
- package/ios/Source/BluetoothSdkDefaults.swift +1 -1
- package/ios/Source/GeneratedReleaseMetadata.swift +5 -5
- package/ios/Source/sgcs/Nimo.swift +62 -37
- package/ios/Source/sgcs/NimoDiscovery.swift +49 -0
- package/ios/Tests/NimoDiscoveryTests.swift +79 -0
- package/package.json +2 -2
- package/src/generated/releaseMetadata.ts +5 -5
|
@@ -3,9 +3,9 @@ package com.mentra.bluetoothsdk
|
|
|
3
3
|
/** Generated by release CI. Do not edit in a release checkout. */
|
|
4
4
|
internal object GeneratedReleaseMetadata {
|
|
5
5
|
const val FAMILY_BASE_VERSION: String = "3.2.1"
|
|
6
|
-
const val RELEASE_IDENTITY: String = "3.2.1-beta.
|
|
7
|
-
const val RELEASE_SET_ID: String = "mentra-3.2.1-beta.
|
|
8
|
-
const val SOURCE_COMMIT: String = "
|
|
9
|
-
const val OTA_MANIFEST_URL: String = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.
|
|
10
|
-
const val OTA_MANIFEST_SHA256: String = "
|
|
6
|
+
const val RELEASE_IDENTITY: String = "3.2.1-beta.498"
|
|
7
|
+
const val RELEASE_SET_ID: String = "mentra-3.2.1-beta.498"
|
|
8
|
+
const val SOURCE_COMMIT: String = "d0b2fd5a107a817c0584a590e75e9b5e2de05786"
|
|
9
|
+
const val OTA_MANIFEST_URL: String = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.498.json"
|
|
10
|
+
const val OTA_MANIFEST_SHA256: String = "9e4e4204706f770ab58f656b3526b98a8d696230caaa0405cd3fcbf1f9abfa40"
|
|
11
11
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
export const BLUETOOTH_SDK_RELEASE_METADATA = Object.freeze({
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"familyBaseVersion": "3.2.1",
|
|
4
|
-
"releaseIdentity": "3.2.1-beta.
|
|
5
|
-
"releaseSetId": "mentra-3.2.1-beta.
|
|
6
|
-
"sourceCommit": "
|
|
7
|
-
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.
|
|
8
|
-
"otaManifestSha256": "
|
|
4
|
+
"releaseIdentity": "3.2.1-beta.498",
|
|
5
|
+
"releaseSetId": "mentra-3.2.1-beta.498",
|
|
6
|
+
"sourceCommit": "d0b2fd5a107a817c0584a590e75e9b5e2de05786",
|
|
7
|
+
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.498.json",
|
|
8
|
+
"otaManifestSha256": "9e4e4204706f770ab58f656b3526b98a8d696230caaa0405cd3fcbf1f9abfa40"
|
|
9
9
|
});
|
|
10
10
|
//# sourceMappingURL=releaseMetadata.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,gBAAgB;IACnC,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,kIAAkI;IACpJ,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.2.1\",\n \"releaseIdentity\": \"3.2.1-beta.
|
|
1
|
+
{"version":3,"file":"releaseMetadata.js","sourceRoot":"","sources":["../../src/generated/releaseMetadata.ts"],"names":[],"mappings":"AAWA,MAAM,CAAC,MAAM,8BAA8B,GAA0C,MAAM,CAAC,MAAM,CAAC;IACjG,eAAe,EAAE,CAAC;IAClB,mBAAmB,EAAE,OAAO;IAC5B,iBAAiB,EAAE,gBAAgB;IACnC,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,0CAA0C;IAC1D,gBAAgB,EAAE,kIAAkI;IACpJ,mBAAmB,EAAE,kEAAkE;CACxF,CAAC,CAAA","sourcesContent":["/** Generated by release CI. Do not edit in a release checkout. */\nexport interface BluetoothSdkReleaseMetadata {\n schemaVersion: 1\n familyBaseVersion: string | null\n releaseIdentity: string | null\n releaseSetId: string | null\n sourceCommit: string | null\n otaManifestUrl: string | null\n otaManifestSha256: string | null\n}\n\nexport const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({\n \"schemaVersion\": 1,\n \"familyBaseVersion\": \"3.2.1\",\n \"releaseIdentity\": \"3.2.1-beta.498\",\n \"releaseSetId\": \"mentra-3.2.1-beta.498\",\n \"sourceCommit\": \"d0b2fd5a107a817c0584a590e75e9b5e2de05786\",\n \"otaManifestUrl\": \"https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.498.json\",\n \"otaManifestSha256\": \"9e4e4204706f770ab58f656b3526b98a8d696230caaa0405cd3fcbf1f9abfa40\"\n})\n"]}
|
|
@@ -16,7 +16,7 @@ enum BluetoothSdkDefaults {
|
|
|
16
16
|
/// silently disable it on every pair the app touches.
|
|
17
17
|
static let autoPowerOffEnabled = false
|
|
18
18
|
private static let infoSdkVersionKey = "MentraBluetoothSdkVersion"
|
|
19
|
-
private static let swiftPackageSdkVersion = "3.2.1-beta.
|
|
19
|
+
private static let swiftPackageSdkVersion = "3.2.1-beta.498"
|
|
20
20
|
private static let swiftPackageSdkVersionPlaceholder = "__MENTRA" + "_BLUETOOTH_SDK_VERSION__"
|
|
21
21
|
|
|
22
22
|
private static func normalizedSdkVersion(_ value: String?) -> String? {
|
|
@@ -3,9 +3,9 @@ import Foundation
|
|
|
3
3
|
/// Generated by release CI. Do not edit in a release checkout.
|
|
4
4
|
enum GeneratedReleaseMetadata {
|
|
5
5
|
static let familyBaseVersion = "3.2.1"
|
|
6
|
-
static let releaseIdentity = "3.2.1-beta.
|
|
7
|
-
static let releaseSetId = "mentra-3.2.1-beta.
|
|
8
|
-
static let sourceCommit = "
|
|
9
|
-
static let otaManifestUrl = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.
|
|
10
|
-
static let otaManifestSha256 = "
|
|
6
|
+
static let releaseIdentity = "3.2.1-beta.498"
|
|
7
|
+
static let releaseSetId = "mentra-3.2.1-beta.498"
|
|
8
|
+
static let sourceCommit = "d0b2fd5a107a817c0584a590e75e9b5e2de05786"
|
|
9
|
+
static let otaManifestUrl = "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.498.json"
|
|
10
|
+
static let otaManifestSha256 = "9e4e4204706f770ab58f656b3526b98a8d696230caaa0405cd3fcbf1f9abfa40"
|
|
11
11
|
}
|
|
@@ -20,10 +20,6 @@ enum NimoBLE {
|
|
|
20
20
|
static let CHAR_RX = CBUUID(string: "00002022-0000-1000-8000-00805F9B34FB")
|
|
21
21
|
static let CHAR_MIC = CBUUID(string: "00002025-0000-1000-8000-00805F9B34FB")
|
|
22
22
|
|
|
23
|
-
static let NAME_PREFIX = "nimo"
|
|
24
|
-
/// iOS ANCS side-channel devices advertise "<name>_ble" — never the data channel.
|
|
25
|
-
static let BLE_NAME_SUFFIX = "_ble"
|
|
26
|
-
|
|
27
23
|
static let CHUNK_SIZE = 501
|
|
28
24
|
static let INTER_FRAME_DELAY_MS = 5
|
|
29
25
|
}
|
|
@@ -591,6 +587,27 @@ class Nimo: NSObject, SGCManager {
|
|
|
591
587
|
private var rxChar: CBCharacteristic?
|
|
592
588
|
private var micChar: CBCharacteristic?
|
|
593
589
|
private var isDisconnecting = false
|
|
590
|
+
private var scanRequested = false
|
|
591
|
+
private lazy var discovery = NimoDiscovery<CBPeripheral>(
|
|
592
|
+
register: { [weak self] in
|
|
593
|
+
#if os(iOS)
|
|
594
|
+
self?.centralManager?.registerForConnectionEvents(options: [.serviceUUIDs: [NimoBLE.SERVICE_UUID]])
|
|
595
|
+
#endif
|
|
596
|
+
}, connected: { [weak self] in
|
|
597
|
+
self?.centralManager?.retrieveConnectedPeripherals(withServices: [NimoBLE.SERVICE_UUID]) ?? []
|
|
598
|
+
}, scan: { [weak self] in
|
|
599
|
+
self?.centralManager?.scanForPeripherals(
|
|
600
|
+
withServices: nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey: false]
|
|
601
|
+
)
|
|
602
|
+
}, stop: { [weak self] in
|
|
603
|
+
self?.centralManager?.stopScan()
|
|
604
|
+
#if os(iOS)
|
|
605
|
+
self?.centralManager?.registerForConnectionEvents(options: [:])
|
|
606
|
+
#endif
|
|
607
|
+
}, name: { $0.name }, found: { [weak self] peripheral, name, rssi in
|
|
608
|
+
self?.onDeviceFound(peripheral, name: name, rssi: rssi)
|
|
609
|
+
}
|
|
610
|
+
)
|
|
594
611
|
|
|
595
612
|
/// Device search
|
|
596
613
|
private var DEVICE_SEARCH_ID = "NOT_SET"
|
|
@@ -680,6 +697,8 @@ class Nimo: NSObject, SGCManager {
|
|
|
680
697
|
func findCompatibleDevices() {
|
|
681
698
|
Bridge.log("NIMO: findCompatibleDevices()")
|
|
682
699
|
DEVICE_SEARCH_ID = "NOT_SET"
|
|
700
|
+
isDisconnecting = false
|
|
701
|
+
scanRequested = true
|
|
683
702
|
DeviceStore.shared.apply("glasses", "connectionState", ConnTypes.SCANNING)
|
|
684
703
|
startScan()
|
|
685
704
|
}
|
|
@@ -687,6 +706,7 @@ class Nimo: NSObject, SGCManager {
|
|
|
687
706
|
func connectById(_ id: String) {
|
|
688
707
|
Bridge.log("NIMO: connectById(\(id))")
|
|
689
708
|
DEVICE_SEARCH_ID = id
|
|
709
|
+
scanRequested = true
|
|
690
710
|
DeviceStore.shared.apply("glasses", "connectionState", ConnTypes.CONNECTING)
|
|
691
711
|
isDisconnecting = false
|
|
692
712
|
startPairingTimeout()
|
|
@@ -694,7 +714,8 @@ class Nimo: NSObject, SGCManager {
|
|
|
694
714
|
}
|
|
695
715
|
|
|
696
716
|
func stopScan() {
|
|
697
|
-
|
|
717
|
+
scanRequested = false
|
|
718
|
+
discovery.cancel()
|
|
698
719
|
}
|
|
699
720
|
|
|
700
721
|
func disconnect() {
|
|
@@ -1061,13 +1082,9 @@ class Nimo: NSObject, SGCManager {
|
|
|
1061
1082
|
|
|
1062
1083
|
// MARK: - BLE Scanning
|
|
1063
1084
|
|
|
1064
|
-
private func isNimoMainDevice(_ name: String) -> Bool {
|
|
1065
|
-
let lower = name.lowercased()
|
|
1066
|
-
return lower.hasPrefix(NimoBLE.NAME_PREFIX) && !lower.hasSuffix(NimoBLE.BLE_NAME_SUFFIX)
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
1085
|
@discardableResult
|
|
1070
1086
|
private func startScan() -> Bool {
|
|
1087
|
+
guard scanRequested, !isDisconnecting else { return false }
|
|
1071
1088
|
Bridge.log("NIMO: startScan()")
|
|
1072
1089
|
if centralManager == nil {
|
|
1073
1090
|
centralManager = CBCentralManager(
|
|
@@ -1083,17 +1100,32 @@ class Nimo: NSObject, SGCManager {
|
|
|
1083
1100
|
|
|
1084
1101
|
// Fast path: reconnect to the cached peripheral UUID.
|
|
1085
1102
|
if connectByUUID() {
|
|
1103
|
+
stopScan()
|
|
1086
1104
|
return true
|
|
1087
1105
|
}
|
|
1088
1106
|
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
)
|
|
1107
|
+
// NIMO's Companion service is GATT over BR/EDR. The main device must
|
|
1108
|
+
// first be paired in Settings; it does not appear in a BLE-only scan.
|
|
1109
|
+
discovery.start()
|
|
1093
1110
|
return true
|
|
1094
1111
|
}
|
|
1095
1112
|
|
|
1113
|
+
private func onDeviceFound(_ peripheral: CBPeripheral, name: String, rssi: Int?) {
|
|
1114
|
+
Bridge.log("NIMO: found Companion device: \(name)")
|
|
1115
|
+
Bridge.sendDiscoveredDevice(DeviceTypes.NIMO, name, rssi: rssi)
|
|
1116
|
+
guard DEVICE_SEARCH_ID != "NOT_SET", name == DEVICE_SEARCH_ID,
|
|
1117
|
+
self.peripheral == nil else { return }
|
|
1118
|
+
Bridge.log("NIMO: Connecting to \(name)")
|
|
1119
|
+
stopScan()
|
|
1120
|
+
lastDeviceName = name
|
|
1121
|
+
lastDeviceUUID = peripheral.identifier.uuidString
|
|
1122
|
+
self.peripheral = peripheral
|
|
1123
|
+
peripheral.delegate = self
|
|
1124
|
+
centralManager?.connect(peripheral, options: nil)
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1096
1127
|
private func connectByUUID() -> Bool {
|
|
1128
|
+
guard peripheral == nil else { return false }
|
|
1097
1129
|
guard DEVICE_SEARCH_ID != "NOT_SET", !DEVICE_SEARCH_ID.isEmpty else { return false }
|
|
1098
1130
|
guard lastDeviceName == DEVICE_SEARCH_ID,
|
|
1099
1131
|
let uuidString = lastDeviceUUID,
|
|
@@ -1299,7 +1331,8 @@ class Nimo: NSObject, SGCManager {
|
|
|
1299
1331
|
}
|
|
1300
1332
|
Bridge.log("NIMO: Attempting reconnection...")
|
|
1301
1333
|
await MainActor.run {
|
|
1302
|
-
self.isDisconnecting
|
|
1334
|
+
guard !self.isDisconnecting else { return }
|
|
1335
|
+
self.scanRequested = true
|
|
1303
1336
|
self.startScan()
|
|
1304
1337
|
}
|
|
1305
1338
|
return false
|
|
@@ -1564,37 +1597,29 @@ extension Nimo: CBCentralManagerDelegate {
|
|
|
1564
1597
|
}
|
|
1565
1598
|
|
|
1566
1599
|
nonisolated func centralManager(
|
|
1567
|
-
_
|
|
1600
|
+
_: CBCentralManager,
|
|
1568
1601
|
didDiscover peripheral: CBPeripheral,
|
|
1569
1602
|
advertisementData: [String: Any],
|
|
1570
1603
|
rssi: NSNumber
|
|
1571
1604
|
) {
|
|
1572
|
-
|
|
1573
|
-
let name = peripheral.name
|
|
1574
|
-
?? advertisementData[CBAdvertisementDataLocalNameKey] as? String
|
|
1575
|
-
else { return }
|
|
1605
|
+
let advertisedName = advertisementData[CBAdvertisementDataLocalNameKey] as? String
|
|
1576
1606
|
let rssiValue = rssi.intValue
|
|
1577
|
-
|
|
1578
1607
|
DispatchQueue.main.async { [weak self] in
|
|
1579
|
-
|
|
1580
|
-
guard self.isNimoMainDevice(name) else { return }
|
|
1581
|
-
|
|
1582
|
-
Bridge.sendDiscoveredDevice(DeviceTypes.NIMO, name, rssi: rssiValue)
|
|
1583
|
-
|
|
1584
|
-
guard self.DEVICE_SEARCH_ID != "NOT_SET" else { return }
|
|
1585
|
-
guard name == self.DEVICE_SEARCH_ID else { return }
|
|
1586
|
-
guard self.peripheral == nil else { return }
|
|
1587
|
-
|
|
1588
|
-
Bridge.log("NIMO: Connecting to \(name)")
|
|
1589
|
-
self.stopScan()
|
|
1590
|
-
self.lastDeviceName = name
|
|
1591
|
-
self.lastDeviceUUID = peripheral.identifier.uuidString
|
|
1592
|
-
self.peripheral = peripheral
|
|
1593
|
-
peripheral.delegate = self
|
|
1594
|
-
central.connect(peripheral, options: nil)
|
|
1608
|
+
self?.discovery.receive(peripheral, advertisedName: advertisedName, rssi: rssiValue)
|
|
1595
1609
|
}
|
|
1596
1610
|
}
|
|
1597
1611
|
|
|
1612
|
+
#if os(iOS)
|
|
1613
|
+
nonisolated func centralManager(
|
|
1614
|
+
_: CBCentralManager, connectionEventDidOccur event: CBConnectionEvent, for peripheral: CBPeripheral
|
|
1615
|
+
) {
|
|
1616
|
+
guard event == .peerConnected else { return }
|
|
1617
|
+
DispatchQueue.main.async { [weak self] in
|
|
1618
|
+
self?.discovery.receive(peripheral)
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
#endif
|
|
1622
|
+
|
|
1598
1623
|
nonisolated func centralManager(_: CBCentralManager, didConnect peripheral: CBPeripheral) {
|
|
1599
1624
|
DispatchQueue.main.async { [weak self] in
|
|
1600
1625
|
guard let self else { return }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
/// Combines system-connected classic devices with incoming CoreBluetooth discoveries.
|
|
4
|
+
/// Kept independent of the radio so discovery can be exercised without hardware.
|
|
5
|
+
@MainActor
|
|
6
|
+
final class NimoDiscovery<Peripheral> {
|
|
7
|
+
private(set) var active = false
|
|
8
|
+
private let register: () -> Void
|
|
9
|
+
private let connected: () -> [Peripheral]
|
|
10
|
+
private let scan: () -> Void
|
|
11
|
+
private let stop: () -> Void
|
|
12
|
+
private let name: (Peripheral) -> String?
|
|
13
|
+
private let found: (Peripheral, String, Int?) -> Void
|
|
14
|
+
|
|
15
|
+
init(register: @escaping () -> Void, connected: @escaping () -> [Peripheral],
|
|
16
|
+
scan: @escaping () -> Void, stop: @escaping () -> Void,
|
|
17
|
+
name: @escaping (Peripheral) -> String?, found: @escaping (Peripheral, String, Int?) -> Void)
|
|
18
|
+
{
|
|
19
|
+
self.register = register
|
|
20
|
+
self.connected = connected
|
|
21
|
+
self.scan = scan
|
|
22
|
+
self.stop = stop
|
|
23
|
+
self.name = name
|
|
24
|
+
self.found = found
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func start() {
|
|
28
|
+
active = true
|
|
29
|
+
// Register first so pairing in Settings cannot race the connected snapshot.
|
|
30
|
+
register()
|
|
31
|
+
for peripheral in connected() {
|
|
32
|
+
receive(peripheral)
|
|
33
|
+
}
|
|
34
|
+
if active { scan() }
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
func cancel() {
|
|
38
|
+
active = false
|
|
39
|
+
stop()
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func receive(_ peripheral: Peripheral, advertisedName: String? = nil, rssi: Int? = nil) {
|
|
43
|
+
guard active, let name = advertisedName ?? name(peripheral) else { return }
|
|
44
|
+
let lower = name.lowercased()
|
|
45
|
+
// The separate ANCS peripheral does not host the Companion data service.
|
|
46
|
+
guard lower.hasPrefix("nimo"), !lower.hasSuffix("_ble") else { return }
|
|
47
|
+
found(peripheral, name, rssi)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
@testable import MentraBluetoothSDK
|
|
2
|
+
import XCTest
|
|
3
|
+
|
|
4
|
+
@MainActor
|
|
5
|
+
final class NimoDiscoveryTests: XCTestCase {
|
|
6
|
+
@MainActor
|
|
7
|
+
private final class Radio {
|
|
8
|
+
var connected: [String] = []
|
|
9
|
+
var events: [String] = []
|
|
10
|
+
var found: [String] = []
|
|
11
|
+
var selected: String?
|
|
12
|
+
lazy var discovery: NimoDiscovery<String> = NimoDiscovery(
|
|
13
|
+
register: { [unowned self] in self.events.append("register") },
|
|
14
|
+
connected: { [unowned self] in self.events.append("retrieve"); return self.connected },
|
|
15
|
+
scan: { [unowned self] in self.events.append("scan") },
|
|
16
|
+
stop: { [unowned self] in self.events.append("stop") },
|
|
17
|
+
name: { $0 },
|
|
18
|
+
found: { [unowned self] _, name, _ in
|
|
19
|
+
found.append(name)
|
|
20
|
+
if selected == name { discovery.cancel() }
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
func testAlreadyConnectedClassicDeviceIsFoundWithoutAdvertisement() {
|
|
26
|
+
let radio = Radio()
|
|
27
|
+
radio.connected = ["NIMO_1234", "NIMO_1234_BLE", "Unrelated"]
|
|
28
|
+
radio.discovery.start()
|
|
29
|
+
XCTAssertEqual(radio.events, ["register", "retrieve", "scan"])
|
|
30
|
+
XCTAssertEqual(radio.found, ["NIMO_1234"])
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
func testPairingInSettingsAfterScanStartedDeliversDevice() {
|
|
34
|
+
let radio = Radio()
|
|
35
|
+
radio.discovery.start()
|
|
36
|
+
XCTAssertTrue(radio.found.isEmpty)
|
|
37
|
+
// Same entry point as connectionEventDidOccur(.peerConnected).
|
|
38
|
+
radio.discovery.receive("NIMO_5678")
|
|
39
|
+
XCTAssertEqual(radio.found, ["NIMO_5678"])
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func testSelectionFromConnectedSnapshotStopsBeforeStartingBleScan() {
|
|
43
|
+
let radio = Radio()
|
|
44
|
+
radio.selected = "NIMO_5678"
|
|
45
|
+
radio.connected = ["NIMO_1234", "NIMO_5678", "NIMO_9999"]
|
|
46
|
+
radio.discovery.start()
|
|
47
|
+
XCTAssertEqual(radio.found, ["NIMO_1234", "NIMO_5678"])
|
|
48
|
+
XCTAssertEqual(radio.events, ["register", "retrieve", "stop"])
|
|
49
|
+
XCTAssertFalse(radio.discovery.active)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
func testCancelledDiscoveryIgnoresQueuedEventsAndCanRestart() {
|
|
53
|
+
let radio = Radio()
|
|
54
|
+
radio.discovery.start()
|
|
55
|
+
radio.discovery.cancel()
|
|
56
|
+
radio.discovery.receive("NIMO_1234")
|
|
57
|
+
XCTAssertTrue(radio.found.isEmpty)
|
|
58
|
+
radio.connected = ["NIMO_1234"]
|
|
59
|
+
radio.discovery.start()
|
|
60
|
+
XCTAssertEqual(radio.found, ["NIMO_1234"])
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
func testBleFallbackUsesAdvertisementNameAndPreservesSignalStrength() {
|
|
64
|
+
var found: [String] = []
|
|
65
|
+
var signal: Int?
|
|
66
|
+
let discovery = NimoDiscovery<String>(
|
|
67
|
+
register: {}, connected: { [] }, scan: {}, stop: {}, name: { _ in nil },
|
|
68
|
+
found: { _, name, rssi in found.append(name); signal = rssi }
|
|
69
|
+
)
|
|
70
|
+
discovery.start()
|
|
71
|
+
discovery.receive("uuid", advertisedName: "NiMo_1234_bLe", rssi: -60)
|
|
72
|
+
discovery.receive("uuid", advertisedName: "Unrelated", rssi: -60)
|
|
73
|
+
discovery.receive("uuid")
|
|
74
|
+
XCTAssertTrue(found.isEmpty)
|
|
75
|
+
discovery.receive("uuid", advertisedName: "NiMo_1234", rssi: -55)
|
|
76
|
+
XCTAssertEqual(found, ["NiMo_1234"])
|
|
77
|
+
XCTAssertEqual(signal, -55)
|
|
78
|
+
}
|
|
79
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mentra/bluetooth-sdk",
|
|
3
|
-
"version": "3.2.1-beta.
|
|
3
|
+
"version": "3.2.1-beta.498",
|
|
4
4
|
"description": "SDK for communicating with smart glasses",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"react-native": "src/index.ts",
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
"registry": "https://registry.npmjs.org/"
|
|
115
115
|
},
|
|
116
116
|
"dependencies": {
|
|
117
|
-
"@mentra/cloud-protocol": "3.2.1-beta.
|
|
117
|
+
"@mentra/cloud-protocol": "3.2.1-beta.498"
|
|
118
118
|
},
|
|
119
119
|
"devDependencies": {
|
|
120
120
|
"@types/node": "^25.9.3",
|
|
@@ -12,9 +12,9 @@ export interface BluetoothSdkReleaseMetadata {
|
|
|
12
12
|
export const BLUETOOTH_SDK_RELEASE_METADATA: Readonly<BluetoothSdkReleaseMetadata> = Object.freeze({
|
|
13
13
|
"schemaVersion": 1,
|
|
14
14
|
"familyBaseVersion": "3.2.1",
|
|
15
|
-
"releaseIdentity": "3.2.1-beta.
|
|
16
|
-
"releaseSetId": "mentra-3.2.1-beta.
|
|
17
|
-
"sourceCommit": "
|
|
18
|
-
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.
|
|
19
|
-
"otaManifestSha256": "
|
|
15
|
+
"releaseIdentity": "3.2.1-beta.498",
|
|
16
|
+
"releaseSetId": "mentra-3.2.1-beta.498",
|
|
17
|
+
"sourceCommit": "d0b2fd5a107a817c0584a590e75e9b5e2de05786",
|
|
18
|
+
"otaManifestUrl": "https://artifactscdn.mentraglass.com/Mentra-Community/MentraOS/releases/mentra-builds-v3.2.1/mentra-live-ota-3.2.1-beta.498.json",
|
|
19
|
+
"otaManifestSha256": "9e4e4204706f770ab58f656b3526b98a8d696230caaa0405cd3fcbf1f9abfa40"
|
|
20
20
|
})
|