@@ -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 */, |
@@ -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 |
@@ -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 |
|
@@ -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 |
+} |
|
@@ -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 |
} |