fizzctl 0.2.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: fizzctl
3
- Version: 0.2.0
3
+ Version: 0.3.0
4
4
  Summary: Control a Redragon K617 Fizz keyboard on Linux: solid colors, 22 firmware-native RGB effects, per-key painting, live animations, and Cfg.ini keymap restore — no vendor software required
5
5
  Keywords: redragon,k617,fizz,rgb,keyboard,backlight,led,hid,linux
6
6
  Author: Ayoub Dya
@@ -14,7 +14,6 @@ Classifier: Programming Language :: Python :: 3
14
14
  Classifier: Programming Language :: Python :: 3.14
15
15
  Classifier: Topic :: System :: Hardware :: Hardware Drivers
16
16
  Classifier: Topic :: System :: Hardware
17
- Requires-Dist: dpkt>=1.9.8
18
17
  Requires-Dist: hidapi>=0.15.0
19
18
  Requires-Python: >=3.14
20
19
  Description-Content-Type: text/markdown
@@ -60,6 +59,8 @@ the trigger did not pick it up.
60
59
  | `key` | Paint a single key | yes |
61
60
  | `paint` | Paint multiple keys at once | yes |
62
61
  | `keymap` | Write the keymap from a Cfg.ini | yes |
62
+ | `macro` | Bind a key that types text on press | yes |
63
+ | `restore` | Reset to the factory keymap, lighting and macros | yes |
63
64
  | `animate` | Host-streamed animation (volatile) | no |
64
65
 
65
66
  ## Examples
@@ -81,6 +82,35 @@ Apply the full keymap (bindings, lighting zones, function keys) from a
81
82
  fizzctl keymap Cfg.ini
82
83
  ```
83
84
 
85
+ - A `keymap` write keeps your current effect/color/brightness and any macros
86
+ you have bound.
87
+ - `fizzctl restore` does the opposite: it resets the keyboard to factory
88
+ state by writing the packaged stock keymap and lighting and wiping every
89
+ macro.
90
+
91
+ ### Macros
92
+
93
+ Bind a key to a macro that types text. Each macro gets its own slot (up to
94
+ 8), and previously bound macros are kept — the device's current keymap is
95
+ read and reused as the base, and your lighting is untouched:
96
+
97
+ ```bash
98
+ fizzctl macro --key CapsLock rgb # type "rgb" each press
99
+ fizzctl macro --key LAlt --delay-ms 50 --cycles 3 hello
100
+ fizzctl macro --key 2 --until-released aaaa
101
+ ```
102
+
103
+ Options: `--delay-ms` (default 30) is the delay between typed events,
104
+ `--cycles` (default 1) plays the macro that many times per press, and
105
+ `--until-released` types in a loop until the key is let go. Macros and their
106
+ bindings are remembered in a local state file (`$XDG_STATE_HOME/fizzctl/`)
107
+ so later macro/keymap writes never drop them. To undo:
108
+
109
+ ```bash
110
+ fizzctl macro --remove-all # unbind every macro, keep keymap + lighting
111
+ fizzctl restore # full factory reset (keymap, lighting, macros)
112
+ ```
113
+
84
114
  ### Set the whole board to one color
85
115
 
86
116
  ```bash
@@ -91,9 +121,9 @@ fizzctl rgb 00ff00 --brightness 4 # or: rgb 00ff00 -b 4
91
121
  ### Firmware effects
92
122
 
93
123
  All 22 effects from the official Redragon software are supported, with full
94
- speed and brightness control. `speed` and `brightness` are 5 levels (0-4,
95
- matching the firmware); higher = faster / brighter. Run `fizzctl effect`
96
- with no name to list every effect:
124
+ speed and brightness control. `speed` is 1..5 and `brightness` is 0..4 (5
125
+ levels each, matching the firmware); higher = faster / brighter. Run
126
+ `fizzctl effect` with no name to list every effect:
97
127
 
