@@ -0,0 +1,47 @@ |
||
| 1 |
+# Project History |
|
| 2 |
+ |
|
| 3 |
+## Origin |
|
| 4 |
+ |
|
| 5 |
+This project started as a proof of concept for reverse engineering three Bluetooth-enabled USB meters sold under the Ruideng name: |
|
| 6 |
+ |
|
| 7 |
+- `UM25(C) V2.0` |
|
| 8 |
+- `UM34(C) V2.3` |
|
| 9 |
+- `TC-66C` |
|
| 10 |
+ |
|
| 11 |
+## Initial Goal |
|
| 12 |
+ |
|
| 13 |
+The original goal was to discover how these devices expose their data over Bluetooth and to build a working software prototype capable of reading and displaying that data. |
|
| 14 |
+ |
|
| 15 |
+## Progress Reached |
|
| 16 |
+ |
|
| 17 |
+The project progressed to the point where data could be obtained from the devices. |
|
| 18 |
+ |
|
| 19 |
+At that stage, active work stopped. |
|
| 20 |
+ |
|
| 21 |
+## Current Knowledge Gaps |
|
| 22 |
+ |
|
| 23 |
+At this point, the exact status of the reverse engineering effort is not fully known: |
|
| 24 |
+ |
|
| 25 |
+- it is not clear which payload fields were fully decoded |
|
| 26 |
+- it is not clear which payload fields remain unknown |
|
| 27 |
+- it is not clear how complete the protocol understanding is for each model |
|
| 28 |
+ |
|
| 29 |
+The project code itself is now the main surviving reference for what was achieved. |
|
| 30 |
+ |
|
| 31 |
+## Available Resources |
|
| 32 |
+ |
|
| 33 |
+The original external research resources are no longer available, except for what is already included in this repository. |
|
| 34 |
+ |
|
| 35 |
+Because of that, the project should treat the existing source code and notes as the baseline for rebuilding protocol knowledge. |
|
| 36 |
+ |
|
| 37 |
+## Current Direction |
|
| 38 |
+ |
|
| 39 |
+The next stage is not to restart reverse engineering from scratch, but to document what is already present in the codebase and collect newly discovered materials in a structured way. |
|
| 40 |
+ |
|
| 41 |
+That includes: |
|
| 42 |
+ |
|
| 43 |
+- manuals |
|
| 44 |
+- specifications |
|
| 45 |
+- payload observations |
|
| 46 |
+- protocol notes |
|
| 47 |
+- reverse engineering findings for each supported meter model |
|
@@ -0,0 +1,5 @@ |
||
| 1 |
+# Documentation |
|
| 2 |
+ |
|
| 3 |
+This folder contains project notes, platform decisions, and collected reverse engineering material. |
|
| 4 |
+ |
|
| 5 |
+It is intended to keep the repository root focused on the app itself while preserving project context in one dedicated place. |
|
@@ -0,0 +1,9 @@ |
||
| 1 |
+# Manuals |
|
| 2 |
+ |
|
| 3 |
+Place product manuals, user guides, or archived copies of vendor documentation here. |
|
| 4 |
+ |
|
| 5 |
+Recommended naming: |
|
| 6 |
+ |
|
| 7 |
+- include model name |
|
| 8 |
+- include version or revision when known |
|
| 9 |
+- include source and date when possible |
|
@@ -0,0 +1,19 @@ |
||
| 1 |
+# Payload Notes |
|
| 2 |
+ |
|
| 3 |
+Use this folder for protocol-level findings. |
|
| 4 |
+ |
|
| 5 |
+Examples: |
|
| 6 |
+ |
|
| 7 |
+- packet captures |
|
| 8 |
+- field maps |
|
| 9 |
+- command and response notes |
|
| 10 |
+- unknown byte ranges |
|
| 11 |
+- per-model payload differences |
|
| 12 |
+ |
|
| 13 |
+For each note, prefer recording: |
|
| 14 |
+ |
|
| 15 |
+- model |
|
| 16 |
+- firmware or hardware revision if known |
|
| 17 |
+- sample payload |
|
| 18 |
+- decoded meaning |
|
| 19 |
+- confidence level |
|
@@ -0,0 +1,19 @@ |
||
| 1 |
+# Research Resources |
|
| 2 |
+ |
|
| 3 |
+This folder is reserved for external and internal technical material gathered after the original proof-of-concept phase. |
|
| 4 |
+ |
|
| 5 |
+Use it to collect: |
|
| 6 |
+ |
|
| 7 |
+- manuals |
|
| 8 |
+- vendor specifications |
|
| 9 |
+- screenshots or extracts of device information |
|
| 10 |
+- protocol notes |
|
| 11 |
+- payload descriptions |
|
| 12 |
+- decoded and undecoded field mappings |
|
| 13 |
+- references to related external projects |
|
| 14 |
+ |
|
| 15 |
+Suggested rule: |
|
| 16 |
+ |
|
| 17 |
+- keep raw source material close to its origin |
|
| 18 |
+- keep interpretation notes in Markdown |
|
| 19 |
+- prefer small focused notes over large mixed documents |
|
@@ -0,0 +1,3 @@ |
||
| 1 |
+# Related Projects |
|
| 2 |
+ |
|
| 3 |
+This folder tracks external projects that may help reconstruct protocol knowledge or validate naming and decoding choices. |
|
@@ -0,0 +1,57 @@ |
||
| 1 |
+# floriandotorg/um24c |
|
| 2 |
+ |
|
| 3 |
+Repository: |
|
| 4 |
+ |
|
| 5 |
+- https://github.com/floriandotorg/um24c |
|
| 6 |
+ |
|
| 7 |
+## Why it matters |
|
| 8 |
+ |
|
| 9 |
+This appears to be a contemporary external project focused on the same family of Bluetooth USB power meters. |
|
| 10 |
+ |
|
| 11 |
+It is relevant because it covers: |
|
| 12 |
+ |
|
| 13 |
+- `UM24C` |
|
| 14 |
+- `UM25C` |
|
| 15 |
+- `UM34C` |
|
| 16 |
+ |
|
| 17 |
+These overlap substantially with the devices targeted by this project. |
|
| 18 |
+ |
|
| 19 |
+## Quick Notes |
|
| 20 |
+ |
|
| 21 |
+From a quick inspection, the project appears to be a web UI built around Web Bluetooth and live plotting. |
|
| 22 |
+ |
|
| 23 |
+Potentially useful areas: |
|
| 24 |
+ |
|
| 25 |
+- model naming conventions |
|
| 26 |
+- field naming choices |
|
| 27 |
+- unit scaling assumptions |
|
| 28 |
+- decoded status values |
|
| 29 |
+- command / payload interpretation hints |
|
| 30 |
+- UI ideas for live data presentation |
|
| 31 |
+ |
|
| 32 |
+## Observations From Initial Review |
|
| 33 |
+ |
|
| 34 |
+- The repository describes itself as a web UI for `UM24C/UM25C/UM34C` power meters. |
|
| 35 |
+- It uses a JavaScript frontend rather than native iOS code. |
|
| 36 |
+- It includes explicit model mappings such as: |
|
| 37 |
+ - `0x0963 -> UM24C` |
|
| 38 |
+ - `0x09c9 -> UM25C` |
|
| 39 |
+ - `0x0d4c -> UM34C` |
|
| 40 |
+- It also includes a charging mode map with values such as `QC2`, `QC3`, `DCP1.5A`, and `SAMSUNG`. |
|
| 41 |
+ |
|
| 42 |
+## Limits |
|
| 43 |
+ |
|
| 44 |
+- It does not appear to target `TC-66C`. |
|
| 45 |
+- It should be treated as a secondary reference, not as ground truth. |
|
| 46 |
+- Any payload interpretation borrowed from it should be validated against our own code and captures. |
|
| 47 |
+ |
|
| 48 |
+## Suggested Use |
|
| 49 |
+ |
|
| 50 |
+Use this project mainly for: |
|
| 51 |
+ |
|
| 52 |
+- terminology alignment |
|
| 53 |
+- comparison of decoded fields |
|
| 54 |
+- cross-checking known model identifiers |
|
| 55 |
+- identifying gaps in our current understanding |
|
| 56 |
+ |
|
| 57 |
+Avoid assuming protocol equivalence without validation. |
|
@@ -0,0 +1,10 @@ |
||
| 1 |
+# Specifications |
|
| 2 |
+ |
|
| 3 |
+Place technical specifications, hardware notes, BLE service descriptions, and device capability summaries here. |
|
| 4 |
+ |
|
| 5 |
+Useful content for this folder: |
|
| 6 |
+ |
|
| 7 |
+- radio module details |
|
| 8 |
+- service and characteristic UUID notes |
|
| 9 |
+- device version comparisons |
|
| 10 |
+- hardware revisions |
|
@@ -1,11 +0,0 @@ |
||
| 1 |
-{\rtf1\ansi\ansicpg1252\cocoartf2511
|
|
| 2 |
-\cocoatextscaling0\cocoaplatform0{\fonttbl\f0\froman\fcharset0 Times-Roman;\f1\fswiss\fcharset0 ArialMT;}
|
|
| 3 |
-{\colortbl;\red255\green255\blue255;}
|
|
| 4 |
-{\*\expandedcolortbl;;}
|
|
| 5 |
-\paperw12240\paperh15840\margl1440\margr1440\vieww9000\viewh8400\viewkind0 |
|
| 6 |
-\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\partightenfactor0 |
|
| 7 |
- |
|
| 8 |
-\f0\fs24 \cf0 Documenting code\ |
|
| 9 |
- {\field{\*\fldinst{HYPERLINK "https://sarunw.com/posts/swift-documentation/"}}{\fldrslt https://sarunw.com/posts/swift-documentation/}}\
|
|
| 10 |
-{\field{\*\fldinst{HYPERLINK "https://developer.apple.com/library/content/documentation/Xcode/Reference/xcode_markup_formatting_ref/Links.html#//apple_ref/doc/uid/TP40016497-CH18-SW1"}}{\fldrslt
|
|
| 11 |
-\f1\fs30 https://developer.apple.com/library/content/documentation/Xcode/Reference/xcode_markup_formatting_ref/Links.html#//apple_ref/doc/uid/TP40016497-CH18-SW1}}} |
|
@@ -21,7 +21,6 @@ |
||
| 21 | 21 |
43567FE92443AD7C00000282 /* ICloudDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = 43567FE82443AD7C00000282 /* ICloudDefault.swift */; };
|
| 22 | 22 |
4360A34D241CBB3800B464F9 /* RSSIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4360A34C241CBB3800B464F9 /* RSSIView.swift */; };
|
| 23 | 23 |
4360A34F241D5CF100B464F9 /* MeterSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4360A34E241D5CF100B464F9 /* MeterSettingsView.swift */; };
|
| 24 |
- 437AEE1524249AAA0025C373 /* Readme.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 437AEE1424249AAA0025C373 /* Readme.rtf */; };
|
|
| 25 | 24 |
437D47D12415F91B00B7768E /* LiveView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437D47D02415F91B00B7768E /* LiveView.swift */; };
|
| 26 | 25 |
437D47D32415FB7E00B7768E /* Decimal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437D47D22415FB7E00B7768E /* Decimal.swift */; };
|
| 27 | 26 |
437D47D52415FD8C00B7768E /* RecordingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 437D47D42415FD8C00B7768E /* RecordingView.swift */; };
|
@@ -53,7 +52,13 @@ |
||
| 53 | 52 |
/* End PBXBuildFile section */ |
| 54 | 53 |
|
| 55 | 54 |
/* Begin PBXFileReference section */ |
| 55 |
+ 1C6B6B942A2D4F5100A0B001 /* Documentation README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
|
| 56 | 56 |
1C6B6B8A2A2D4F5100A0B001 /* Platform Decision - iOS 15.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "Platform Decision - iOS 15.md"; sourceTree = "<group>"; };
|
| 57 |
+ 1C6B6B8B2A2D4F5100A0B001 /* Project History.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = "Project History.md"; sourceTree = "<group>"; };
|
|
| 58 |
+ 1C6B6B8D2A2D4F5100A0B001 /* Research Resources README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
|
| 59 |
+ 1C6B6B8F2A2D4F5100A0B001 /* Manuals README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
|
| 60 |
+ 1C6B6B912A2D4F5100A0B001 /* Specifications README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
|
| 61 |
+ 1C6B6B932A2D4F5100A0B001 /* Payload Notes README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
|
| 57 | 62 |
4308CF8524176CAB0002E80B /* DataGroupRowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataGroupRowView.swift; sourceTree = "<group>"; };
|
| 58 | 63 |
4308CF872417770D0002E80B /* DataGroupsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataGroupsView.swift; sourceTree = "<group>"; };
|
| 59 | 64 |
430CB4FB245E07EB006525C2 /* ChevronView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChevronView.swift; sourceTree = "<group>"; };
|
@@ -67,7 +72,6 @@ |
||
| 67 | 72 |
43567FE82443AD7C00000282 /* ICloudDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ICloudDefault.swift; sourceTree = "<group>"; };
|
| 68 | 73 |
4360A34C241CBB3800B464F9 /* RSSIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RSSIView.swift; sourceTree = "<group>"; };
|
| 69 | 74 |
4360A34E241D5CF100B464F9 /* MeterSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MeterSettingsView.swift; sourceTree = "<group>"; };
|
| 70 |
- 437AEE1424249AAA0025C373 /* Readme.rtf */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; path = Readme.rtf; sourceTree = "<group>"; };
|
|
| 71 | 75 |
437D47D02415F91B00B7768E /* LiveView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveView.swift; sourceTree = "<group>"; };
|
| 72 | 76 |
437D47D22415FB7E00B7768E /* Decimal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Decimal.swift; sourceTree = "<group>"; };
|
| 73 | 77 |
437D47D42415FD8C00B7768E /* RecordingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingView.swift; sourceTree = "<group>"; };
|
@@ -113,6 +117,52 @@ |
||
| 113 | 117 |
/* End PBXFrameworksBuildPhase section */ |
| 114 | 118 |
|
| 115 | 119 |
/* Begin PBXGroup section */ |
| 120 |
+ 1C6B6B952A2D4F5100A0B001 /* Documentation */ = {
|
|
| 121 |
+ isa = PBXGroup; |
|
| 122 |
+ children = ( |
|
| 123 |
+ 1C6B6B942A2D4F5100A0B001 /* Documentation README.md */, |
|
| 124 |
+ 1C6B6B8A2A2D4F5100A0B001 /* Platform Decision - iOS 15.md */, |
|
| 125 |
+ 1C6B6B8B2A2D4F5100A0B001 /* Project History.md */, |
|
| 126 |
+ 1C6B6B8C2A2D4F5100A0B001 /* Research Resources */, |
|
| 127 |
+ ); |
|
| 128 |
+ path = Documentation; |
|
| 129 |
+ sourceTree = "<group>"; |
|
| 130 |
+ }; |
|
| 131 |
+ 1C6B6B8C2A2D4F5100A0B001 /* Research Resources */ = {
|
|
| 132 |
+ isa = PBXGroup; |
|
| 133 |
+ children = ( |
|
| 134 |
+ 1C6B6B8D2A2D4F5100A0B001 /* Research Resources README.md */, |
|
| 135 |
+ 1C6B6B8E2A2D4F5100A0B001 /* Manuals */, |
|
| 136 |
+ 1C6B6B902A2D4F5100A0B001 /* Specifications */, |
|
| 137 |
+ 1C6B6B922A2D4F5100A0B001 /* Payload Notes */, |
|
| 138 |
+ ); |
|
| 139 |
+ path = "Research Resources"; |
|
| 140 |
+ sourceTree = "<group>"; |
|
| 141 |
+ }; |
|
| 142 |
+ 1C6B6B8E2A2D4F5100A0B001 /* Manuals */ = {
|
|
| 143 |
+ isa = PBXGroup; |
|
| 144 |
+ children = ( |
|
| 145 |
+ 1C6B6B8F2A2D4F5100A0B001 /* Manuals README.md */, |
|
| 146 |
+ ); |
|
| 147 |
+ path = Manuals; |
|
| 148 |
+ sourceTree = "<group>"; |
|
| 149 |
+ }; |
|
| 150 |
+ 1C6B6B902A2D4F5100A0B001 /* Specifications */ = {
|
|
| 151 |
+ isa = PBXGroup; |
|
| 152 |
+ children = ( |
|
| 153 |
+ 1C6B6B912A2D4F5100A0B001 /* Specifications README.md */, |
|
| 154 |
+ ); |
|
| 155 |
+ path = Specifications; |
|
| 156 |
+ sourceTree = "<group>"; |
|
| 157 |
+ }; |
|
| 158 |
+ 1C6B6B922A2D4F5100A0B001 /* Payload Notes */ = {
|
|
| 159 |
+ isa = PBXGroup; |
|
| 160 |
+ children = ( |
|
| 161 |
+ 1C6B6B932A2D4F5100A0B001 /* Payload Notes README.md */, |
|
| 162 |
+ ); |
|
| 163 |
+ path = "Payload Notes"; |
|
| 164 |
+ sourceTree = "<group>"; |
|
| 165 |
+ }; |
|
| 116 | 166 |
4308CF89241777130002E80B /* Data Groups */ = {
|
| 117 | 167 |
isa = PBXGroup; |
| 118 | 168 |
children = ( |
@@ -183,8 +233,7 @@ |
||
| 183 | 233 |
43CBF653240BF3EB00255B8B = {
|
| 184 | 234 |
isa = PBXGroup; |
| 185 | 235 |
children = ( |
| 186 |
- 1C6B6B8A2A2D4F5100A0B001 /* Platform Decision - iOS 15.md */, |
|
| 187 |
- 437AEE1424249AAA0025C373 /* Readme.rtf */, |
|
| 236 |
+ 1C6B6B952A2D4F5100A0B001 /* Documentation */, |
|
| 188 | 237 |
43CBF65E240BF3EB00255B8B /* USB Meter */, |
| 189 | 238 |
43CBF65D240BF3EB00255B8B /* Products */, |
| 190 | 239 |
4347F01B28D717C1007EE7B1 /* Frameworks */, |
@@ -335,7 +384,6 @@ |
||
| 335 | 384 |
files = ( |
| 336 | 385 |
43CBF66F240BF3ED00255B8B /* LaunchScreen.storyboard in Resources */, |
| 337 | 386 |
43CBF66C240BF3ED00255B8B /* Preview Assets.xcassets in Resources */, |
| 338 |
- 437AEE1524249AAA0025C373 /* Readme.rtf in Resources */, |
|
| 339 | 387 |
43CBF669240BF3ED00255B8B /* Assets.xcassets in Resources */, |
| 340 | 388 |
); |
| 341 | 389 |
runOnlyForDeploymentPostprocessing = 0; |