Showing 5 changed files with 133 additions and 42 deletions
+4 -0
USB Meter.xcodeproj/project.pbxproj
@@ -34,6 +34,7 @@
34 34
 		438695892463F062008855A9 /* Measurements.swift in Sources */ = {isa = PBXBuildFile; fileRef = 438695882463F062008855A9 /* Measurements.swift */; };
35 35
 		4386958B2F6A1001008855A9 /* UMProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4386958A2F6A1001008855A9 /* UMProtocol.swift */; };
36 36
 		4386958D2F6A1002008855A9 /* TC66Protocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4386958C2F6A1002008855A9 /* TC66Protocol.swift */; };
37
+		4386958F2F6A4E3E008855A9 /* MeterCapabilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4386958E2F6A4E3E008855A9 /* MeterCapabilities.swift */; };
37 38
 		43874C7F2414F3F400525397 /* Float.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43874C7E2414F3F400525397 /* Float.swift */; };
38 39
 		43874C83241533AD00525397 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43874C82241533AD00525397 /* Data.swift */; };
39 40
 		43874C852415611200525397 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43874C842415611200525397 /* Double.swift */; };
@@ -111,6 +112,7 @@
111 112
 		438695882463F062008855A9 /* Measurements.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Measurements.swift; sourceTree = "<group>"; };
112 113
 		4386958A2F6A1001008855A9 /* UMProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UMProtocol.swift; sourceTree = "<group>"; };
113 114
 		4386958C2F6A1002008855A9 /* TC66Protocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TC66Protocol.swift; sourceTree = "<group>"; };
115
+		4386958E2F6A4E3E008855A9 /* MeterCapabilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeterCapabilities.swift; sourceTree = "<group>"; };
114 116
 		43874C7E2414F3F400525397 /* Float.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Float.swift; sourceTree = "<group>"; };
115 117
 		43874C82241533AD00525397 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
116 118
 		43874C842415611200525397 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
@@ -359,6 +361,7 @@
359 361
 				4383B45F240EB2D000DAAEBF /* Meter.swift */,
360 362
 				43ED78AD2420A0BE00974487 /* BluetoothSerial.swift */,
361 363
 				439D996424234B98008DE3AA /* BluetoothRadio.swift */,
364
+				4386958E2F6A4E3E008855A9 /* MeterCapabilities.swift */,
362 365
 				4386958A2F6A1001008855A9 /* UMProtocol.swift */,
363 366
 				4386958C2F6A1002008855A9 /* TC66Protocol.swift */,
364 367
 				43CBF663240BF3EB00255B8B /* CKModel.xcdatamodeld */,
@@ -499,6 +502,7 @@
499 502
 				437D47D52415FD8C00B7768E /* RecordingView.swift in Sources */,
500 503
 				432EA6442445A559006FC905 /* ChartContext.swift in Sources */,
501 504
 				4308CF8624176CAB0002E80B /* DataGroupRowView.swift in Sources */,
505
+				4386958F2F6A4E3E008855A9 /* MeterCapabilities.swift in Sources */,
502 506
 				43554B32244449B5004E66F5 /* MeasurementPointView.swift in Sources */,
503 507
 				43F7792B2465AE1600745DF4 /* UIView.swift in Sources */,
504 508
 				43ED78AE2420A0BE00974487 /* BluetoothSerial.swift in Sources */,
+2 -2
USB Meter/Model/BluetoothManager.swift
@@ -46,7 +46,7 @@ class BluetoothManager : NSObject, ObservableObject {
46 46
             return
47 47
         }
48 48
         