98
128
  ```bash
99
129
  fizzctl effect
@@ -153,11 +183,11 @@ fizzctl-dev list
153
183
 
154
184
  ## How the RGB paths work
155
185
 
156
- **Flash writes** (`rgb`, `key`, `paint`, `effect`, `keymap`) send a 4-5 frame
157
- burst through the vendor HID interface (`258a:0049`, interface 1, usage page
158
- `0xFF00`). The sequence ends with a `5AA5` magic commit that writes to flash.
159
- Colors persist across reboots. Keys not listed in a `key` or `paint` canvas
160
- turn off.
186
+ **Flash writes** (`rgb`, `key`, `paint`, `effect`, `keymap`, `macro`,
187
+ `restore`) send a burst through the vendor HID interface (`258a:0049`,
188
+ interface 1, usage page `0xFF00`). The sequence ends with a `5AA5` magic
189
+ commit that writes to flash. Colors persist across reboots. Keys not listed
190
+ in a `key` or `paint` canvas turn off.
161
191
 
162
192
  **Animations** (`animate`) stream 382-byte per-key reports at the requested
163
193
  frame rate with no flash commit. They are host-side only and lost on
@@ -39,6 +39,8 @@ the trigger did not pick it up.
39
39
  | `key` | Paint a single key | yes |
40
40
  | `paint` | Paint multiple keys at once | yes |
41
41
  | `keymap` | Write the keymap from a Cfg.ini | yes |
42
+ | `macro` | Bind a key that types text on press | yes |
43
+ | `restore` | Reset to the factory keymap, lighting and macros | yes |
42
44
  | `animate` | Host-streamed animation (volatile) | no |
43
45
 
44
46
  ## Examples
@@ -60,6 +62,35 @@ Apply the full keymap (bindings, lighting zones, function keys) from a
60
62
  fizzctl keymap Cfg.ini
61
63
  ```
62
64
 
65
+ - A `keymap` write keeps your current effect/color/brightness and any macros
66
+ you have bound.
67
+ - `fizzctl restore` does the opposite: it resets the keyboard to factory
68
+ state by writing the packaged stock keymap and lighting and wiping every
69
+ macro.
70
+
71
+ ### Macros
72
+
73
+ Bind a key to a macro that types text. Each macro gets its own slot (up to
74
+ 8), and previously bound macros are kept — the device's current keymap is
75
+ read and reused as the base, and your lighting is untouched:
76
+
77
+ ```bash
78
+ fizzctl macro --key CapsLock rgb # type "rgb" each press
79
+ fizzctl macro --key LAlt --delay-ms 50 --cycles 3 hello
80
+ fizzctl macro --key 2 --until-released aaaa
81
+ ```
82
+
83
+ Options: `--delay-ms` (default 30) is the delay between typed events,
84
+ `--cycles` (default 1) plays the macro that many times per press, and
85
+ `--until-released` types in a loop until the key is let go. Macros and their
86
+ bindings are remembered in a local state file (`$XDG_STATE_HOME/fizzctl/`)
87
+ so later macro/keymap writes never drop them. To undo:
88
+
89
+ ```bash
90
+ fizzctl macro --remove-all # unbind every macro, keep keymap + lighting
91
+ fizzctl restore # full factory reset (keymap, lighting, macros)
92
+ ```
93
+
63
94
  ### Set the whole board to one color
64
95
 
65
96
  ```bash
@@ -70,9 +101,9 @@ fizzctl rgb 00ff00 --brightness 4 # or: rgb 00ff00 -b 4
70
101
  ### Firmware effects
71
102
 
72
103
  All 22 effects from the official Redragon software are supported, with full
73
- speed and brightness control. `speed` and `brightness` are 5 levels (0-4,
74
- matching the firmware); higher = faster / brighter. Run `fizzctl effect`
75
- with no name to list every effect:
104
+ speed and brightness control. `speed` is 1..5 and `brightness` is 0..4 (5
105
+ levels each, matching the firmware); higher = faster / brighter. Run
106
+ `fizzctl effect` with no name to list every effect:
76
107
 
77
108
  ```bash
78
109
  fizzctl effect
@@ -132,11 +163,11 @@ fizzctl-dev list
132
163
 
