|
Bogdan Timofte
authored
2 weeks ago
|
1
|
# TC66C Transport and Payload Working Note
|
|
|
2
|
|
|
|
3
|
This note translates the reviewed `TC66` manuals and the current app code into an implementation-oriented working reference.
|
|
|
4
|
|
|
|
5
|
## Scope
|
|
|
6
|
|
|
|
7
|
This note is about `TC66C`, not `TC66`.
|
|
|
8
|
|
|
|
9
|
Reason:
|
|
|
10
|
|
|
|
11
|
- the manuals say `TC66` is USB-only
|
|
|
12
|
- the iOS and Android apps are `TC66C`-only
|
|
|
13
|
- the current app code has a separate `TC66C` BLE path
|
|
|
14
|
|
|
|
15
|
## Evidence Sources
|
|
|
16
|
|
|
|
17
|
Primary sources used for this note:
|
|
|
18
|
|
|
|
19
|
- `Documentation/Research Resources/Specifications/TC66 Manuals Working Summary.md`
|
|
Bogdan Timofte
authored
2 weeks ago
|
20
|
- `Documentation/Research Resources/Specifications/PW0316 BLE Module Working Summary.md`
|
|
Bogdan Timofte
authored
2 weeks ago
|
21
|
- `USB Meter/Model/Meter.swift`
|
|
|
22
|
- `USB Meter/Model/BluetoothRadio.swift`
|
|
|
23
|
- `USB Meter/Model/BluetoothSerial.swift`
|
|
|
24
|
|
|
|
25
|
## Current App Assumptions
|
|
|
26
|
|
|
|
27
|
The current app already treats `TC66C` as a different protocol family than `UM25C` / `UM34C`.
|
|
|
28
|
|
|
|
29
|
Confirmed from code:
|
|
|
30
|
|
|
|
31
|
- model enum contains a dedicated `TC66C` case
|
|
|
32
|
- `TC66C` is mapped to radio type `PW0316`
|
|
|
33
|
- peripheral names `TC66C` and `PW0316` are both recognized as `TC66C`
|
|
|
34
|
- the scan path includes services `FFE0` and `FFE5` for this radio family
|
|
|
35
|
|
|
|
36
|
## BLE Transport Assumptions In Code
|
|
|
37
|
|
|
|
38
|
The current code assumes the following BLE transport for `TC66C`:
|
|
|
39
|
|
|
|
40
|
- notify characteristic: service `FFE0`, characteristic `FFE4`
|
|
|
41
|
- write characteristic: service `FFE5`, characteristic `FFE9`
|
|
|
42
|
|
|
|
43
|
This differs from the `UM` family path already documented elsewhere:
|
|
|
44
|
|
|
|
45
|
- `UM25C` / `UM34C` use `FFE0` / `FFE1`
|
|
|
46
|
- `TC66C` uses a separate `PW0316`-style path in the current app
|
|
|
47
|
|
|
Bogdan Timofte
authored
2 weeks ago
|
48
|
The newly imported `PW0316` vendor manual explicitly validates this mapping:
|
|
|
49
|
|
|
|
50
|
- `FFE5` / `FFE9` is the BLE-to-UART write channel
|
|
|
51
|
- `FFE0` / `FFE4` is the UART-to-BLE notification channel
|
|
|
52
|
- `FFC0` / `FFC1` / `FFC2` exists as an optional anti-hijack password channel
|
|
|
53
|
|
|
Bogdan Timofte
authored
2 weeks ago
|
54
|
## Request / Response Shape
|
|
|
55
|
|
|
|
56
|
The current app polls `TC66C` using ASCII commands.
|
|
|
57
|
|
|
|
58
|
Confirmed command surface already used by the app:
|
|
|
59
|
|
|
|
60
|
- measurement snapshot request: `bgetva\r\n`
|
|
|
61
|
- next page: `bnextp\r\n`
|
|
|
62
|
- previous page: `blastp\r\n`
|
|
|
63
|
- rotate screen: `brotat\r\n`
|
|
|
64
|
|
|
|
65
|
Expected snapshot response size in current code:
|
|
|
66
|
|
|
|
67
|
- `192` bytes
|
|
|
68
|
|
|
|
69
|
Important implication:
|
|
|
70
|
|
|
|
71
|
- the app assumes fixed-length snapshot framing for `TC66C`
|
|
|
72
|
- this is not derived from the manuals directly; it comes from the existing reverse-engineered implementation
|
|
|
73
|
|
|
Bogdan Timofte
authored
2 weeks ago
|
74
|
What the `PW0316` module manual adds here:
|
|
|
75
|
|
|
|
76
|
- the BLE layer itself is designed around `20`-byte BLE payloads
|
|
|
77
|
- UART transparent frames can be up to `200` bytes and are automatically split by the module
|
|
|
78
|
|
|
|
79
|
Working interpretation:
|
|
|
80
|
|
|
|
81
|
- the app's reassembly of a `192`-byte encrypted snapshot is application-layer behavior above the module transport
|
|
|
82
|
- the module manual supports the fragmentation assumption, but not the `192`-byte frame itself
|
|
|
83
|
|
|
Bogdan Timofte
authored
2 weeks ago
|
84
|
## Encrypted Snapshot Structure
|
|
|
85
|
|
|
|
86
|
The current parser decrypts the `192`-byte response with `AES ECB`.
|
|
|
87
|
|
|
|
88
|
Observed implementation details:
|
|
|
89
|
|
|
|
90
|
- the app uses a hard-coded `32`-byte AES key
|
|
|
91
|
- the decrypted payload is treated as three `64`-byte packets
|
|
|
92
|
- those packets are referred to as `pac1`, `pac2`, and `pac3`
|
|
|
93
|
|
|
|
94
|
Each packet is validated as:
|
|
|
95
|
|
|
|
96
|
- first four bytes are ASCII header `pac1`, `pac2`, or `pac3`
|
|
|
97
|
- bytes `0...59` are CRC-covered
|
|
|
98
|
- CRC seed is `0xFFFF`
|
|
|
99
|
- stored CRC is little-endian at offset `60`
|
|
|
100
|
|
|
|
101
|
If any of the three packets fail validation, the app rejects the snapshot as invalid.
|
|
|
102
|
|
|
|
103
|
## Field Map Currently Parsed By The App
|
|
|
104
|
|
|
|
105
|
The offsets below are offsets inside the decrypted packet blocks, not offsets into the encrypted `192`-byte BLE frame.
|
|
|
106
|
|
|
|
107
|
### `pac1`
|
|
|
108
|
|
|
|
109
|
- offset `4`, size `4`: candidate model name as ASCII
|
|
|
110
|
- offset `8`, size `4`: candidate firmware version as ASCII
|
|
|
111
|
- offset `12`, size `4`: candidate serial number, little-endian `UInt32`
|
|
|
112
|
- offset `44`, size `4`: candidate boot count, little-endian `UInt32`
|
|
|
113
|
- offset `48`, size `4`: voltage, raw / `10000`
|
|
|
114
|
- offset `52`, size `4`: current, raw / `100000`
|
|
|
115
|
- offset `56`, size `4`: power, raw / `10000`
|
|
|
116
|
|
|
|
117
|
Confidence:
|
|
|
118
|
|
|
|
119
|
- voltage / current / power are high-confidence because the app actively uses them
|
|
|
120
|
- model / firmware / serial / boot count are medium-confidence because they exist as commented decoding hints in code, not active UI fields
|
|
|
121
|
|
|
|
122
|
### `pac2`
|
|
|
123
|
|
|
|
124
|
- offset `4`, size `4`: load resistance, raw / `10`
|
|
|
125
|
- offset `8`, size `4`: data group `0` accumulated charge, raw / `1000`
|
|
|
126
|
- offset `16`, size `4`: data group `1` accumulated charge, raw / `1000`
|
|
|
127
|
- offset `48`, size `4`: data group `0` accumulated energy, raw / `1000`
|
|
|
128
|
- offset `56`, size `4`: data group `1` accumulated energy, raw / `1000`
|
|
|
129
|
- offset `24`, size `4`: temperature sign flag, `1` means negative in current parser
|
|
|
130
|
- offset `28`, size `4`: temperature magnitude
|
|
|
131
|
- offset `32`, size `4`: `D+` voltage, raw / `100`
|
|
|
132
|
- offset `36`, size `4`: `D-` voltage, raw / `100`
|
|
|
133
|
|
|
|
134
|
Confidence:
|
|
|
135
|
|
|
|
136
|
- load resistance, temperature, `D+`, and `D-` are high-confidence in the sense that the app displays them
|
|
|
137
|
- exact data-group interpretation is medium-confidence because the parser only fills groups `0` and `1`
|
|
|
138
|
|
|
|
139
|
### `pac3`
|
|
|
140
|
|
|
|
141
|
- no fields are currently decoded from `pac3`
|
|
|
142
|
|
|
|
143
|
This is a major open area for further reverse engineering.
|
|
|
144
|
|
|
|
145
|
## Mismatch Between Manuals And Current App
|
|
|
146
|
|
|
|
147
|
### 1. Device pages vs exposed controls
|
|
|
148
|
|
|
|
149
|
The manuals describe many on-device capabilities:
|
|
|
150
|
|
|
|
151
|
- offline recording
|
|
|
152
|
- protocol detection
|
|
|
153
|
- trigger / decoy
|
|
|
154
|
- system settings
|
|
|
155
|
- information page
|
|
|
156
|
- simple mode
|
|
|
157
|
|
|
|
158
|
The current app only implements these direct `TC66C` controls:
|
|
|
159
|
|
|
|
160
|
- request live snapshot
|
|
|
161
|
- previous page
|
|
|
162
|
- next page
|
|
|
163
|
- rotate screen
|
|
|
164
|
|
|
|
165
|
Not implemented in the current app for `TC66C`:
|
|
|
166
|
|
|
|
167
|
- clear data group
|
|
|
168
|
- select data group
|
|
|
169
|
- brightness change
|
|
|
170
|
- screen timeout change
|
|
|
171
|
- recording-threshold change
|
|
|
172
|
|
|
|
173
|
The code explicitly guards these setters off for `TC66C`.
|
|
|
174
|
|
|
|
175
|
### 2. Data-group coverage
|
|
|
176
|
|
|
|
177
|
The manuals discuss data groups, but the current parser only populates two groups for `TC66C`.
|
|
|
178
|
|
|
|
179
|
Working interpretation:
|
|
|
180
|
|
|
|
181
|
- either `TC66C` exposes only two remotely readable groups in the current snapshot layout
|
|
|
182
|
- or the current parser only decodes the first two groups and leaves the rest unknown
|
|
|
183
|
|
|
|
184
|
This needs verification from captures or app analysis.
|
|
|
185
|
|
|
|
186
|
### 3. Bluetooth scope
|
|
|
187
|
|
|
|
188
|
The manuals are clear that:
|
|
|
189
|
|
|
|
190
|
- `TC66` is not a Bluetooth target
|
|
|
191
|
- `TC66C` uses BLE for mobile apps
|
|
|
192
|
|
|
|
193
|
This matches the current app architecture and strengthens confidence that `TC66C` should remain a separate transport family in the codebase.
|
|
|
194
|
|
|
|
195
|
## Working State Model For `TC66C`
|
|
|
196
|
|
|
|
197
|
The current implementation implicitly models at least these state domains:
|
|
|
198
|
|
|
|
199
|
- connection state
|
|
|
200
|
- active device page
|
|
|
201
|
- instantaneous electrical measurements:
|
|
|
202
|
- voltage
|
|
|
203
|
- current
|
|
|
204
|
- power
|
|
|
205
|
- current direction is documented in manuals but not currently decoded into a separate published field
|
|
|
206
|
- accumulated data:
|
|
|
207
|
- charge
|
|
|
208
|
- energy
|
|
|
209
|
- at least two data groups
|
|
|
210
|
- cable and charger context:
|
|
|
211
|
- load resistance
|
|
|
212
|
- `D+`
|
|
|
213
|
- `D-`
|
|
|
214
|
- quick-charge related behavior
|
|
|
215
|
- environment:
|
|
|
216
|
- temperature
|
|
|
217
|
- device metadata:
|
|
|
218
|
- firmware version candidate
|
|
|
219
|
- serial number candidate
|
|
|
220
|
- boot count candidate
|
|
|
221
|
|
|
|
222
|
## Practical Implications For Implementation
|
|
|
223
|
|
|
|
224
|
### Keep `TC66C` separate from UM-family decoding
|
|
|
225
|
|
|
|
226
|
- transport is different
|
|
|
227
|
- request commands are different
|
|
|
228
|
- payload framing is different
|
|
|
229
|
- encryption is different
|
|
|
230
|
|
|
|
231
|
The code already reflects this split and the manuals support it.
|
|
|
232
|
|
|
|
233
|
### Treat `pac3` as the highest-value unknown
|
|
|
234
|
|
|
|
235
|
We already have enough for a basic live meter UI from `pac1` and `pac2`.
|
|
|
236
|
|
|
|
237
|
What is still likely hidden:
|
|
|
238
|
|
|
|
239
|
- additional device settings
|
|
|
240
|
- active page information
|
|
|
241
|
- recording configuration
|
|
|
242
|
- protocol-detection or trigger state
|
|
|
243
|
- more complete data-group information
|
|
|
244
|
|
|
|
245
|
### Do not over-trust current group mapping
|
|
|
246
|
|
|
|
247
|
The app's `TC66C` parser only maps two groups, while the manuals talk more generally about groups and offline storage.
|
|
|
248
|
|
|
|
249
|
Until verified, avoid hard-coding a stronger assumption than:
|
|
|
250
|
|
|
|
251
|
- `TC66C` snapshots currently expose at least two group-like accumulators in our parser
|
|
|
252
|
|
|
|
253
|
### Separate manual truth from protocol truth
|
|
|
254
|
|
|
|
255
|
The manuals are strong for:
|
|
|
256
|
|
|
|
257
|
- feature list
|
|
|
258
|
- UX flow
|
|
|
259
|
- transport family split
|
|
|
260
|
- required `PD / CC pull-down` behavior
|
|
|
261
|
|
|
|
262
|
The manuals are not enough for:
|
|
|
263
|
|
|
|
264
|
- exact BLE field map
|
|
|
265
|
- command framing completeness
|
|
|
266
|
- full payload offsets
|
|
|
267
|
|
|
|
268
|
## Suggested Verification Priorities
|
|
|
269
|
|
|
|
270
|
1. confirm `FFE0/FFE4` notify and `FFE5/FFE9` write behavior against real `TC66C` hardware
|
|
|
271
|
2. capture and archive one or more raw `192`-byte encrypted snapshots
|
|
|
272
|
3. decrypt and annotate unknown bytes in `pac3`
|
|
|
273
|
4. verify whether more than two data groups exist in BLE snapshots
|
|
|
274
|
5. determine whether current device page is present in payload
|
|
|
275
|
6. verify whether recording state and interval are exposed remotely
|
|
|
276
|
7. promote candidate metadata fields in `pac1` from code comments to confirmed fields
|
|
|
277
|
|
|
|
278
|
## Recommended Next Notes
|
|
|
279
|
|
|
|
280
|
The next helpful artifacts for the repository would be:
|
|
|
281
|
|
|
|
282
|
- a raw `TC66C` sample-capture note in `Payload Notes`
|
|
|
283
|
- a byte-offset map for `pac1`, `pac2`, and `pac3`
|
|
|
284
|
- an implementation checklist for exposing currently undocumented `TC66C` features in the UI
|