Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions Sources/MetaWear/BoardEngine.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import Foundation
import CoreBluetooth
import Combine

public protocol BoardEngine {
// Called once we have the peripheral and characteristics
func initialize(peripheral: CBPeripheral, commandChar: CBCharacteristic?, notifyChar: CBCharacteristic?, queue: DispatchQueue)

// Full Swift initialization pipeline (parity with C++ initialize):
// Enables notify (handled via setNotifyValue in MetaWear), reads DIS,
// discovers modules by querying READ_INFO_REGISTER in the same order
// as the C++ MODULE_DISCOVERY_CMDS, optionally reads logging time,
// runs module init hooks, and returns BoardState.
func startInitialization() -> AnyPublisher<BoardState, MWError>

// Low-level write
func send(_ data: Data, expectsResponse: Bool) -> AnyPublisher<Data?, MWError>

// Raw notify payloads
func notifications() -> AnyPublisher<Data, Never>
}

public final class NoopBoardEngine: BoardEngine {
private let subject = PassthroughSubject<Data, Never>()
public init() {}

public func initialize(peripheral: CBPeripheral, commandChar: CBCharacteristic?, notifyChar: CBCharacteristic?, queue: DispatchQueue) {
#if DEBUG
print("[BoardEngine:Noop] initialize called with peripheral: \(peripheral.identifier), command: \(String(describing: commandChar?.uuid)), notify: \(String(describing: notifyChar?.uuid)), queue: \(queue.label)")
#endif
// no-op
}

public func startInitialization() -> AnyPublisher<BoardState, MWError> {
#if DEBUG
print("[BoardEngine:Noop] startInitialization called")
#endif
return Fail(error: MWError.operationFailed("Board engine not configured")).eraseToAnyPublisher()
}

public func send(_ data: Data, expectsResponse: Bool) -> AnyPublisher<Data?, MWError> {
#if DEBUG
print("[BoardEngine:Noop] send called ->", data as NSData, "expectsResponse:", expectsResponse)
#endif
return Fail<Data?, MWError>(error: MWError.operationFailed("Board engine not configured"))
.eraseToAnyPublisher()
}

public func notifications() -> AnyPublisher<Data, Never> {
#if DEBUG
print("[BoardEngine:Noop] notifications publisher requested")
#endif
return subject.eraseToAnyPublisher()
}
}

72 changes: 72 additions & 0 deletions Sources/MetaWear/BoardState.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import Foundation

public struct BoardState: Equatable, Sendable {
public struct ModuleInfo: Equatable, Sendable {
public var present: Bool
public var implementation: Int32
public var revision: UInt8
public var extra: Data

public init(present: Bool, implementation: Int32, revision: UInt8, extra: Data) {
self.present = present
self.implementation = implementation
self.revision = revision
self.extra = extra
#if DEBUG
print("[BoardState] ModuleInfo init -> present: \(present), impl: \(implementation), rev: \(revision), extraBytes: \(extra.count)")
#endif
}
}

public struct LoggingTimeRef: Equatable, Sendable {
public var resetUID: UInt32
public var epochMs: Int64

public init(resetUID: UInt32, epochMs: Int64) {
self.resetUID = resetUID
self.epochMs = epochMs
#if DEBUG
print("[BoardState] LoggingTimeRef init -> resetUID: \(resetUID), epochMs: \(epochMs)")
#endif
}
}

// Minimal properties we can know during setup without C++
public var isMetaBoot: Bool

// DIS fields
public var firmwareRevision: String?
public var hardwareRevision: String?
public var modelNumber: String?
public var manufacturerName: String?
public var serialNumber: String?

// Module info keyed by module id (UInt8)
public var moduleInfo: [UInt8: ModuleInfo]

// Optional logging reference time
public var loggingTime: LoggingTimeRef?

public init(
isMetaBoot: Bool,
firmwareRevision: String? = nil,
hardwareRevision: String? = nil,
modelNumber: String? = nil,
manufacturerName: String? = nil,
serialNumber: String? = nil,
moduleInfo: [UInt8: ModuleInfo] = [:],
loggingTime: LoggingTimeRef? = nil
) {
self.isMetaBoot = isMetaBoot
self.firmwareRevision = firmwareRevision
self.hardwareRevision = hardwareRevision
self.modelNumber = modelNumber
self.manufacturerName = manufacturerName
self.serialNumber = serialNumber
self.moduleInfo = moduleInfo
self.loggingTime = loggingTime
#if DEBUG
print("[BoardState] init -> metaBoot: \(isMetaBoot), fw: \(String(describing: firmwareRevision)), hw: \(String(describing: hardwareRevision)), model: \(String(describing: modelNumber)), mfr: \(String(describing: manufacturerName)), serial: \(String(describing: serialNumber)), modules: \(moduleInfo.count), loggingTime: \(String(describing: loggingTime))")
#endif
}
}
Loading