133
164
  ## How the RGB paths work
134
165
 
135
- **Flash writes** (`rgb`, `key`, `paint`, `effect`, `keymap`) send a 4-5 frame
136
- burst through the vendor HID interface (`258a:0049`, interface 1, usage page
137
- `0xFF00`). The sequence ends with a `5AA5` magic commit that writes to flash.
138
- Colors persist across reboots. Keys not listed in a `key` or `paint` canvas
139
- turn off.
166
+ **Flash writes** (`rgb`, `key`, `paint`, `effect`, `keymap`, `macro`,
167
+ `restore`) send a burst through the vendor HID interface (`258a:0049`,
168
+ interface 1, usage page `0xFF00`). The sequence ends with a `5AA5` magic
169
+ commit that writes to flash. Colors persist across reboots. Keys not listed
170
+ in a `key` or `paint` canvas turn off.
140
171
 
141
172
  **Animations** (`animate`) stream 382-byte per-key reports at the requested
142
173
  frame rate with no flash commit. They are host-side only and lost on
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fizzctl"
3
- version = "0.2.0"
3
+ version = "0.3.0"
4
4
  description = "Control a Redragon K617 Fizz keyboard on Linux: solid colors, 22 firmware-native RGB effects, per-key painting, live animations, and Cfg.ini keymap restore — no vendor software required"
5
5
  readme = "README.md"
