🔴 Critical: - DXSmartProvisioner: complete rewrite to match Android's new SDK protocol - Writes to FFE2 (not FFE1) using 4E4F protocol packets - Correct command IDs: 0x74 UUID, 0x75 Major, 0x76 Minor, 0x77 RSSI, 0x78 AdvInt, 0x79 TxPower, 0x60 Save - Frame selection (0x11/0x12) + frame type (0x62 iBeacon) - Old SDK fallback (0x36-0x43 via FFE1 with 555555 re-auth per command) - Auth timing: 100ms delays (was 500ms, matches Android SDK) - BeaconShardPool: replaced 71 pattern UUIDs with exact 64 from Android 🟡 Warnings: - BlueCharmProvisioner: 3 fallback write methods matching Android (FEA3 direct → FEA1 raw → FEA1 indexed), legacy FFF0 support, added "minew123" and "bc04p" passwords (5 total, was 3) - BeaconBanList: added 4 missing prefixes (8492E75F, A0B13730, EBEFD083, B5B182C7), full UUID ban list, getBanReason() helper - BLEManager: documented MAC OUI limitation (48:87:2D not available on iOS via CoreBluetooth) 🔵 Info: - APIClient: added get_beacon_config endpoint for server-configured values - ScanView: unknown beacon type now tries KBeacon→DXSmart→BlueCharm fallback chain via new FallbackProvisioner - DXSmartProvisioner: added readFrame2() for post-write verification Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
56 lines
1.8 KiB
Swift
56 lines
1.8 KiB
Swift
import Foundation
|
|
import CoreBluetooth
|
|
|
|
/// Tries KBeacon → DXSmart → BlueCharm in sequence for unknown beacon types.
|
|
/// Matches Android's fallback behavior when beacon type can't be determined.
|
|
final class FallbackProvisioner: BeaconProvisioner {
|
|
|
|
private let peripheral: CBPeripheral
|
|
private let centralManager: CBCentralManager
|
|
private var activeProvisioner: (any BeaconProvisioner)?
|
|
|
|
private(set) var isConnected: Bool = false
|
|
|
|
init(peripheral: CBPeripheral, centralManager: CBCentralManager) {
|
|
self.peripheral = peripheral
|
|
self.centralManager = centralManager
|
|
}
|
|
|
|
func connect() async throws {
|
|
let provisioners: [() -> any BeaconProvisioner] = [
|
|
{ KBeaconProvisioner(peripheral: self.peripheral, centralManager: self.centralManager) },
|
|
{ DXSmartProvisioner(peripheral: self.peripheral, centralManager: self.centralManager) },
|
|
{ BlueCharmProvisioner(peripheral: self.peripheral, centralManager: self.centralManager) },
|
|
]
|
|
|
|
var lastError: Error = ProvisionError.connectionTimeout
|
|
|
|
for makeProvisioner in provisioners {
|
|
let provisioner = makeProvisioner()
|
|
do {
|
|
try await provisioner.connect()
|
|
activeProvisioner = provisioner
|
|
isConnected = true
|
|
return
|
|
} catch {
|
|
provisioner.disconnect()
|
|
lastError = error
|
|
}
|
|
}
|
|
|
|
throw lastError
|
|
}
|
|
|
|
func writeConfig(_ config: BeaconConfig) async throws {
|
|
guard let provisioner = activeProvisioner else {
|
|
throw ProvisionError.notConnected
|
|
}
|
|
try await provisioner.writeConfig(config)
|
|
}
|
|
|
|
func disconnect() {
|
|
activeProvisioner?.disconnect()
|
|
activeProvisioner = nil
|
|
isConnected = false
|
|
}
|
|
}
|