// // MeterCapabilities.swift // USB Meter // // Created by Codex on 23/03/2026. // import SwiftUI struct MeterCapabilities { let availableDataGroupIDs: [UInt8] let supportsDataGroupCommands: Bool let supportsRecordingView: Bool let supportsScreenSettings: Bool let supportsRecordingThreshold: Bool let reportsCurrentScreenIndex: Bool let showsDataGroupEnergy: Bool let highlightsActiveDataGroup: Bool let supportsFahrenheit: Bool let supportsChargerDetection: Bool let primaryTemperatureUnitSymbol: String? let dataGroupsTitle: String let documentedWorkingVoltage: String let chargerTypeDescriptions: [UInt16: String] let screenDescriptions: [UInt16: String] let dataGroupsHint: String? let recordingThresholdHint: String? func chargerTypeDescription(for index: UInt16) -> String { guard supportsChargerDetection else { return "-" } if let label = chargerTypeDescriptions[index] { return label } return index == 0 ? "Unknown" : "Unknown (\(index))" } func screenDescription(for index: UInt16) -> String? { screenDescriptions[index] } } extension MeterCapabilities { static let umFamily = MeterCapabilities( availableDataGroupIDs: Array(0...9), supportsDataGroupCommands: true, supportsRecordingView: true, supportsScreenSettings: true, supportsRecordingThreshold: true, reportsCurrentScreenIndex: true, showsDataGroupEnergy: true, highlightsActiveDataGroup: true, supportsFahrenheit: true, supportsChargerDetection: true, primaryTemperatureUnitSymbol: "℃", dataGroupsTitle: "Data Groups", documentedWorkingVoltage: "4-24 V", chargerTypeDescriptions: [ 1: "QC2", 2: "QC3", 3: "Apple 2.4A", 4: "Apple 2.1A", 5: "Apple 1.0A", 6: "Apple 0.5A", 7: "DCP 1.5A", 8: "Samsung" ], screenDescriptions: [ 0: "Main Measurement", 1: "Quick Charge", 2: "Charging Record", 3: "Cable Impedance", 4: "Graphing", 5: "System Settings" ], dataGroupsHint: "The active group is reported by the meter. Group 0 is temporary. Groups 1-9 persist across power cycles.", recordingThresholdHint: "The meter starts its built-in charge record when current rises above this threshold." ) static let tc66c = MeterCapabilities( availableDataGroupIDs: [0, 1], supportsDataGroupCommands: false, supportsRecordingView: true, supportsScreenSettings: false, supportsRecordingThreshold: false, reportsCurrentScreenIndex: false, showsDataGroupEnergy: true, highlightsActiveDataGroup: false, supportsFahrenheit: false, supportsChargerDetection: false, primaryTemperatureUnitSymbol: nil, dataGroupsTitle: "Memory Totals", documentedWorkingVoltage: "3.5-24 V", chargerTypeDescriptions: [:], screenDescriptions: [:], dataGroupsHint: "The device exposes two read-only memories with charge and energy totals. The active memory is not reported.", recordingThresholdHint: nil ) } extension Model { private static let tc66Tint = Color( uiColor: UIColor { traits in traits.userInterfaceStyle == .dark ? .systemGray2 : .black } ) static let byPeripheralName = Dictionary( uniqueKeysWithValues: allCases.flatMap { model in model.peripheralNames.map { ($0, model) } } ) var radio: BluetoothRadio { switch self { case .UM25C, .UM34C: return .BT18 case .TC66C: return .PW0316 } } var peripheralNames: [String] { switch self { case .UM25C: return ["UM25C"] case .UM34C: return ["UM34C"] case .TC66C: return ["TC66C", "PW0316"] } } var canonicalName: String { switch self { case .UM25C: return "UM25C" case .UM34C: return "UM34C" case .TC66C: return "TC66C" } } var color: Color { switch self { case .UM25C: return .blue case .UM34C: return .yellow case .TC66C: return Self.tc66Tint } } var capabilities: MeterCapabilities { switch self { case .UM25C, .UM34C: return .umFamily case .TC66C: return .tc66c } } }