Showing 4 changed files with 62 additions and 3 deletions
+16 -0
USB Meter/Model/Meter.swift
@@ -153,6 +153,14 @@ class Meter : NSObject, ObservableObject, Identifiable {
153 153
         capabilities.chargerTypeDescription(for: chargerTypeIndex)
154 154
     }
155 155
 
156
+    var deviceModelSummary: String {
157
+        let baseName = reportedModelName.isEmpty ? modelString : reportedModelName
158
+        if modelNumber != 0 {
159
+            return "\(baseName) (\(modelNumber))"
160
+        }
161
+        return baseName
162
+    }
163
+
156 164
     @Published var btSerial: BluetoothSerial
157 165
     
158 166
     @Published var measurements = Measurements()
@@ -217,6 +225,10 @@ class Meter : NSObject, ObservableObject, Identifiable {
217 225
     @Published var loadResistance: Double = 0
218 226
     @Published var modelNumber: UInt16 = 0
219 227
     @Published var chargerTypeIndex: UInt16 = 0
228
+    @Published var reportedModelName: String = ""
229
+    @Published var firmwareVersion: String = ""
230
+    @Published var serialNumber: UInt32 = 0
231
+    @Published var bootCount: UInt32 = 0
220 232
     private var enableAutoConnect: Bool = false
221 233
         
222 234
     init ( model: Model, with serialPort: BluetoothSerial ) {
@@ -332,6 +344,10 @@ class Meter : NSObject, ObservableObject, Identifiable {
332 344
     }
333 345
 
334 346
     private func apply(tc66Snapshot snapshot: TC66Snapshot) {
347
+        reportedModelName = snapshot.modelName
348
+        firmwareVersion = snapshot.firmwareVersion
349
+        serialNumber = snapshot.serialNumber
350
+        bootCount = snapshot.bootCount
335 351
         voltage = snapshot.voltage
336 352
         current = snapshot.current
337 353
         power = snapshot.power
+8 -2
USB Meter/Model/TC66Protocol.swift
@@ -47,6 +47,12 @@ enum TC66Protocol {
47 47
         0xa7, 0xf1, 0x06, 0x61, 0x9a, 0xb8, 0x72, 0x88
48 48
     ]
49 49
 
50
+    private static func sanitizedASCII(from data: Data) -> String {
51
+        data.asciiString
52
+            .replacingOccurrences(of: "\0", with: "")
53
+            .trimmingCharacters(in: .whitespacesAndNewlines.union(.controlCharacters))
54
+    }
55
+
50 56
     private static func validate(packetId: UInt8, packet: Data) -> Bool {
51 57
         let expectedHeader = "pac\(packetId)".data(using: .ascii)
52 58
         let packetHeader = packet.subdata(from: 0, length: 4)
@@ -91,8 +97,8 @@ enum TC66Protocol {
91 97
         let temperatureSign = UInt32(littleEndian: pac2.value(from: 24)) == 1 ? -1.0 : 1.0
92 98
 
93 99
         return TC66Snapshot(
94
-            modelName: pac1.subdata(from: 4, length: 4).asciiString,
95
-            firmwareVersion: pac1.subdata(from: 8, length: 4).asciiString,
100
+            modelName: sanitizedASCII(from: pac1.subdata(from: 4, length: 4)),
101
+            firmwareVersion: sanitizedASCII(from: pac1.subdata(from: 8, length: 4)),
96 102
             serialNumber: UInt32(littleEndian: pac1.value(from: 12)),
97 103
             bootCount: UInt32(littleEndian: pac1.value(from: 44)),
98 104
             voltage: Double(UInt32(littleEndian: pac1.value(from: 48))) / 10000,
+37 -0
USB Meter/Views/Meter/MeterSettingsView.swift
@@ -35,6 +35,27 @@ struct MeterSettingsView: View {
35 35
                 }
36 36
                 .padding()
37 37
                 .background(RoundedRectangle(cornerRadius: 15).foregroundColor(.secondary).opacity(0.1))
38
+                if meter.operationalState == .dataIsAvailable {
39
+                    VStack(alignment: .leading, spacing: 8) {
40
+                        Text("Device Info").fontWeight(.semibold)
41
+                        DeviceInfoRow(label: "Advertised Model", value: meter.modelString)
42
+                        DeviceInfoRow(label: "Displayed Model", value: meter.deviceModelSummary)
43
+                        if meter.modelNumber != 0 {
44
+                            DeviceInfoRow(label: "Model Code", value: "\(meter.modelNumber)")
45
+                        }
46
+                        if !meter.firmwareVersion.isEmpty {
47
+                            DeviceInfoRow(label: "Firmware", value: meter.firmwareVersion)
48
+                        }
49
+                        if meter.serialNumber != 0 {
50
+                            DeviceInfoRow(label: "Serial", value: "\(meter.serialNumber)")
51
+                        }
52
+                        if meter.bootCount != 0 {
53
+                            DeviceInfoRow(label: "Boot Count", value: "\(meter.bootCount)")
54
+                        }
55
+                    }
56
+                    .padding()
57
+                    .background(RoundedRectangle(cornerRadius: 15).foregroundColor(.secondary).opacity(0.1))
58
+                }
38 59
                 if meter.operationalState == .dataIsAvailable && meter.supportsUMSettings {
39 60
                     // MARK: Screen Timeout
40 61
                     // Ar trebui separat enabled/disabled de valorile in minute eventual stocata valoarea in iCloud la dezactivare pentru restaurare
@@ -78,6 +99,22 @@ struct MeterSettingsView: View {
78 99
     }
79 100
 }
80 101
 
102
+private struct DeviceInfoRow: View {
103
+    let label: String
104
+    let value: String
105
+
106
+    var body: some View {
107
+        HStack {
108
+            Text(label)
109
+            Spacer()
110
+            Text(value)
111
+                .foregroundColor(.secondary)
112
+                .multilineTextAlignment(.trailing)
113
+        }
114
+        .font(.footnote)
115
+    }
116
+}
117
+
81 118
 struct EditNameView: View {
82 119
     
83 120
     @EnvironmentObject private var meter: Meter
+1 -1
USB Meter/Views/Meter/MeterView.swift
@@ -42,7 +42,7 @@ struct MeterView: View {
42 42
             connectionControlButton()
43 43
             // MARK: Show Data
44 44
             if ( meter.operationalState ==  .dataIsAvailable) {
45
-                Text("Model: \(meter.modelString) - (\(meter.modelNumber))")
45
+                Text("Model: \(meter.deviceModelSummary)")
46 46
                 HStack {
47 47
                     Button(action: {self.dataGroupsViewVisibility.toggle()}) {
48 48
                         VStack {