Skip to content

Error Handling & Debugging

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

Error Handling & Debugging

Common Errors

BLE Errors

enum BLEError: Error {
    case deviceNotFound
    case connectionFailed(String)
    case serviceDiscoveryFailed
    case characteristicNotFound
    case timeout(operation: String)
    case invalidState(String)
    
    var description: String {
        switch self {
        case .deviceNotFound:
            return "Device not found or out of range"
        case .connectionFailed(let reason):
            return "Connection failed: \(reason)"
        case .serviceDiscoveryFailed:
            return "Failed to discover required services"
        case .characteristicNotFound:
            return "Required characteristic not found"
        case .timeout(let operation):
            return "Operation timed out: \(operation)"
        case .invalidState(let state):
            return "Invalid state: \(state)"
        }
    }
}

Parser Errors

enum ParserError: Error {
    case invalidParameters
    case parserCreationFailed(dc_status_t)
    case datetimeRetrievalFailed(dc_status_t)
    case sampleProcessingFailed(dc_status_t)
    case invalidData(String)
}

Device Errors

enum DeviceError: Error {
    case unsupportedDevice
    case firmwareOutdated
    case lowBattery
    case busyState
    case unauthorized
}

Troubleshooting Guides

Connection Issues

  1. Device Not Found
func troubleshootDeviceNotFound() -> [String] {
    var checklist = [String]()
    
    // Check Bluetooth state
    if centralManager.state != .poweredOn {
        checklist.append("Enable Bluetooth")
    }
    
    // Check device name
    if let name = deviceName, name.isEmpty {
        checklist.append("Verify device name")
    }
    
    // Check range
    if let rssi = lastRSSI, rssi < -80 {
        checklist.append("Move closer to device")
    }
    
    return checklist
}
  1. Connection Failures
func troubleshootConnection() async -> Bool {
    // Check authorization
    guard CBCentralManager.authorization == .allowedAlways else {
        throw BLEError.unauthorized
    }
    
    // Verify device state
    guard peripheral.state != .connected else {
        try await disconnect()
    }
    
    // Attempt connection
    do {
        try await connect()
        return true
    } catch {
        logError("Connection failed: \(error)")
        return false
    }
}
  1. Data Transfer Issues
func troubleshootTransfer() {
    // Monitor transfer rate
    let transferRate = calculateTransferRate()
    if transferRate < minimumRate {
        logWarning("Slow transfer rate: \(transferRate)")
    }
    
    // Check packet loss
    let lossRate = calculatePacketLoss()
    if lossRate > maxLossRate {
        logError("High packet loss: \(lossRate)%")
    }
}

Logging System

Logger Implementation

public class Logger {
    public static let shared = Logger()
    private var isEnabled = true
    private var minLevel: LogLevel = .debug
    
    public enum LogLevel: Int {
        case debug = 0
        case info = 1
        case warning = 2
        case error = 3
        
        var prefix: String {
            switch self {
            case .debug: return "🔍 DEBUG"
            case .info: return "ℹ️ INFO"
            case .warning: return "⚠️ WARN"
            case .error: return "❌ ERROR"
            }
        }
    }
    
    public func log(_ message: String, 
                   level: LogLevel = .debug, 
                   file: String = #file, 
                   function: String = #function) {
        guard isEnabled && level.rawValue >= minLevel.rawValue else { 
            return 
        }
        
        let timestamp = dateFormatter.string(from: Date())
        let fileName = (file as NSString).lastPathComponent
        
        print("\(level.prefix) [\(timestamp)] [\(fileName)] \(message)")
    }
}

Usage Examples

// Log levels
logDebug("Starting device scan")
logInfo("Device connected: \(deviceName)")
logWarning("Slow transfer rate detected")
logError("Failed to parse dive data: \(error)")

// Detailed logging
func logTransferStats() {
    Logger.shared.log("""
        Transfer Statistics:
        - Bytes transferred: \(bytesTransferred)
        - Transfer rate: \(transferRate) bytes/sec
        - Packet loss: \(packetLoss)%
        - Duration: \(duration) seconds
        """, 
        level: .info
    )
}

Debug Strategies

Debug Tools

  1. State Monitor
class StateMonitor {
    static func dumpState() {
        print("=== System State ===")
        print("BLE State: \(centralManager.state)")
        print("Connected: \(connectedDevice != nil)")
        print("Services: \(discoveredServices.count)")
        print("Buffer Size: \(receivedData.count)")
        print("==================")
    }
}
  1. Packet Inspector
class PacketInspector {
    static func inspectPacket(_ data: Data) {
        print("Packet Size: \(data.count) bytes")
        print("Hex: \(data.hexDescription)")
        print("ASCII: \(data.asciiDescription)")
        
        if data.count >= 2 {
            let header = data.prefix(2)
            print("Header: \(header.hexDescription)")
        }
    }
}
  1. Performance Monitor
class PerformanceMonitor {
    private var timestamps: [String: Date] = [:]
    
    func start(_ operation: String) {
        timestamps[operation] = Date()
    }
    
    func end(_ operation: String) {
        guard let startTime = timestamps[operation] else { return }
        let duration = Date().timeIntervalSince(startTime)
        logInfo("\(operation) took \(duration) seconds")
    }
}

Debugging Techniques

  1. Connection Debugging
func debugConnection() {
    // Enable detailed logging
    Logger.shared.setMinLevel(.debug)
    Logger.shared.setShowRawData(true)
    
    // Monitor state changes
    centralManager.$state
        .sink { state in
            logDebug("BLE State changed: \(state)")
        }
        .store(in: &cancellables)
        
    // Monitor connection events
    peripheral.delegate = self
}
  1. Data Transfer Debugging
func debugTransfer() {
    // Monitor chunks
    func didReceiveData(_ data: Data) {
        logDebug("""
            Received chunk:
            - Size: \(data.count)
            - First bytes: \(data.prefix(4).hexDescription)
            - Buffer size: \(receivedData.count)
            """)
    }
}
  1. Parser Debugging
func debugParsing(_ data: Data) {
    // Validate structure
    guard data.count >= minSize else {
        logError("Invalid data size: \(data.count)")
        return
    }
    
    // Check markers
    let hasStartMarker = data.first == frameMarker
    let hasEndMarker = data.last == frameMarker
    logDebug("Markers: start=\(hasStartMarker), end=\(hasEndMarker)")
    
    // Validate checksum
    let checksumValid = validateChecksum(data)
    logDebug("Checksum valid: \(checksumValid)")
}