Types & errors
The values the API takes and returns. Field meanings are on the Library types and Native API; raw HID ids (keycodes, button slots, Consumer usages) on Usage IDs.
Every enum subclasses enum.IntEnum. A member is its wire byte: int(Button.LEFT) == 0. Anywhere an enum is accepted, a bare int works too, for a raw HID id, endpoint number, or interface number with no named member.
Injection enums Button · Action
See the injection model for what each Action means; button slots on Usage IDs.
| Member | Value | Meaning |
|---|---|---|
SOFT_RELEASE | 0 | release unless held on the real device |
PRESS | 1 | hold down |
FORCE_RELEASE | 2 | release even against a hold on the real device |
Lock & blanket enums Direction · BearingMode · LockTargetKind · Blanket
See Lock for directions and blanket classes, and Catch for a direction on a traffic subscription.
Its meaning depends on what it is attached to: an axis, a usage, or a CatchFilter naming a byte-oriented catch class.
| Member | Value | Aliases | Axis or wheel | Button or key | Traffic-class filter |
|---|---|---|---|---|---|
BOTH | 0 | - | both signs; a scale sets the two fixed signs and passes WITH / AGAINST in full | press and release | both directions |
POSITIVE | 1 | PRESS · IN | +x / +y / wheel-up only | the press edge | IN, device to PC |
NEGATIVE | 2 | RELEASE · OUT | -x / -y / wheel-down only | the release edge | OUT, PC to device |
WITH | 3 | - | the sign the box is injecting | refused | no meaning |
AGAINST | 4 | - | the sign opposing it | refused | no meaning |
Aliases are the same values under call-site names: Direction.PRESS is Direction.POSITIVE. WITH and AGAINST are measured against the bearing, not a fixed sign; .is_relative tells them apart.
Only an axis has a bearing, so WITH or AGAINST on a lock of anything else raises RelativeDirectionError. A media usage has no edges: an edge named on one is sent as BOTH, and reads back that way in Locks.
How the box reads the direction it is injecting, which WITH and AGAINST are measured against. Set with dev.set_bearing(window_ms, mode).
| Member | Value | Meaning |
|---|---|---|
PER_AXIS | 0 | each axis compares its sign against its bearing, independently; the default |
VECTOR | 1 | the native delta is projected onto the injected direction. The relative scale weighs only the part along it, and one relative scale (the lower of X's and Y's) governs X and Y as one vector. The fixed-sign scales still apply to what is left on each axis |
Under VECTOR, Locks reports that one scale.
| Member | Value |
|---|---|
X | 0 |
Y | 1 |
WHEEL | 2 |
PAN | 3 |
USAGE | 4 |
Built by LockTarget.x/y/wheel/pan/usage (and the button/key/media shortcuts).
| Member | Value | Class | Direction |
|---|---|---|---|
AIM | 0 | the X and Y cursor axes | a sign, on each axis |
WHEEL | 1 | the wheel | a sign |
BUTTONS | 2 | every mouse button | an edge, on each button |
KEYS | 3 | every keyboard key and modifier | an edge: POSITIVE blocks presses, NEGATIVE releases, BOTH both |
MEDIA | 4 | every media usage | nothing; media has no edges |
These are ABI-local ordinals (matching the crate's Blanket order), not the clip auto-lock scope bits.
Keycode enums Key · MediaKey
Named subsets of the HID usage tables; full lists on Usage IDs (keys, media). Any call taking a Key or MediaKey also accepts a raw int usage.
| Members | Values |
|---|---|
A .. Z | 4 to 29 |
N1 .. N9, N0 | 30 to 39 |
ENTER ESCAPE BACKSPACE TAB SPACE | 40 to 44 |
CAPS_LOCK | 57 |
F1 .. F12 | 58 to 69 |
INSERT HOME PAGE_UP DELETE END PAGE_DOWN | 73 to 78 |
RIGHT LEFT DOWN UP (arrows) | 79 to 82 |
LEFT_CTRL LEFT_SHIFT LEFT_ALT LEFT_GUI | 224 to 227 |
RIGHT_CTRL RIGHT_SHIFT RIGHT_ALT RIGHT_GUI | 228 to 231 |
| Member | Value |
|---|---|
PLAY | 176 |
PAUSE | 177 |
NEXT_TRACK | 181 |
PREV_TRACK | 182 |
STOP | 183 |
PLAY_PAUSE | 205 |
MUTE | 226 |
VOLUME_UP | 233 |
VOLUME_DOWN | 234 |
LED & admin enums LedTarget · LedMode · RebootTarget
| Member | Value |
|---|---|
DEVICE | 0 |
HOST | 1 |
BOTH | 2 |
| Member | Value |
|---|---|
AUTO | 0 |
OFF | 1 |
SOLID | 2 |
BLINK | 3 |
| Member | Value |
|---|---|
DEVICE_DOWNLOAD | 0 |
HOST_DOWNLOAD | 1 |
DEVICE_RUN | 2 |
HOST_RUN | 3 |
Emit pace EmitMode · EmitPace
Passed to dev.set_emit_pace(). See Options.
| Member | Value |
|---|---|
LEARNED | 0 |
INTERVAL | 1 |
FIXED | 2 |
A frozen dataclass carrying mode and hz. Build it with EmitPace.learned(), EmitPace.interval(), or EmitPace.fixed(hz) (the rate snaps to 1000/n and caps at 1 kHz).
RenderRenderMode
Passed to dev.set_render(). See Options.
| Member | Value |
|---|---|
OFF | 0 |
STOCK | 1 |
DESPIKED | 2 |
UNSMOOTHED | 3 |
ClipClipState · Edge · ClipAction · ClipTrigger · ClipPacketTrigger · ClipSettings · ClipStatus
Buffered-clip types. See Clip.
| Member | Value | Meaning |
|---|---|---|
IDLE | 0 | No clip playing. |
PLAYING | 1 | Draining the ring, one entry per native frame. |
PAUSED | 2 | Halted mid-clip; the cursor and any held input are retained. |
FAULTED | 3 | An append was dropped or the ring overflowed; clear to recover. |
| Member | Value | Meaning |
|---|---|---|
DEVICE | 0 | The PC-facing chip, written directly over the control port. |
HOST | 1 | The chip that reads the real device, relayed over the inter-chip link. |
| Member | Value | Meaning |
|---|---|---|
NEW | 0 | Selected but not yet booted. |
PENDING_VERIFY | 1 | Booted and on probation (the rollback window). |
VALID | 2 | Confirmed by the image itself. |
INVALID | 3 | The image asked to be rolled back. |
ABORTED | 4 | Booted once and never confirmed. |
UNKNOWN | 0xFF | No entry for this slot. |
| Member | Value | Fires on |
|---|---|---|
BOTH | 0 | either edge of the trigger usage |
PRESS | 1 | the native press edge |
RELEASE | 2 | the native release edge |
Which edge of a ClipTrigger runs its action.
| Member | Value | Runs |
|---|---|---|
START | 0 | rewind and play |
STOP | 1 | stop and release |
PAUSE | 2 | halt mid-clip |
RESUME | 3 | continue from the pause |
RESTART | 4 | force a rewind and play |
TOGGLE | 5 | play if idle/paused, stop if playing |
The action a bound trigger of either kind runs on the box, matching the clip.start/stop/pause/resume/restart/toggle methods.
A dataclass binding a native usage's edge to a clip action, passed to clip.bind(). The box runs the action with no host round-trip.
| Field | Type | Meaning |
|---|---|---|
on | Usage | the trigger usage (button, key, or media) |
edge | Edge | which edge fires the action |
action | ClipAction | what the box runs |
consume | bool | suppress the native edge so it never reaches the game PC (default False) |
Construct it directly, e.g. ClipTrigger(Usage.button(Button.SIDE1), Edge.PRESS, ClipAction.TOGGLE, consume=True).
A dataclass binding a matched packet to a clip action, keyed by (traffic_class, id, direction, match_bytes, mask). Passed to clip.bind_packet() and read back by clip.query_config(). See Clip.
| Field | Type | Meaning |
|---|---|---|
traffic_class | TrafficClass | the surface the packet crosses: any member but BUS and CLIP_TRANSFER |
id | int | the interface number for HID_IN, the endpoint number for the rest, or ClipPacketTrigger.ANY_ID (0xFFFF) |
direction | Direction | IN, OUT or BOTH |
action | ClipAction | what the box runs, on the frame clock's next tick |
match_bytes, mask | bytes | the head compare, both one length and ≤PKT_MATCH_MAX. A packet matches when head[i] & mask[i] == match_bytes[i] for each byte. The default b"" matches every packet on the address |
consume | bool | drop every packet this trigger matches as the top-ranked trigger, before the rewrite table sees it. The box holds a consuming trigger only under allow_imperfect_clones, and on any class but CONTROL (default False) |
once_per_run | bool | run the action on the first packet of a run of matching packets; needs a class other than CONTROL, a concrete id, and IN or OUT (default False) |
selector_len | int | with once_per_run: how many leading match bytes pick the run's stream (a report ID, for example); the remaining bytes are the condition (default 0) |
hits | int | packets matched as the top-ranked trigger since the trigger was bound or overwritten (saturating). Read back by query_config(). bind_packet() does not send it, but raises ValueError outside 0..65535 |
from medius import ClipAction, ClipPacketTrigger, ClipPacketTriggerError, Direction, TrafficClass
clip = dev.clip()
# Report ID 7 on interface 2 carries a button in bit 5 of its second byte. Start once per hold.
held = ClipPacketTrigger(TrafficClass.HID_IN, 2, Direction.IN, ClipAction.START,
match_bytes=b"\x07\x20", mask=b"\xFF\x20",
once_per_run=True, selector_len=1)
clip.bind_packet(held)
try:
clip.bind_packet(ClipPacketTrigger(TrafficClass.CONTROL, 0, Direction.OUT,
ClipAction.STOP, consume=True))
except ClipPacketTriggerError as e:
print(e) # consume on CONTROL; nothing was sent
for t in clip.query_config().packet_triggers:
print(t.traffic_class, t.id, t.action, t.hits)
clip.unbind_packet(held) # by key
clip.clear_triggers() # both kinds| Field | Type | Meaning |
|---|---|---|
autolock | List[Blanket] | the input groups auto-locked while the clip plays |
loop | bool | playback loops at the clip end (retained mode only) |
retain | bool | the loaded clip is retained so it can rewind and replay |
finalized | bool | a retained clip's end is fixed, ready to replay and loop |
ride | bool | the clip's motion waits for a native move under movement riding |
triggers | List[ClipTrigger] | the bound input triggers (up to 8) |
packet_triggers | List[ClipPacketTrigger] | the bound packet triggers (up to 8), in the order the box holds them, each with its hits |
| Field / method | Type | Meaning |
|---|---|---|
state | ClipState | the lifecycle state |
free / total | int | ring bytes free (pace top-ups off this) / retained clip size in bytes (streaming: bytes buffered but not yet played) |
played | int | bytes played from the clip start (retained progress; ~0 while streaming) |
ticks | int | content frames played since the box booted (gap runs excluded) |
underruns / overruns / seq_gaps | int | empty-ring / ring-full / dropped-append counts |
xfers | int | clip transfers the real device completed |
xfer_errs | int | clip transfers that ended any other way: a refusal, no reply, no room in the box's queue, or dropped behind a transfer the real device did not reply to |
gated | int | raw reports and transfers the box discarded because the imperfect-clone opt-in was off |
held | List[Usage] | the held-usage snapshot: the buttons, keys, and media the clip is holding down (one shape, like a UsageSnapshot) |
is_held(usage) | bool | test one Usage in held |
| Module constant | Value | Meaning |
|---|---|---|
CLIP_EDGES_MAX | 8 | the most edges one clip frame carries |
CLIP_RAW_MAX | 8 | the most raw reports one clip frame carries |
CLIP_ENTRY_MAX | 512 | the most bytes one clip frame encodes to: one CLIP_APPEND payload |
CLIP_PKT_TRIG_MAX | 8 | the most packet triggers the box holds, beside its input triggers |
CLIP_PKT_MATCH_POOL | 112 | the match bytes the box holds across every packet trigger |
PKT_MATCH_MAX | 16 | the most match bytes one packet trigger compares |
Stream enums CatchClass · TrafficClass · Axis · CatchFilter · Capture · CatchEventKind · ClockDomain · BusEventKind · LogLevel
See Catch and Logs & counters; consuming events is on Streams.
The address class a CatchFilter names. Members 0 to 3 are the lock classes, unchanged; the rest are the byte-oriented traffic the box carries. id is class-specific.
| Member | Value | id means | As a blanket |
|---|---|---|---|
BUTTON | 0 | a Button slot | every button |
KEY | 1 | a HID keyboard usage | every key and modifier |
MEDIA | 2 | a 16-bit Consumer usage | every media usage |
AXIS | 3 | an Axis | every axis |
HID_IN | 4 | an interface number | every HID interface |
HID_OUT | 5 | an endpoint number | every interrupt-OUT endpoint |
VENDOR_INTERRUPT | 6 | an endpoint number | every vendor interrupt endpoint |
VENDOR_BULK | 7 | an endpoint number | every vendor bulk endpoint |
CONTROL | 8 | an endpoint number (0 = EP0; on EP0, the requests the clone relays to the real device) | every control endpoint |
EMIT | 9 | an endpoint number | every emitting endpoint |
BUS | 10 | unused | the bus lifecycle |
CLIP_TRANSFER | 11 | the endpoint number (0 = EP0) a clip's transfer ran on | every control endpoint |
The every-class wildcard is CatchFilter.everything(), whose catch_class reads None. cls.is_input() is true for 0 to 3, cls.is_traffic() for the rest.
Where each class is tapped, and why a locked input still reports, is on Catch.
The byte-oriented half of the address space, values 4 to 11 under the same names as CatchClass.
| Members | Values |
|---|---|
HID_IN HID_OUT | 4, 5 |
VENDOR_INTERRUPT VENDOR_BULK | 6, 7 |
CONTROL EMIT BUS | 8, 9, 10 |
CLIP_TRANSFER | 11 |
CatchFilter.traffic and traffic_class take a TrafficClass, so an input class can't be passed to a traffic constructor.
| Member | Value |
|---|---|
X | 0 |
Y | 1 |
WHEEL | 2 |
PAN | 3 |
One relative axis, for CatchFilter.watch_axis(axis). The values are the wire axis ids a catch or lock entry carries.
One subscription entry: a class, an id inside it, a direction, and how many bytes to keep per event. Pass one or an iterable to dev.catch_events() or dev.input_events(). Instance methods return a new filter.
CatchFilter.watch(usage) -> CatchFilter # a Usage, or a Button/Key/MediaKey CatchFilter.watch_axis(axis) -> CatchFilter # one Axis CatchFilter.watch_class(input_class) -> CatchFilter # every usage in one Class CatchFilter.watch_axes() -> CatchFilter # X, Y, the wheel and AC Pan CatchFilter.all_input() -> List[CatchFilter] # all four input classes CatchFilter.traffic(traffic_class, id) -> CatchFilter # one endpoint, interface, or EP number CatchFilter.traffic_class(tc) -> CatchFilter # every id in one TrafficClass CatchFilter.everything() -> CatchFilter # every class, every id, one entry .with_direction(direction) -> CatchFilter # a Direction, default BOTH .with_capture(n) -> CatchFilter # bytes kept per event, default 0 = all .on_press() / .on_release() -> CatchFilter # one edge of an input filter .inbound() / .outbound() -> CatchFilter # one flow of a traffic filter .same_address(other) -> bool # same table entry, whatever the capture CatchFilter.traffic(TrafficClass.VENDOR_INTERRUPT, 0x83).with_capture(16)
| Property | Type | Meaning |
|---|---|---|
catch_class | Optional[CatchClass] | the address class, or None for the every-class wildcard |
id | Optional[int] | the class-specific id, or None for the every-id wildcard. An id of 0 is a real address, not a wildcard. |
direction | Direction | for an input class, the press/release edge, as for a lock; for a traffic class, the transfer flow, where POSITIVE is IN (device to PC) and NEGATIVE is OUT (PC to device). |
capture | int | bytes captured per event; 0 = the whole packet |
The top-ranked entry supplies the capture; the ranking is on The table.
same_address is true across two filters that differ only in capture, and false once one is narrowed to a direction.
Arguments are checked before ctypes: with_direction, watch_axis, watch_class, traffic, and traffic_class take a member of their enum, with_capture a byte; anything else raises a ValueError naming the argument.
The box's table holds 32 entries; catch_events() raises CatchTableFullError when this process's subscriptions together exceed it. A box-side refusal (a class this firmware does not know) raises nothing: compare CatchState.entries from dev.query_catch() with what you sent.
Capture.WHOLE # 0, keep the whole packet Capture.first(n) # keep the first n bytes; first(0) is WHOLE
What with_capture takes. Traffic classes only: an input class carries no packet, so naming one with a capture raises CaptureNotApplicableError.
A capture is a ceiling you request, not a guarantee. The box holds one entry per address and cuts once, so another subscriber asking for more of that address raises your capture too.
| Member | Value | CatchEvent.payload type | Fed by |
|---|---|---|---|
MOTION | 0 | MotionEvent | CatchClass.AXIS |
USAGES | 1 | UsageSnapshot | BUTTON / KEY / MEDIA |
TRAFFIC | 2 | TrafficEvent | every class from HID_IN to CLIP_TRANSFER |
Which of the box's two chips stamped an event's ts_us. The two ESP32-S3s boot independently, so nothing relates their timers.
| Member | Value | Stamped | Covers |
|---|---|---|---|
HOST_CHIP | 0 | in USB interrupt context, when the real device's transfer completed | motion, usages, HID_IN, and native IN transfers on VENDOR_INTERRUPT / VENDOR_BULK |
DEVICE_CHIP | 1 | at the tap on the clone side | HID_OUT, every OUT transfer, a raw packet on a vendor IN endpoint, and CONTROL / EMIT / BUS / CLIP_TRANSFER |
Compare stamps only within one domain. Both clocks are box-local, wrap every ~71.6 minutes, and restart at zero when their chip reboots. A value below the previous one is a wrap, a reboot, or a domain change.
A Timeline puts stamps on this machine's clock; to cross domains, apply the ClockEstimate offset within its error bound.
What a CatchClass.BUS event describes. These also drive Health bits and Stats counters; catching them adds a timestamped ordering.
| Member | Value | Payload fields |
|---|---|---|
RESET | 0 | - |
SUSPEND | 1 | - |
RESUME | 2 | - |
CONFIGURED | 3 | configuration |
DECONFIGURED | 4 | - |
SET_INTERFACE | 5 | interface, alt |
DEVICE_ATTACHED | 6 | - |
DEVICE_DETACHED | 7 | - |
CLONE_UP | 8 | - |
CLONE_DOWN | 9 | - |
BusEvent is the decoded dataclass TrafficEvent.bus_event() returns: a kind plus configuration, interface and alt, each 0 for the kinds carrying none.
| Member | Value |
|---|---|
ERROR | 0 |
WARN | 1 |
INFO | 2 |
DEBUG | 3 |
VERBOSE | 4 |
Wire enums MotionKind · MoveTiming · PendingMotion · Class · FrameType
Mostly internal. MotionKind and Class tag the structs the Usage and Motion builders produce; FrameType names a wire frame for MockBox.saw() and RecordedFrame.type. Frame semantics are on Frames and Library frames.
| Member | Value |
|---|---|
CURSOR | 0 |
WHEEL | 1 |
PAN | 2 |
| Member | Value | Meaning |
|---|---|---|
RIDE | 0 | follow movement riding: while it is on, wait for a native cursor move to carry the delta (the default) |
NOW | 1 | emit on the next mouse report, native or not, whatever movement riding is set to |
| Member | Value | Meaning |
|---|---|---|
KEEP | 0 | leave motion held by riding as it is (the default) |
FLUSH | 1 | emit held motion now, ignoring the ride window |
DISCARD | 2 | drop held motion |
| Member | Value |
|---|---|
BUTTON | 0 |
KEY | 1 |
MEDIA | 2 |
| Member | Value | Member | Value |
|---|---|---|---|
MOVE | 1 | LOCK | 10 |
INJECT | 3 | CATCH | 11 |
RESET | 4 | MOTION_EVENT | 12 |
QUERY | 5 | USAGE_EVENT | 15 |
RESP | 6 | OPTION | 17 |
REBOOT_DL | 7 | CLIP_APPEND | 18 |
LOG | 8 | CLIP_CTRL | 19 |
LED | 9 | CLIP_SET | 20 |
CLIP_TRIGGER | 21 | ||
TRAFFIC_EVENT | 22 |
Parameter builders Usage · Motion · LockTarget
Classes that wrap a C struct. Build them with their class methods, never field by field, and pass the result to the matching call.
Usage.button(button) -> Usage # build Usage.key(key) -> Usage Usage.media(media) -> Usage usage.kind -> Class # read one back usage.id -> int
An injection target for dev.inject(input, action), and what an InputEvent and a UsageSnapshot return. It compares by value, hashes, and reprs as Usage(kind=BUTTON, id=0).
# Naming a button off the stream: id is the Button value, kind says which class it is.
if ev.usage is not None and ev.usage.kind is Class.BUTTON:
print(Button(ev.usage.id).name)
# Or compare whole usages.
if ev.usage == Usage.button(Button.SIDE1):
print("side button")Motion.cursor(dx, dy) -> Motion Motion.wheel(delta) -> Motion Motion.pan(delta) -> Motion
A relative axis drive for dev.move_axis(motion, timing, pending); pan is AC Pan (horizontal scroll), a full peer of the wheel. See Move.
LockTarget.x() -> LockTarget LockTarget.y() -> LockTarget LockTarget.wheel() -> LockTarget LockTarget.pan() -> LockTarget LockTarget.usage(usage) -> LockTarget LockTarget.button(button) -> LockTarget LockTarget.key(key) -> LockTarget LockTarget.media(media) -> LockTarget
An axis or usage to lock for dev.lock(target, direction); the button/key/media shortcuts wrap usage(). See Lock.
Device enums DeviceKind
The cloned device's kind, on DeviceInfo.kind, and what Device.find_mouse_box() / find_keyboard_box() select on. See DeviceKind.
| Member | Value |
|---|---|
UNKNOWN | 0 |
KEYBOARD | 1 |
MOUSE | 2 |
Identity & capability types Version · Health · DeviceInfo · Caps
Dataclasses returned by the queries. Canonical field docs: Library structs.
| Field / property | Type | Meaning |
|---|---|---|
proto_ver | int | control-protocol version |
fw_major | int | firmware major |
fw_minor | int | firmware minor |
fw_patch | int | firmware patch |
mac | bytes | the device chip's base MAC (6 bytes), a stable per-box id |
mac_hex | str | the MAC as 12 lowercase hex digits |
name | str | the box's human-readable name (a synthesised default when unset), set with set_name |
| Field | Type |
|---|---|
link_up | bool |
mouse_attached | bool |
clone_configured | bool |
injection_active | bool |
rate_confident | bool |
lock_on | bool |
catch_on | bool |
kbd_attached | bool |
rewrite_on | bool |
patch_on | bool |
transform_on | bool |
| Field | Type | Meaning |
|---|---|---|
vid | int | USB vendor id |
pid | int | USB product id |
bcd_device | int | device release (BCD) |
bcd_usb | int | USB spec (BCD) |
has_serial | bool | exposes a serial string |
has_bos | bool | exposes a BOS descriptor |
kind | DeviceKind | the real device's primary kind, from its HID report descriptors |
product | str | the product string (empty when none) |
is_cloned() | bool | a device is cloned, including one with no HID interface (n_hid 0). With nothing cloned every field is zero |
| Field / method | Type | Meaning |
|---|---|---|
mouse | MouseCaps | mouse capabilities |
keyboard | KbdCaps | keyboard capabilities |
mouse_change_driven | bool | mouse reports only on change |
kbd_change_driven | bool | keyboard reports only on change |
has_mouse() | bool | a mouse interface is present |
has_keyboard() | bool | a keyboard interface is present |
is_composite() | bool | the clone has more than one HID interface (n_hid > 1) |
| Field | Type | Meaning |
|---|---|---|
n_buttons | int | button count |
has_x | bool | X axis present |
has_y | bool | Y axis present |
has_wheel | bool | wheel present |
pan | bool | AC Pan (horizontal scroll) present |
has_report_id | bool | reports carry a report id |
n_hid | int | HID interface count |
| Field | Type | Meaning |
|---|---|---|
n_keys | int | rollover key count |
nkro | bool | n-key rollover |
has_consumer | bool | Consumer (media) page |
has_system | bool | System-control page |
has_report_id | bool | reports carry a report id |
State & telemetry types Rate · Stats · Locks · CatchState · CatchEntry · ClockEstimate · ImperfectStatus · Counters · PortInfo
More query results, plus PortInfo from find_ports(). Canonical field docs: Library structs.
| Field | Type | Meaning |
|---|---|---|
major, minor, patch | int | the version this chip is running |
slot | int | which app slot it booted, 0 or 1 |
state | ImageState | confirmed, on probation, or rolled back |
| Field | Type | Meaning |
|---|---|---|
device | ChipFirmware | the PC-facing chip |
host | ChipFirmware | None | None when the host chip has not replied over the link |
slot_size | int | usable bytes in a spare slot, the same on both chips |
device_staged | bool | an image is written and waiting to be activated |
host_staged | bool | the same, for the host chip |
any_pending() | bool | either chip has not confirmed the image it booted, so an update is refused |
| Field / method | Type | Meaning |
|---|---|---|
native_period_us | int | mouse report period, µs |
poll_period_us | int | poll period, µs |
confident | bool | estimate is settled |
change_driven | bool | reports only on change |
native_hz() | float | None | rate in Hz, or None if unknown |
| Field | Type | Meaning |
|---|---|---|
inject_emits | int | injected reports emitted |
tx_drops | int | reports the clone's IN queue could not hold |
tx_merges | int | coalesced TX frames |
tx_maxdepth | int | peak TX queue depth |
tx_wedges | int | wedged-endpoint recoveries |
wakeups | int | remote wakeups the clone signalled to the game PC, for the real device or an injection |
reset_count | int | resets seen |
config_count | int | clone configures |
link_rx_drops | int | input frames the device chip could not take off the link from the host chip |
host_rx_drops | int | the same count on the host chip, relayed over the link |
relay_drops | int | relayed traffic and commands that went no further, never native input. One count each for: a vendor IN packet whose endpoint queue was full of the control PC's RAW packets; a native zero-length packet answering a poll the PC never made (the box runs one poll ahead of a suspended PC); an OUT packet with no room in the queue, that failed three times on the real device's bus, or that a bus reset or SET_INTERFACE overtook; a RAW OUT packet with no room to wait; a relayed request the box could not queue; a flagged MOVE the motion batch could not take; a frame other than native input that either chip's link receive ring dropped; a control-PC frame its receive ring had no room for. A control-port UART overrun counts once, however many frames it cost |
session | int | times the box released some or all of the session state a host set. 0 at boot; it wraps, so compare for inequality. The library watches it for session recovery |
| Field / method | Type | Meaning |
|---|---|---|
entries | List[LockEntry] | one LockEntry per weighed direction |
scale_of(target, direction) | int | percent of the native value kept on that target and direction, 100 when nothing weighs it. BOTH reports the scale of smallest magnitude across every direction (a negative one on a tie): a block outranks a reversal of any size, and a pass outranks a reversal past -100. A delta meets a different figure: its fixed-sign scale times its relative scale |
is_locked(target, direction) | bool | whether that target/direction is blocked outright; a direction merely weighed is not locked. Also true when a whole-class blanket covers it. BOTH asks about the two fixed signs only, so name WITH or AGAINST to ask about one of those |
| Readback case | What entries holds |
|---|---|
| a blanket key lock | one entry per blocked edge, never BOTH |
| a media lock, blanket or specific | BOTH, always |
a relative direction under BearingMode.VECTOR | the effective scale, the lower of X's and Y's, on both axes |
| 85 entries reached | entries past 85 are left out, and nothing marks the cut; see the native LOCKS budget |
| Module constant | Value | Meaning |
|---|---|---|
LOCK_SCALE_BLOCK | 0 | keep none of the native value |
LOCK_SCALE_PASS | 100 | keep all of it, untouched |
LOCK_SCALE_MAX | 255 | 2.55×, the ceiling |
LOCK_SCALE_MIN | -255 | 2.55× reversed, the floor; a negative reverses what it keeps (-100 inverts an axis). Axes only |
| Field | Type | Meaning |
|---|---|---|
target | LockTarget | what is weighed (an axis or a usage) |
is_blanket | bool | a whole-class entry, where target names only the class |
direction | Direction | which direction of the target this entry weighs |
scale | int | percent of the native value kept, signed: a negative one reverses what it keeps. A usage is one bit, so the box stores a block or a pass: never a value between, never negative |
is_block | bool | scale == 0: blocked outright rather than weighed |
What Direction.WITH and Direction.AGAINST are measured against; see the native bearing.
| Field / property | Type | Meaning |
|---|---|---|
window_ms | Optional[int] | how long an axis holds the direction of its last injected delta; None is off, leaving both relative directions inert |
mode | BearingMode | how the bearing is read |
is_live | bool | whether a bearing is held at all |
Module constant BEARING_WINDOW_DEFAULT_MS (20) is the factory window; a box that has been set boots at its stored value.
The live subscription table: the only view of which filters the box holds, since catch_events() gets no reply.
| Field | Type | Meaning |
|---|---|---|
table_full | bool | an entry was refused because the 32-entry table was full |
dropped | int | box-wide events that could not be queued |
clock | ClockEstimate | the measured relationship between the two chips' clocks |
entries | List[CatchEntry] | one entry per live subscription, up to 32 |
One row of the box's table: the CatchFilter you sent, with its drop count.
| Field | Type | Meaning |
|---|---|---|
filter | CatchFilter | the entry as the box stored it; a class blanket stays one entry, never expanded per id |
dropped | int | events this entry could not queue |
| Field / member | Type | Meaning |
|---|---|---|
offset_us | int | the host chip's clock minus the device chip's, in µs (signed) |
rate_ppb | Optional[int] | relative drift between the two chips, parts per billion (signed), or None when the box fitted no rate |
delay_us | int | the best measured round trip in the window; the offset is good to ~half of it |
age_ms | Optional[int] | age of the estimate, or None when there is no estimate yet |
error_bound_us | int | half delay_us: the bound on how wrong offset_us can be |
to_host_domain(device_us) | Optional[int] | a device-chip stamp on the host chip's timeline, or None when there is no estimate to apply |
The two chips' crystals drift the offset by up to 20 µs/s; extrapolate with rate_ppb.
Applying the offset is optional: each event's clock stays authoritative.
| Field | Type | Meaning |
|---|---|---|
allowed | bool | imperfect clones opted in |
over_capacity | bool | real device exceeds clone capacity |
clone_imperfect | bool | the live clone is imperfect |
See Options.
| Field | Type | Meaning |
|---|---|---|
mode | EmitPace | the pace |
resolved_hz | int | the ceiling in effect; 0 = learned/adaptive or no device yet, 1000 once the renderer has a profile |
force_hz | int | None | the forced wire rate requested; None leaves native |
advertised_hz | int | what the clone's input endpoints advertise now, forced or native; 0 = no clone |
force_active | bool | whether a forced interval is written into the descriptor being served |
See Options.
| Field | Type | Meaning |
|---|---|---|
mode | RenderMode | the texture motion is rendered with; OFF is the paced fill |
full | bool | whether native motion is rendered by the model rather than relayed |
ready | bool | whether a profile has armed for the real device; nothing is rendered until it has |
See Options.
| Field | Type | Meaning |
|---|---|---|
percent | int | share of the command interval a delta is released across; 0 is the whole delta on the next report |
span_us | int | the interval in effect, in microseconds; 0 when nothing is released across an interval |
See Options.
| Field | Type | Meaning |
|---|---|---|
frames_tx | int | host-side frames sent |
frames_rx | int | host-side frames received |
crc_drops | int | frames dropped on CRC |
reconnects | int | link reconnects |
restarts | int | device-chip restarts the library recovered from; a session release does not count here |
| Field | Type | Meaning |
|---|---|---|
path | str | serial path, e.g. /dev/ttyACM0 or COM3 |
vid | int | USB vendor id |
pid | int | USB product id |
serial | Optional[str] | the CH343 adapter's serial, when it serves one |
Pass path to Device.open(path). Canonical: PortInfo.
| Field / property | Type | Meaning |
|---|---|---|
port | PortInfo | the box's control port |
version | Version | its firmware version and control protocol, with the box MAC and name |
device | Optional[DeviceInfo] | the real device it clones; None for a box on another control protocol (opening that box raises BadProtoVerError) |
id | str | the box identity (the MAC hex) |
serial | Optional[str] | the CH343 serial |
Pass id or serial to Device.open_by_id(id). Canonical: BoxInfo.
import medius
for b in medius.list_boxes():
if b.device is None:
print(f"{b.id} speaks protocol {b.version.proto_ver}: update its firmware")
else:
print(b.id, b.device.kind.name, b.device.product)Event & log types Yielded by the streams
Stream payloads: dev.catch_events() yields CatchEvent, dev.input_events() yields InputEvent, and dev.logs() yields LogLine. What catch reports is on Catch.
| Field / member | Type | Meaning |
|---|---|---|
kind | CatchEventKind | which payload is set |
payload | MotionEvent | UsageSnapshot | TrafficEvent | the decoded event |
ts_us | int | When the event happened, in box microseconds: the report's arrival for input, the tap firing for traffic. Box-local and wraps every ~71.6 minutes, so compare it only with other box stamps. See Catch timestamps. |
clock | ClockDomain | which chip stamped ts_us. Two stamps are directly comparable only when this matches; across domains, apply CatchState.clock. |
motion | MotionEvent | None | payload when kind == MOTION |
usages | UsageSnapshot | None | payload when kind == USAGES |
traffic | TrafficEvent | None | payload when kind == TRAFFIC |
| Field | Type | Meaning |
|---|---|---|
dx | int | X delta |
dy | int | Y delta |
dz | int | wheel delta |
pan | int | AC Pan (horizontal scroll) delta |
The enclosing CatchEvent carries the stamp and domain.
| Field / method | Type | Meaning |
|---|---|---|
usages | List[Usage] | every held Usage (button, key, or media; modifiers are key usages 0xE0 to 0xE7) |
cls | Class | the one class this snapshot covers, from the frame header |
direction | Direction | the edge that produced it |
is_held(usage) | bool | test a Usage in the snapshot |
Only held usages matching your filters appear, and no event is sent when none match. A one-button subscription stays sparse while the mouse reports at 1 kHz.
An empty snapshot still names its class: cls and direction come from the frame header, not the entries.
The payload for every byte-oriented CatchClass from HID_IN to CLIP_TRANSFER: one packet, one control transaction, or one bus event, with whatever the entry's capture let through.
| Field / method | Type | Meaning |
|---|---|---|
catch_class | CatchClass | which class produced it |
id | int | endpoint number or interface number, per the class |
direction | Direction | IN (device to PC) or OUT (PC to device) |
flags | int | class-specific, see the table below |
true_len | int | the packet's length before capture truncation |
bytes | bytes | the captured bytes, at most 180 of them |
truncated() | bool | len(bytes) < true_len: bytes were cut |
setup() | Optional[bytes] | the 8-byte setup packet of a CONTROL or CLIP_TRANSFER event; None for another class or a shorter capture |
data() | bytes | the data stage of a CONTROL or CLIP_TRANSFER event, the whole packet for any other class |
control_status() | Optional[ControlStatus] | the handshake the game PC received, flags bits 0-1; None for any class but CONTROL |
rule_acted() | bool | whether a rewrite rule changed, dropped, answered or refused the packet: flags bit 7 on HID_IN, HID_OUT, the vendor classes, CONTROL and EMIT |
transfer_status() | Optional[TransferStatus | int] | how the transfer ended, as a TransferStatus (NAK when no reply came) or the raw byte for a status no member names; None for any class but CLIP_TRANSFER |
bus_event() | Optional[BusEvent] | the decoded lifecycle event; None for a class other than BUS, or an unknown kind |
zlp() | bool | whether the event is a zero-length packet (flags bit 1 on the packet classes). On a HID endpoint, a HID_IN or EMIT event also returns true when a ZLP ended the report after its bytes |
bulk_end_of_transfer() | bool | whether a VENDOR_BULK event is the last of its transfer, flags bit 0 |
| Class | flags | Read it with |
|---|---|---|
HID_IN, EMIT | b1 a zero-length packet (on a HID endpoint, possibly one that ended the report after the event's bytes); b7 a rewrite rule acted on the packet | zlp(), rule_acted() |
HID_OUT, VENDOR_INTERRUPT | b1 a zero-length packet, b7 a rule acted | zlp(), rule_acted() |
VENDOR_BULK | b0 end-of-transfer, b1 zero-length packet, b7 a rule acted | bulk_end_of_transfer(), zlp(), rule_acted() |
CONTROL | b0-b1 the handshake the game PC received, a ControlStatus; b7 a rule acted | control_status(), rule_acted() |
CLIP_TRANSFER | how the transfer ended, a TransferStatus byte; 0xFE when no reply came | transfer_status() |
BUS | the BusEventKind; the bytes hold its arguments | bus_event() |
| everything else | 0 | - |
A CONTROL or CLIP_TRANSFER event is one completed transaction. bytes is [setup 8][data...] (IN data only on CLIP_TRANSFER); direction says which way the data stage went.
CONTROL data | Holds |
|---|---|
| IN | the reply the game PC received, after a REPLY_PATCH or REPLY_REPLACE rule, or an ANSWER rule's payload |
| OUT | the data stage the game PC sent, before a PATCH or REPLACE rule rewrote it for the real device |
A CONTROL event is the transaction as the game PC received it, on any control endpoint. Requests the box serves from its value cache still produce one.
| Member | Value | Meaning |
|---|---|---|
OK | 0 | the transaction completed |
STALLED | 1 | the game PC got a STALL from the real device, from a rule that refused the request, or (above endpoint 0) for a failed request |
NAKED | 2 | NAKed until the host gave up, on endpoint 0 only |
OTHER | 3 | a handshake value this build does not know; read it off TrafficEvent.flags bits 0-1 |
One decoded input: a press edge, a release edge, or a motion report. Yielded by dev.input_events(), diffed from the box's held-usage snapshots.
| Field / property | Type | Meaning |
|---|---|---|
kind | InputKind | which arm is populated |
usage | Optional[Usage] | the usage that changed; None for MOTION |
dx / dy / dz / pan | int | right / down / wheel-up / pan-right deltas this report; 0 unless kind is MOTION |
ts_us | int | the box stamp, as on a CatchEvent |
clock | ClockDomain | which chip stamped it |
is_press / is_release | bool | shorthand for the kind test |
| Member | Value | Populates |
|---|---|---|
PRESS | 0 | usage, a momentary usage going down |
RELEASE | 1 | usage, the same coming up |
MOTION | 2 | dx, dy, dz, pan |
One event placed on this machine's clock by a Timeline.
| Field | Type | Meaning |
|---|---|---|
host_ns | int | when the event happened, on the same monotonic scale passed as now_ns |
box_us | int | the event's stamp, unwrapped past the 32-bit rollover |
excess_ns | int | how much later than the measured floor this event arrived. Jitter, not latency. |
| Field | Type | Meaning |
|---|---|---|
level | LogLevel | severity |
text | str | the log message |
Advanced control layer types Setup · TransferOutcome · RewriteRule · Patch
Value types for the imperfect-clone advanced control layer. See Raw injection, Control transfers, Rewrite rules, and Descriptor patches.
| Field | Type | Meaning |
|---|---|---|
request_type | int | bmRequestType: direction in bit 7 (set = device-to-host). |
request | int | bRequest. |
value | int | wValue. |
index | int | wIndex. |
length | int | wLength: the data-stage length. |
| Field | Type | Meaning |
|---|---|---|
status | TransferStatus | int | OK (0x00), REFUSED (0xFC), STALL (0xFD), NAK (0xFE), NO_DEVICE (0xFF), or a byte no constant names. |
data | bytes | The IN data the real device returned. |
is_ok() | bool | Whether the transfer completed. |
RewriteRule is what dev.set_rewrite takes and query_rewrite_entry returns, keyed by (rewrite_class, id, direction, match_bytes, mask). query_rewrite returns a RewriteTable (table_full, generation, entries) of RewriteEntry summaries. table_full says the box refused the last new rule or overwrite for lack of room (32 rules, or the 2048-byte payload pool full). The next change to the table, or a clear, resets it.
| Field | Type | Meaning |
|---|---|---|
rewrite_class | RewriteClass | HID_IN 4, HID_OUT 5, VENDOR_INTERRUPT 6, VENDOR_BULK 7, CONTROL 8, EMIT 9, ANY 0xFF. |
id | int | Interface number or endpoint number. |
direction | Direction | BOTH / POSITIVE / NEGATIVE. |
action | RewriteAction | PASS 0, DROP 1, PATCH 2, REPLACE 3, ANSWER 4, STALL 5, NAK 6, REPLY_PATCH 7, REPLY_REPLACE 8. |
offset | int | Where a patching action writes. |
match_bytes, mask, payload | bytes | The head compare (equal length) and the action's payload. |
Patch is what dev.set_patch takes, keyed by (section, cfg, index, offset); empty bytes removes it. query_patches returns a PatchSet (applied, pending, refused, table_full, entries) of PatchEntry summaries; the four flags read as on PatchSet.
| Field | Type | Meaning |
|---|---|---|
section | PatchSection | DEVICE 0, CONFIG 1, REPORT 2, STRING 3, BOS 4. |
cfg | int | Configuration index, for CONFIG/REPORT. 0 is the first configuration, not bConfigurationValue. |
index | int | Interface or string index, for REPORT/STRING. |
offset | int | Byte offset within the descriptor. |
bytes | bytes | The overwrite bytes; empty removes the patch. |
Transform types Transform · Transforms
Value types for field transforms. Build a Transform with a classmethod or from parts; dev.query_transforms returns a Transforms table. To weigh or reverse a field, use dev.scale (signed percent).
Transform.swap(a, b) -> Transform Transform.remap(source, dest) -> Transform Transform(op, source, dest)
| Field | Type | Meaning |
|---|---|---|
op | TransformOp | REMAP 0, SWAP 1. |
source | LockTarget | The field the transform reads. |
dest | LockTarget | The field it writes. Naming the same field as source raises TransformOpFieldsError: both ops move a value. |
Transforms carries table_full (bool) and entries (a list of Transform, in the order the box applies them).
ErrorsMediusError, its subclasses, and the Status codes
Every Blocks call (and any that fails on the wire) raises a MediusError or a subclass; catch the base class for all of them. Canonical mapping: Library errors.
| Attribute | Type | Meaning |
|---|---|---|
status | Status | the failure code |
message | str | the last error text |
proto_ver | int | offending version byte (bad-proto-version only) |
from medius import Device, MediusError, NotFoundError
try:
dev = Device.find()
except NotFoundError:
... # no box plugged in
except MediusError as e: # any other failure
print(e.status, e.message)| Exception | Raised on |
|---|---|
IoError | ERR_IO |
NotFoundError | ERR_NOT_FOUND |
NoReplyError | ERR_NO_REPLY |
BadProtoVerError | ERR_BAD_PROTO_VER |
QueryTimeoutError | ERR_QUERY_TIMEOUT |
DisconnectedError | ERR_DISCONNECTED |
FrameTooLongError | ERR_FRAME_TOO_LONG |
UpdateError | ERR_UPDATE |
InvalidArgError | ERR_INVALID_ARG |
PanicError | ERR_PANIC |
CatchTableFullError | ERR_CATCH_TABLE_FULL |
EmptySubscriptionError | ERR_EMPTY_SUBSCRIPTION |
CaptureNotApplicableError | ERR_CAPTURE_NOT_APPLICABLE |
NotAnInputFilterError | ERR_NOT_AN_INPUT_FILTER |
WildcardNotInputError | ERR_WILDCARD_NOT_INPUT |
HalfEdgeInputFilterError | ERR_HALF_EDGE_INPUT_FILTER |
ReservedIdError | ERR_RESERVED_ID |
RelativeDirectionError | ERR_RELATIVE_DIRECTION |
LockScaleRangeError | ERR_LOCK_SCALE_RANGE |
LockScaleUsageError | ERR_LOCK_SCALE_USAGE |
ImperfectRequiredError | ERR_IMPERFECT_REQUIRED |
RewriteMaskLengthError | ERR_REWRITE_MASK_LENGTH |
RewriteActionClassError | ERR_REWRITE_ACTION_CLASS |
RewritePayloadTooLargeError | ERR_REWRITE_PAYLOAD_TOO_LARGE |
RewriteTableFullError | ERR_REWRITE_TABLE_FULL |
TransformOpFieldsError | ERR_TRANSFORM_OP_FIELDS |
TransformTableFullError | ERR_TRANSFORM_TABLE_FULL |
RawDirectionError | ERR_RAW_DIRECTION |
ClipFrameCountError | ERR_CLIP_FRAME_COUNT |
ClipFrameTooLongError | ERR_CLIP_FRAME_TOO_LONG |
ClipTransferDataError | ERR_CLIP_TRANSFER_DATA |
ClipPacketTriggerError | ERR_CLIP_PACKET_TRIGGER |
RewriteMatchTooLongError | ERR_REWRITE_MATCH_TOO_LONG |
RewritePoolFullError | ERR_REWRITE_POOL_FULL |
The last 24 are argument refusals, raised before a frame reaches the box.
| Refusal | Raised on |
|---|---|
CatchTableFullError | this process's subscriptions together need more than the box's 32 entries |
EmptySubscriptionError | a subscription with no filters, which would never yield an event |
CaptureNotApplicableError | a Capture on an input class, which carries no packet |
NotAnInputFilterError | a traffic class passed to input_events, which cannot decode one |
WildcardNotInputError | CatchFilter.everything() passed to input_events; it covers traffic too |
HalfEdgeInputFilterError | an input filter narrowed to one edge, which cannot be decoded into press and release |
ReservedIdError | an exact id equal to the blanket sentinel, which would address the whole class instead |
RelativeDirectionError | Direction.WITH or AGAINST where only a fixed sign or edge can be addressed; they resolve against the bearing at emit time, after the call |
LockScaleRangeError | a lock scale outside LOCK_SCALE_MIN to LOCK_SCALE_MAX |
LockScaleUsageError | a negative (reversing) lock scale on a button, key or media usage, which carries one bit and has nothing to reverse |
ImperfectRequiredError | set_rewrite or apply_patch with the imperfect-clone opt-in off |
RewriteMaskLengthError | a rewrite rule whose match and mask are different lengths |
RewriteActionClassError | a rewrite action that its rule's class does not accept |
RewritePayloadTooLargeError | a rewrite payload larger than the head the box holds for its class |
TransformOpFieldsError | a transform op that cannot address its source and destination fields, or one field named as both |
RewriteTableFullError | a rewrite rule past the table's capacity |
TransformTableFullError | a transform past the table's capacity |
RawDirectionError | a raw injection direction other than Direction.IN or Direction.OUT |
ClipFrameCountError | a clip frame with more than CLIP_EDGES_MAX edges or CLIP_RAW_MAX raw reports |
ClipFrameTooLongError | a clip frame that encodes to more than CLIP_ENTRY_MAX bytes |
ClipTransferDataError | a clip transfer whose data is not what its setup packet announces: length bytes for an OUT request, none for an IN one |
ClipPacketTriggerError | a ClipPacketTrigger the box would refuse; the message says why |
RewriteMatchTooLongError | a rewrite rule with more than 16 match bytes |
RewritePoolFullError | a rewrite payload larger than the room the held rules leave in the box's 2048-byte payload pool; an overwrite counts the bytes it replaces as free |
DisconnectedError ends a stream iteration instead of propagating. OK and ERR_UNKNOWN have no subclass; ERR_UNKNOWN raises the base MediusError.
| Attribute | Type | Meaning |
|---|---|---|
op | int | None | the refused op: 0 begin, 1 data, 2 end, 3 abort, 4 activate; 0 after a confirm that timed out |
update_status | int | None | the box's update status for it, such as 0x1B for a chip on probation |
arg | int | None | the status argument |
All three are None when the library raised it without a detail from the box.
| Member | Value | Member | Value |
|---|---|---|---|
OK | 0 | ERR_DISCONNECTED | 6 |
ERR_IO | 1 | ERR_FRAME_TOO_LONG | 7 |
ERR_NOT_FOUND | 2 | ERR_UPDATE | 8 |
ERR_NO_REPLY | 3 | ERR_INVALID_ARG | 9 |
ERR_BAD_PROTO_VER | 4 | ERR_PANIC | 10 |
ERR_QUERY_TIMEOUT | 5 | ERR_UNKNOWN | 11 |
ERR_CATCH_TABLE_FULL | 12 | ERR_WILDCARD_NOT_INPUT | 16 |
ERR_EMPTY_SUBSCRIPTION | 13 | ERR_HALF_EDGE_INPUT_FILTER | 17 |
ERR_CAPTURE_NOT_APPLICABLE | 14 | ERR_RESERVED_ID | 18 |
ERR_NOT_AN_INPUT_FILTER | 15 | ERR_RELATIVE_DIRECTION | 19 |
ERR_LOCK_SCALE_RANGE | 20 | ERR_TRANSFORM_OP_FIELDS | 27 |
ERR_LOCK_SCALE_USAGE | 21 | ERR_TRANSFORM_TABLE_FULL | 28 |
ERR_IMPERFECT_REQUIRED | 22 | ERR_RAW_DIRECTION | 29 |
ERR_REWRITE_MASK_LENGTH | 23 | ERR_CLIP_FRAME_COUNT | 30 |
ERR_REWRITE_ACTION_CLASS | 24 | ERR_CLIP_FRAME_TOO_LONG | 31 |
ERR_REWRITE_PAYLOAD_TOO_LARGE | 25 | ERR_CLIP_TRANSFER_DATA | 32 |
ERR_REWRITE_TABLE_FULL | 26 | ERR_CLIP_PACKET_TRIGGER | 33 |
ERR_REWRITE_MATCH_TOO_LONG | 34 | ERR_REWRITE_POOL_FULL | 35 |