Skip to content

API Reference

Latisha. edited this page Dec 27, 2024 · 1 revision

API Reference

Core Classes

CoreBluetoothManager

Core class for BLE operations.

public class CoreBluetoothManager: NSObject, ObservableObject {
    /// Shared instance
    public static let shared = CoreBluetoothManager()
    
    /// Current connection state
    @Published public var isPeripheralReady: Bool
    
    /// Connected device
    @Published public var connectedDevice: CBPeripheral?
    
    /// List of discovered devices
    @Published public var discoveredPeripherals: [CBPeripheral]
    
    /// Start scanning for devices
    public func startScanning()
    
    /// Stop scanning
    public func stopScanning()
    
    /// Connect to a device
    /// - Parameter address: Device UUID string
    /// - Returns: Success status
    public func connectToDevice(_ address: String) -> Bool
    
    /// Close current connection
    public func close()
}

DiveLogRetriever

Handles dive log download and processing.

public class DiveLogRetriever {
    /// Retrieve dive logs from a device
    /// - Parameters:
    ///   - devicePtr: Pointer to device data
    ///   - deviceName: Name of the device
    ///   - viewModel: View model for updates
    ///   - onProgress: Progress callback
    ///   - completion: Completion handler
    public static func retrieveDiveLogs(
        from devicePtr: UnsafeMutablePointer<device_data_t>,
        deviceName: String,
        viewModel: DiveDataViewModel,
        onProgress: ((Int, Int) -> Void)?,
        completion: @escaping (Bool) -> Void
    )
}

GenericParser

Parses dive data from various devices.

public class GenericParser {
    /// Parse dive data from raw bytes
    /// - Parameters:
    ///   - family: Device family
    ///   - model: Device model
    ///   - diveNumber: Dive number
    ///   - diveData: Raw dive data
    ///   - dataSize: Size of data
    /// - Returns: Parsed dive data
    public static func parseDiveData(
        family: DeviceFamily,
        model: UInt32,
        diveNumber: Int,
        diveData: UnsafePointer<UInt8>,
        dataSize: Int
    ) throws -> DiveData
}

Data Models

DiveData

Represents a complete dive record.

public struct DiveData: Identifiable {
    /// Unique identifier
    public let id: UUID
    
    /// Dive number
    public let number: Int
    
    /// Date and time of dive
    public let datetime: Date
    
    /// Maximum depth reached (meters)
    public var maxDepth: Double
    
    /// Total dive time (seconds)
    public var divetime: TimeInterval
    
    /// Water temperature (Celsius)
    public var temperature: Double
    
    /// Detailed dive profile
    public var profile: [DiveProfilePoint]
    
    /// Tank pressure readings
    public var tankPressure: [Double]
    
    /// Current gas mix index
    public var gasMix: Int?
    
    /// Tank information
    public var tanks: [Tank]?
}

DiveProfilePoint

Individual point in dive profile.

public struct DiveProfilePoint {
    /// Time from start of dive
    public let time: TimeInterval
    
    /// Current depth
    public let depth: Double
    
    /// Temperature at this point
    public let temperature: Double?
    
    /// Tank pressure
    public let pressure: Double?
    
    /// Gas partial pressures
    public let po2: Double?
    public let pn2: Double?
    public let phe: Double?
}

View Models

DiveDataViewModel

Manages dive data and download state.

public class DiveDataViewModel: ObservableObject {
    /// Retrieved dives
    @Published public var dives: [DiveData]
    
    /// Current status message
    @Published public var status: String
    
    /// Download progress
    @Published public var progress: DownloadProgress
    
    /// Last dive fingerprint
    @Published public var lastFingerprint: Data?
    
    /// Clear all data
    public func clear()
    
    /// Save fingerprint
    public func saveFingerprint(_ fingerprint: Data)
    
    /// Update progress
    public func updateProgress(current: Int)
}

Protocols

DeviceProtocol

Protocol for dive computer devices.

public protocol DeviceProtocol {
    /// Device family
    var family: DeviceFamily { get }
    
    /// Device model
    var model: UInt32 { get }
    
    /// Connect to device
    func connect() async throws
    
    /// Disconnect from device
    func disconnect()
    
    /// Retrieve dive logs
    func retrieveLogs() async throws -> [DiveData]
}

Enumerations

DeviceFamily

Supported device families.

public enum DeviceFamily: String, Codable {
    case shearwaterPredator
    case shearwaterPetrel
    case suuntoEonSteel
    
    var asDCFamily: dc_family_t {
        switch self {
        case .shearwaterPredator: 
            return DC_FAMILY_SHEARWATER_PREDATOR
        case .shearwaterPetrel: 
            return DC_FAMILY_SHEARWATER_PETREL
        case .suuntoEonSteel: 
            return DC_FAMILY_SUUNTO_EONSTEEL
        }
    }
}

DownloadProgress

Download progress states.

public enum DownloadProgress: Equatable {
    case idle
    case inProgress(current: Int)
    case completed
    case error(String)
    case cancelled
}

Extensions

Data Extensions

extension Data {
    /// Hex string representation
    var hexString: String {
        map { String(format: "%02hhx", $0) }.joined()
    }
    
    /// Find complete HDLC frame
    func findCompleteFrame() -> Data?
}

Example Usage

Basic Device Connection

let manager = CoreBluetoothManager.shared
manager.startScanning()

// Handle discovered devices
manager.$discoveredPeripherals
    .sink { peripherals in
        for peripheral in peripherals {
            if peripheral.name?.contains("EON") == true {
                _ = manager.connectToDevice(
                    peripheral.identifier.uuidString
                )
            }
        }
    }
    .store(in: &cancellables)

Retrieve Dive Logs

let viewModel = DiveDataViewModel()

DiveLogRetriever.retrieveDiveLogs(
    from: devicePtr,
    deviceName: "EON Steel",
    viewModel: viewModel,
    onProgress: { current, total in
        print("Progress: \(current)/\(total)")
    }
) { success in
    if success {
        print("Retrieved \(viewModel.dives.count) dives")
    }
}

Parse Dive Data

do {
    let dive = try GenericParser.parseDiveData(
        family: .suuntoEonSteel,
        model: SuuntoModel.eonSteel,
        diveNumber: 1,
        diveData: dataPtr,
        dataSize: size
    )
    
    print("Dive depth: \(dive.maxDepth)m")
    print("Duration: \(dive.divetime) seconds")
} catch {
    print("Parse error: \(error)")
}