49
-        guard let model = ModelByPeriferalName[peripheralName] else {
49
+        guard let model = Model.byPeripheralName[peripheralName] else {
50 50
             return
51 51
         }
52 52
         
@@ -54,7 +54,7 @@ class BluetoothManager : NSObject, ObservableObject {
54 54
         
55 55
         if appData.meters[peripheral.identifier] == nil {
56 56
             track("adding new USB Meter named '\(peripheralName)' with MAC Address: '\(macAddress)'")
57
-            let btSerial = BluetoothSerial(peripheral: peripheral, radio: modelRadios[model] ?? .UNKNOWN, with: macAddress, managedBy: manager!, RSSI: RSSI.intValue)
57
+            let btSerial = BluetoothSerial(peripheral: peripheral, radio: model.radio, with: macAddress, managedBy: manager!, RSSI: RSSI.intValue)
58 58
             var m = appData.meters
59 59
             m[peripheral.identifier] = Meter(model: model, with: btSerial)
60 60
             appData.meters = m
+21 -39
USB Meter/Model/Meter.swift
@@ -12,7 +12,6 @@
12 12
 //MARK: Package dependency https://github.com/krzyzanowskim/CryptoSwift
13 13
 
14 14
 import CoreBluetooth
15
-import CryptoSwift
16 15
 import SwiftUI
17 16
 
18 17
 /**
@@ -23,32 +22,12 @@ import SwiftUI
23 22
  [UM Series](https://sigrok.org/wiki/RDTech_UM_series)
24 23
  [TC66C](https://sigrok.org/wiki/RDTech_TC66C)
25 24
  */
26
-enum Model {
25
+enum Model: CaseIterable {
27 26
     case UM25C
28 27
     case UM34C
29 28
     case TC66C
30 29
 }
31 30
 
32
-var modelRadios: [Model : BluetoothRadio] = [
33
-    .UM25C : .BT18,
34
-    .UM34C : .BT18,
35
-    .TC66C : .PW0316
36
-]
37
-
38
-var ModelByPeriferalName: [String : Model] = [
39
-    "UM25C" : .UM25C,
40
-    "UM34C" : .UM34C,
41
-    "TC66C" : .TC66C,
42
-    "PW0316" : .TC66C
43
-]
44
-
45
-var colorForModel: [Model : Color] = [
46
-    .UM25C : .blue,
47
-    .UM34C : .yellow,
48
-    .TC66C : .black
49
-]
50
-
51
-
52 31
 class Meter : NSObject, ObservableObject, Identifiable {
53 32
 
54 33
     enum OperationalState: Int, Comparable {
@@ -138,37 +117,40 @@ class Meter : NSObject, ObservableObject, Identifiable {
138 117
     
139 118
     var color : Color {
140 119
         get {
141
-            return colorForModel[model]!
120
+            return model.color
142 121
         }
143 122
     }
144 123
 
124
+    var capabilities: MeterCapabilities {
125
+        model.capabilities
126
+    }
127
+
145 128
     var availableDataGroupIDs: [UInt8] {
146
-        switch model {
147
-        case .UM25C, .UM34C:
148
-            return Array(0...9)
149
-        case .TC66C:
150
-            return [0, 1]
151
-        }
129
+        capabilities.availableDataGroupIDs
152 130
     }
153 131
 
154 132
     var supportsDataGroupCommands: Bool {
155
-        model != .TC66C
133
+        capabilities.supportsDataGroupCommands
156 134
     }
157 135
 
158 136
     var supportsUMSettings: Bool {
159
-        model != .TC66C
137
+        capabilities.supportsScreenSettings
160 138
     }
161 139
 
162 140
     var supportsRecordingThreshold: Bool {
163
-        model != .TC66C
141
+        capabilities.supportsRecordingThreshold
164 142
     }
165 143
 
166 144
     var supportsFahrenheit: Bool {
167
-        model != .TC66C
145
+        capabilities.supportsFahrenheit
168 146
     }
169 147
 
170 148
     var supportsChargerDetection: Bool {
171
-        model != .TC66C
149
+        capabilities.supportsChargerDetection
150
+    }
151
+
152
+    var chargerTypeDescription: String {
153
+        capabilities.chargerTypeDescription(for: chargerTypeIndex)
172 154
     }
173 155
 
174 156
     @Published var btSerial: BluetoothSerial
@@ -396,12 +378,12 @@ class Meter : NSObject, ObservableObject, Identifiable {
396 378
     }
397 379
     
398 380
     func clear() {
399
-        guard model != .TC66C else { return }
381
+        guard supportsDataGroupCommands else { return }
400 382
         commandQueue.append(UMProtocol.clearCurrentGroup)
401 383
     }
402 384
     
403 385
     func clear(group id: UInt8) {
404
-        guard model != .TC66C else { return }
386
+        guard supportsDataGroupCommands else { return }
405 387
         commandQueue.append(UMProtocol.selectDataGroup(id))
406 388
         clear()
407 389
         commandQueue.append(UMProtocol.selectDataGroup(selectedDataGroup))
@@ -416,16 +398,16 @@ class Meter : NSObject, ObservableObject, Identifiable {
416 398
     
417 399
     private func setSceeenBrightness ( to value: UInt8) {
418 400
         track("\(name) - \(value)")
419
-        guard model != .TC66C else { return }
401
+        guard supportsUMSettings else { return }
420 402
         commandQueue.append(UMProtocol.setScreenBrightness(value))
421 403
     }
422 404
     private func setScreenSaverTimeout ( to value: UInt8) {
423 405
         track("\(name) - \(value)")
424
-        guard model != .TC66C else { return }
406
+        guard supportsUMSettings else { return }
425 407
         commandQueue.append(UMProtocol.setScreenSaverTimeout(value))
426 408
     }
427 409
     func setrecordingTreshold ( to value: UInt8) {
428
-        guard model != .TC66C else { return }
410
+        guard supportsRecordingThreshold else { return }
429 411
         commandQueue.append(UMProtocol.setRecordingThreshold(value))
430 412
     }
431 413
     
+105 -0
USB Meter/Model/MeterCapabilities.swift
@@ -0,0 +1,105 @@
1
+//
2
+//  MeterCapabilities.swift
3
+//  USB Meter
4
+//
5
+//  Created by Codex on 23/03/2026.
6
+//
7
+
8
+import SwiftUI
9
+
10
+struct MeterCapabilities {
11
+    let availableDataGroupIDs: [UInt8]
12
+    let supportsDataGroupCommands: Bool
13
+    let supportsScreenSettings: Bool
14
+    let supportsRecordingThreshold: Bool
15
+    let supportsFahrenheit: Bool
16
+    let supportsChargerDetection: Bool
17
+    let chargerTypeDescriptions: [UInt16: String]
18
+
19
+    func chargerTypeDescription(for index: UInt16) -> String {
20
+        guard supportsChargerDetection else { return "-" }
21
+        if let label = chargerTypeDescriptions[index] {
22
+            return label
23
+        }
24
+        return index == 0 ? "Unknown" : "Unknown (\(index))"
25
+    }
26
+}
27
+
28
+extension MeterCapabilities {
29
+    static let umFamily = MeterCapabilities(
30
+        availableDataGroupIDs: Array(0...9),
31
+        supportsDataGroupCommands: true,
32
+        supportsScreenSettings: true,
33
+        supportsRecordingThreshold: true,
34
+        supportsFahrenheit: true,
35
+        supportsChargerDetection: true,
36
+        chargerTypeDescriptions: [
37
+            1: "QC2",
38
+            2: "QC3",
39
+            3: "Apple 2.4A",
40
+            4: "Apple 2.1A",
41
+            5: "Apple 1.0A",
42
+            6: "Apple 0.5A",
43
+            7: "DCP 1.5A",
44
+            8: "Samsung"
45
+        ]
46
+    )
47
+
48
+    static let tc66c = MeterCapabilities(
49
+        availableDataGroupIDs: [0, 1],
50
+        supportsDataGroupCommands: false,
51
+        supportsScreenSettings: false,
52
+        supportsRecordingThreshold: false,
53
+        supportsFahrenheit: false,
54
+        supportsChargerDetection: false,
55
+        chargerTypeDescriptions: [:]
56
+    )
57
+}
58
+
59
+extension Model {
60
+    static let byPeripheralName = Dictionary(
61
+        uniqueKeysWithValues: allCases.flatMap { model in
62
+            model.peripheralNames.map { ($0, model) }
63
+        }
64
+    )
65
+
66
+    var radio: BluetoothRadio {
67
+        switch self {
68
+        case .UM25C, .UM34C:
69
+            return .BT18
70
+        case .TC66C:
71
+            return .PW0316
72
+        }
73
+    }
74
+
75
+    var peripheralNames: [String] {
76
+        switch self {
77
+        case .UM25C:
78
+            return ["UM25C"]
79
+        case .UM34C:
80
+            return ["UM34C"]
81
+        case .TC66C:
82
+            return ["TC66C", "PW0316"]
83
+        }
84
+    }
85
+
86
+    var color: Color {
87
+        switch self {
88
+        case .UM25C:
89
+            return .blue
90
+        case .UM34C:
91
+            return .yellow
92
+        case .TC66C:
93
+            return .black
94
+        }
95
+    }
96
+
97
+    var capabilities: MeterCapabilities {
98
+        switch self {
99
+        case .UM25C, .UM34C:
100
+            return .umFamily
101
+        case .TC66C:
102
+            return .tc66c
103
+        }
104
+    }
105
+}
+1 -1
USB Meter/Views/Meter/LiveView.swift
@@ -56,7 +56,7 @@ struct LiveView: View {
56 56
                     Text("\(meter.usbPlusVoltage.format(decimalDigits: 2))V")
57 57
                     Text("\(meter.usbMinusVoltage.format(decimalDigits: 2))V")
58 58
                     if meter.supportsChargerDetection {
59
-                        Text("\(meter.chargerTypeIndex)")
59
+                        Text(meter.chargerTypeDescription)
60 60
                     }
61 61
                 }
62 62
             }