6
6
  keywords = [
@@ -25,10 +25,7 @@ classifiers = [
25
25
  "Topic :: System :: Hardware",
26
26
  ]
27
27
  requires-python = ">=3.14"
28
- dependencies = [
29
- "dpkt>=1.9.8",
30
- "hidapi>=0.15.0",
31
- ]
28
+ dependencies = ["hidapi>=0.15.0"]
32
29
 
33
30
  [project.license]
34
31
  text = "MIT"
@@ -0,0 +1,41 @@
1
+ [project]
2
+ name = "fizzctl"
3
+ version = "0.3.0"
4
+ description = "Control a Redragon K617 Fizz keyboard on Linux: solid colors, 22 firmware-native RGB effects, per-key painting, live animations, and Cfg.ini keymap restore — no vendor software required"
5
+ readme = "README.md"
6
+ license = { text = "MIT" }
7
+ authors = [{ name = "Ayoub Dya", email = "ayoubdya@gmail.com" }]
8
+ keywords = [
9
+ "redragon",
10
+ "k617",
11
+ "fizz",
12
+ "rgb",
13
+ "keyboard",
14
+ "backlight",
15
+ "led",
16
+ "hid",
17
+ "linux",
18
+ ]
19
+ classifiers = [
20
+ "Development Status :: 4 - Beta",
21
+ "Environment :: Console",
22
+ "Intended Audience :: End Users/Desktop",
23
+ "Operating System :: POSIX :: Linux",
24
+ "Programming Language :: Python :: 3",
25
+ "Programming Language :: Python :: 3.14",
26
+ "Topic :: System :: Hardware :: Hardware Drivers",
27
+ "Topic :: System :: Hardware",
28
+ ]
29
+ requires-python = ">=3.14"
30
+ dependencies = ["hidapi>=0.15.0"]
31
+
32
+ [project.scripts]
33
+ fizzctl = "fizzctl:main"
34
+ fizzctl-dev = "fizzctl:main_dev"
35
+
36
+ [build-system]
37
+ requires = ["uv_build>=0.12.13,<0.13.0"]
38
+ build-backend = "uv_build"
39
+
40
+ [tool.uv]
41
+ package = true
@@ -7,4 +7,4 @@ by :func:`main_dev` via the ``fizzctl-dev`` console script.
7
7
  from .cli import main, main_dev
8
8
 
9
9
  __all__ = ["main", "main_dev"]
10
- __version__ = "0.2.0"
10
+ __version__ = "0.3.0"
@@ -1,11 +1,25 @@
1
1
  """Baked firmware bytes, inlined as hex so the package ships no binary files.
2
2
 
3
3
  All constants come from USB captures of the OEM software:
4
- * CONST_MODE / CONST_CANVAS / CONST_ROUTING / CONST_EXEC — the
4
+ * CONST_MODE / CONST_CANVAS / CONST_ROUTING / CONST_EXEC — the
5
5
  four constant 1032-byte frames of the Restore sequence.
6
- * FW_FRAMES — the 5-frame static-effect template used for RGB writes.
6
+ * FW_TEMPLATE — the 5-frame effect template: shared MODE and ROUTING,
7
+ a distinct CANVAS, and five byte overrides of CONST_EXEC.
8
+ * RGB_EXEC / RGB_SEC — the whole-board solid-color variant.
9
+ * CONST_KEYMAP — a clean 1032-byte 06 04 d4 keymap block (no macro
10
+ bindings), captured from the device. The macro command uses it as the
11
+ default base; KeymapEncoder can rebuild the same block from a Cfg.ini.
7
12
  """
8
13
 
14
+
15
+ def _patch(base: bytes, diffs: dict[int, int]) -> bytes:
16
+ """Copy `base`, overriding a handful of byte offsets."""
17
+ b = bytearray(base)
18
+ for off, val in diffs.items():
19
+ b[off] = val
20
+ return bytes(b)
21
+
22
+
9
23
  CONST_MODE = bytes.fromhex(
10
24
  "0608b80040000000000000000000000000000000000000000000000000ff0000"
11
25
  "0000ff00ff00ffff00ff00ff00ffffffffffff00000000ff00ff00ffff00ff00"
@@ -150,49 +164,9 @@ CONST_EXEC = bytes.fromhex(
150
164
  "0000000000000000"
151
165
  )
152
166
 
153
- FW_FRAMES = [
154
- # frame 0: 6B
155
- bytes.fromhex(
156
- "0583b6000000"
157
- ),
158
- # frame 1: 1032B
159
- bytes.fromhex(
160
- "0608b80040000000000000000000000000000000000000000000000000ff0000"
161
- "0000ff00ff00ffff00ff00ff00ffffffffffff00000000ff00ff00ffff00ff00"
162
- "ff00ffffffffffff00000000ff00ff00ffff00ff00ff00ffffffffffff000000"
163
- "00ff00ff00ffff00ff00ff00ffffffffffff00000000ff00ff00ffff00ff00ff"
164
- "00ffffffffffff00000000ff00ff00ffff00ff00ff00ffffffffffff00000000"
165
- "ff00ff00ffff00ff00ff00ffffffffffff00000000ff00ff00ffff00ff00ff00"
166
- "ffffffffffff00000000ff00ff00ffff00ff00ff00ffffffffffff00000000ff"
167
- "00ff00ffff00ff00ff00ffffffffffff00000000ff00ff00ffff00ff00ff00ff"
168
- "ffffffffff00000000ff00ff00ffff00ff00ff00ffffffffffff00000000ff00"
169
- "ff00ffff00ff00ff00ffffffffffff00000000ff00ff00ffff00ff00ff00ffff"
170
- "ffffffff00000000ff00ff00ffff00ff00ff00ffffffffffff00000000ff00ff"
171
- "00ffff00ff00ff00ffffffffffff00000000ff00ff00ffff00ff00ff00ffffff"
172
- "ffffff00000000ff00ff00ffff00ff00ff00ffffffffffff00000000ff00ff00"
173
- "ffff00ff00ff00ffffffffffff00000000ff00ff00ffff00ff00ff00ffffffff"
174
- "ffff00000000ff00ff00ffff00ff00ff00ffffffffffff00000000ff00ff00ff"
175
- "ff00ff00ff00ffffffffff000000000000000000000000000000000000000000"
176
- "0000000000000000000000000000000000000000000000000000000000000000"
177
- "0000000000000000000000000000000000000000000000000000000000000000"
178
- "0000000000000000000000000000000000000000000000000000000000000000"
179
- "0000000000000000000000000000000000000000000000000000000000000000"
180
- "0000000000000000000000000000000000000000000000000000000000000000"
181
- "0000000000000000000000000000000000000000000000000000000000000000"
182
- "0000000000000000000000000000000000000000000000000000000000000000"
183
- "0000000000000000000000000000000000000000000000000000000000000000"
184
- "0000000000000000000000000000000000000000000000000000000000000000"
185
- "0000000000000000000000000000000000000000000000000000000000000000"
186
- "0000000000000000000000000000000000000000000000000000000000000000"
187
- "0000000000000000000000000000000000000000000000000000000000000000"
188
- "0000000000000000000000000000000000000000000000000000000000000000"
189
- "0000000000000000000000000000000000000000000000000000000000000000"
190
- "0000000000000000000000000000000000000000000000000000000000000000"
191
- "0000000000000000000000000000000000000000000000000000000000000000"
192
- "0000000000000000"
193
- ),
194
- # frame 2: 1032B
195
- bytes.fromhex(
167
+ INIT = bytes.fromhex("0583b6000000")
168
+
169
+ FW_CANVAS = bytes.fromhex(
196
170
  "0609bc0040000000000000000000000000000000000000000000000000000000"
197
171
  "00000000000000000000000000000000000000ff00ff00ff0000000000000000"
198
172
  "0000000000000000ffffff00ff0000000000000000000000000000000000ff00"
@@ -226,89 +200,54 @@ FW_FRAMES = [
226
200
  "0000000000000000000000000000000000000000000000000000000000000000"
227
201
  "0000000000000000000000000000000000000000000000000000000000000000"
228
202
  "0000000000000000"
229
- ),
230
- # frame 3: 1032B
231
- bytes.fromhex(
232
- "0609c00040000000000000000000ffffffffffffff0000000000000000000000"
233
- "000000ffffffffff00000000000000000000000000000000ffffffffff000000"
234
- "000000000000000000000000ff000000ffff0000000000000000000000000000"
235
- "00ff000000000000000000000000000000000000000000000000000000000000"
236
- "0000000000000000000000000000000000000000000000000000000000000000"
237
- "0000000000000000000000000000000000000000000000000000000000000000"
238
- "0000000000000000000000000000000000000000000000000000000000000000"
239
- "0000000000000000000000000000000000000000000000000000000000000000"
240
- "0000000000000000000000000000000000000000000000000000000000000000"
241
- "0000000000000000000000000000000000000000000000000000000000000000"
242
- "0000000000000000000000000000000000000000000000000000000000000000"
243
- "0000000000000000000000000000000000000000000000000000000000000000"
244
- "0000000000000000ffffffffffffff0000000000000000000000000000ffffff"
245
- "ff0000000000000000000000000000000000ffffffff00000000000000000000"
246
- "0000000000000000000000000000000000000000000000000000000000000000"
247
- "0000000000000000000000000000000000000000000000000000000000000000"
248
- "0000000000000000000000000000000000000000000000000000000000000000"
249
- "0000000000000000000000000000000000000000000000000000000000000000"
250
- "0000000000000000000000000000000000000000000000000000000000000000"
251
- "0000000000000000000000000000000000000000000000000000000000000000"
252
- "0000000000000000000000000000000000000000000000000000000000000000"
253
- "0000000000000000000000000000000000000000000000000000000000000000"
254
- "0000000000000000000000000000000000000000000000000000000000000000"
255
- "0000000000000000000000000000000000000000000000000000000000000000"
256
- "000000000000000000000000000000000000000000000000ff00ff0000000000"
257
- "000000000000000000000000ffffff0000000000000000000000000000000000"
258
- "ff0000000000000000000000000000000000000000ff00ff0000000000000000"
259
- "0000000000000000000000000000000000000000000000000000000000000000"
260
- "0000000000000000000000000000000000000000000000000000000000000000"
261
- "0000000000000000000000000000000000000000000000000000000000000000"
262
- "0000000000000000000000000000000000000000000000000000000000000000"
263
- "0000000000000000000000000000000000000000000000000000000000000000"
264
- "0000000000000000"
265
- ),
266
- # frame 4: 1032B
267
- bytes.fromhex(
268
- "0603b600000000000000000000005aa503030000000120010000000055550100"
269
- "00000000ffff0034073307330733073307330733073307330733073307330733"
270
- "07330733073307330733073307335aa500100744074407440744074407440744"
271
- "0404040404040404040400000000000000000000000000000000000000000000"
272
- "0000000000000000005aa5030300000000000000000000000000000000000000"
273
- "0000000000000000000000000000000000000000000000000000000000000000"
274
- "0000000000000000000000000000000000000000000000000000000000000000"
275
- "0000000000000000000000000000000000000000000000000000000000000000"
276
- "0000000000000000000000000000000000000000000000000000000000000000"
277
- "0000000000000000000000000000000000000000000000000000000000000000"
278
- "0000000000000000000000000000000000000000000000000000000000000000"
279
- "0000000000000000000000000000000000000000000000000000000000000000"
280
- "0000000000000000000000000000000000000000000000000000000000000000"
281
- "0000000000000000000000000000000000000000000000000000000000000000"
282
- "0000000000000000000000000000000000000000000000000000000000000000"
283
- "0000000000000000000000000000000000000000000000000000000000000000"
284
- "0000000000000000000000000000000000000000000000000000000000000000"
285
- "0000000000000000000000000000000000000000000000000000000000000000"
286
- "0000000000000000000000000000000000000000000000000000000000000000"
287
- "0000000000000000000000000000000000000000000000000000000000000000"
288
- "0000000000000000000000000000000000000000000000000000000000000000"
203
+ )
204
+
205
+ EXEC_DIFFS = {18: 0, 21: 1, 38: 0, 39: 52, 141: 0}
206
+
207
+ FW_TEMPLATE = [
208
+ INIT,
209
+ CONST_MODE,
210
+ FW_CANVAS,
211
+ CONST_ROUTING,
212
+ _patch(CONST_EXEC, EXEC_DIFFS),
213
+ ]
214
+
215
+ CONST_KEYMAP = bytes.fromhex(
216
+ "0604d4004000000000000000020000000200000d02000014060000e1060000e0"
217
+ "00000000020000010200000e020000150000001d0200001e0000000002000002"
218
+ "0200000f020000160000001b0200001f00000000020000030200001002000017"
219
+ "0000000600000000000000000200000400000015000000090000001900000000"
220
+ "0000000002000005000000170000000a00000005020000200000000002000006"
221
+ "0000001c0000000b00000011000000000000000002000007000000180000000d"
222
+ "0200001a0000000000000000020000080000000c0000000e0200001b20000000"
223
+ "0000000002000009000000120000000f0200001c00000050000000000200000a"
224
+ "02000011020000180200001d00000000000000000200000b0200001202000019"
225
+ "0000000000000000000000000200000c02000013000000000000000000000051"
226
+ "000000000000002a0000003100000028000000520000004f0000000000000000"
289
227
  "0000000000000000000000000000000000000000000000000000000000000000"
290
228
  "0000000000000000000000000000000000000000000000000000000000000000"
291
229
  "0000000000000000000000000000000000000000000000000000000000000000"
292
230
  "0000000000000000000000000000000000000000000000000000000000000000"
293
231
  "0000000000000000000000000000000000000000000000000000000000000000"
232
+ "000000000000000000000000000000000000000000000000000000290000001e"
233
+ "0000001f00000020000000210000002200000023000000240000002500000026"
234
+ "000000270000002d0000002e0000002b000000140000001a0000000800000013"
235
+ "0000002f00000030000000390000000400000016000000070000003300000034"
236
+ "00000010000000360000003700000038060000e3060000e20000002c00000000"
294
237
  "0000000000000000000000000000000000000000000000000000000000000000"
238
+ "000000000000000000000000000000000000000000000000000000350000003a"
239
+ "0000003b0000003c0000003d0000003e0000003f000000400000004100000042"
240
+ "000000430000004400000045040000cd040000ea00000052040000e900000046"
241
+ "000000490000004c040000e200000050000000510000004f0000004a0000004d"
242
+ "0c0003000d0003000000004b0000004e0e0000010b0003000e00000700000000"
295
243
  "0000000000000000000000000000000000000000000000000000000000000000"
296
244
  "0000000000000000000000000000000000000000000000000000000000000000"
297
245
  "0000000000000000000000000000000000000000000000000000000000000000"
298
246
  "0000000000000000000000000000000000000000000000000000000000000000"
299
247
  "0000000000000000000000000000000000000000000000000000000000000000"
300
248
  "0000000000000000"
301
- ),
302
- ]
303
-
304
-
249
+ )
305
250
 
306
- # --- RGB static-color protocol ---
307
- RGB_INIT = bytes.fromhex("0583b6000000")
308
- # P1 canvas is BUILT (header + split-plane colors + SEC at 660), not taken from
309
- # a template. P2 routing is the same 06 09 c0 block used by the Restore
310
- # sequence (matches RESTORE_CONSTANT_FRAMES[2] exactly). EXEC must be the
311
- # static-color variant: effect_id=0x01, brightness=0x15.
312
251
  RGB_SEC = bytes.fromhex(
313
252
  "ffffffffff000000000000000000000000000000ffffffffff00000000000000"
314
253
  "00000000000000000000ffffff00ff000000000000000000000000000000ff00"
@@ -1,8 +1,7 @@
1
1
  """USB capture import/diff/export for the K617 OEM software.
2
2
 
3
- Inputs accepted:
3
+ Input accepted:
4
4
  * Wireshark JSON : `tshark -r cap.pcapng -T json > cap.json` (recommended)
5
- * raw .pcap : Linux usbmon capture, parsed with dpkt
6
5
 
7
6
  The job:
8
7
  1. pull every HID feature-report payload out of the USB stream,
@@ -147,24 +146,6 @@ def _parse_usb_layer(u: dict, setup: dict | None = None) -> FrameCapture | None:
147
146
  )
148
147
 
149
148
 
150
- def load_pcap_usbmon(path: str) -> list[FrameCapture]:
151
- """Minimal Linux usbmon .pcap reader (dpkt)."""
152
- import dpkt
153
-
154
- out: list[FrameCapture] = []
155
- with open(path, "rb") as fh:
156
- pcap = dpkt.pcap.Reader(fh)
157
- for _, buf in pcap:
158
- try:
159
- u = dpkt.usbmon.LinuxUSB(buf)
160
- except Exception:
161
- continue
162
- data = bytes(u.transfer_buffer) if u.xfer_type & 0x80 else None
163
- direction = "IN" if u.urb_type == 0x55 else "OUT"
164
- out.append(FrameCapture(direction=direction, transfer="urb", request=None, report_id=None, data=data or b""))
165
- return out
166
-
167
-
168
149
  def significant(records: list[FrameCapture], direction: str = "OUT") -> list[FrameCapture]:
169
150
  """Keep only payload-bearing writes from the host (the interesting direction)."""
170
151
  return [r for r in records if r.direction == direction and len(r.data) > 0]
@@ -104,15 +104,3 @@ class CfgIni:
104
104
  @property
105
105
  def key_entries(self) -> list[tuple[int, KeyEntry]]:
106
106
  return sorted(self.keys.items())
107
-
108
-
109
- if __name__ == "__main__":
110
- import sys
111
- cfg = CfgIni(sys.argv[1] if len(sys.argv) > 1 else "Cfg.ini")
112
- print(f"OPT: {len(cfg.opt)} keys")
113
- print(f"[FN] {len(cfg.fn)} mappings")
114
- for idx, be in cfg.fn_entries:
115
- print(f" K{idx:<3} = {', '.join(f'0x{b:02X}' for b in be)}")
116
- print(f"[KEY] {len(cfg.keys)} keys")
117
- for idx, e in cfg.key_entries:
118
- print(f" K{idx:<3} = {e.matrix} {', '.join(f'0x{b:02X}' for b in e.behavior)}")