sofapython 0.0.1rc1__py3-none-any.whl
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.
- sofapython/__init__.py +136 -0
- sofapython/ack.py +79 -0
- sofapython/aio.py +552 -0
- sofapython/backup_export.py +507 -0
- sofapython/blob_decoders.py +806 -0
- sofapython/cli.py +447 -0
- sofapython/commands.py +1273 -0
- sofapython/deframer.py +73 -0
- sofapython/device_create.py +1174 -0
- sofapython/devices.py +534 -0
- sofapython/discovery.py +315 -0
- sofapython/frame_handlers.py +131 -0
- sofapython/hub_listener.py +242 -0
- sofapython/hub_logging.py +152 -0
- sofapython/hub_versions.py +112 -0
- sofapython/inputs.py +501 -0
- sofapython/macros.py +669 -0
- sofapython/notify_demuxer.py +434 -0
- sofapython/opcode_handlers.py +1655 -0
- sofapython/protocol_const.py +633 -0
- sofapython/proxy_ack_waiters.py +660 -0
- sofapython/proxy_activity_ops.py +943 -0
- sofapython/proxy_backup.py +504 -0
- sofapython/proxy_backup_export.py +486 -0
- sofapython/proxy_catalog.py +915 -0
- sofapython/proxy_frame_decode.py +227 -0
- sofapython/proxy_ir_blob.py +676 -0
- sofapython/proxy_restore.py +2004 -0
- sofapython/proxy_wifi_device.py +1101 -0
- sofapython/state_helpers.py +713 -0
- sofapython/transport_bridge.py +876 -0
- sofapython/version.py +4 -0
- sofapython/wire_schema.py +164 -0
- sofapython/x1_proxy.py +1833 -0
- sofapython-0.0.1rc1.dist-info/METADATA +162 -0
- sofapython-0.0.1rc1.dist-info/RECORD +39 -0
- sofapython-0.0.1rc1.dist-info/WHEEL +4 -0
- sofapython-0.0.1rc1.dist-info/entry_points.txt +2 -0
- sofapython-0.0.1rc1.dist-info/licenses/LICENSE +21 -0
sofapython/version.py
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"""Per-variant wire-format schema for the three hub firmware lines.
|
|
2
|
+
|
|
3
|
+
The hub speaks the same opcode set across the X1, X1S and X2 product
|
|
4
|
+
lines, but a handful of record-level shape choices differ between
|
|
5
|
+
"narrow" hubs (X1: ASCII labels, 30-byte name slots) and "wide" hubs
|
|
6
|
+
(X1S/X2: UTF-16BE labels, 60-byte name slots, larger input-entry
|
|
7
|
+
stride). This module is the *single* place where those per-variant
|
|
8
|
+
numeric choices are declared.
|
|
9
|
+
|
|
10
|
+
Every builder and parser in the integration that needs a variant
|
|
11
|
+
decision reads it from :func:`schema_for`. Callers never sniff payload
|
|
12
|
+
bytes to *decide* which variant they are talking to; the hub version
|
|
13
|
+
is established once during connect (mDNS classification, re-confirmed
|
|
14
|
+
by the connect banner) and stored on the proxy. Shape sniffing is
|
|
15
|
+
allowed only to *validate* an incoming payload against the expected
|
|
16
|
+
variant -- mismatches log a warning and proceed.
|
|
17
|
+
|
|
18
|
+
If a previously-unknown firmware lineage appears, :func:`schema_for`
|
|
19
|
+
raises a ``ValueError`` rather than silently picking a default. The
|
|
20
|
+
intent is to fail loudly at the boundary so a future variant cannot
|
|
21
|
+
quietly inherit the X1 layout and corrupt writes for the user.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from dataclasses import dataclass
|
|
27
|
+
from enum import Enum
|
|
28
|
+
from typing import Final, Mapping
|
|
29
|
+
|
|
30
|
+
from .hub_versions import HUB_VERSION_X1, HUB_VERSION_X1S, HUB_VERSION_X2
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class InputEntryLayout(Enum):
|
|
34
|
+
"""Per-entry layout used inside a family-0x46 inputs page.
|
|
35
|
+
|
|
36
|
+
``NARROW_ASCII`` is the 27-byte stride seen on X1 hubs: a 1-byte
|
|
37
|
+
key id followed by a 6-byte fid and a 20-byte ASCII label slot.
|
|
38
|
+
|
|
39
|
+
``WIDE_UTF16BE`` is the 48-byte stride seen on X1S/X2 hubs: a
|
|
40
|
+
1-byte key id, a 6-byte fid, a 1-byte ordinal and a 40-byte
|
|
41
|
+
UTF-16BE label slot.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
NARROW_ASCII = "narrow_ascii"
|
|
45
|
+
WIDE_UTF16BE = "wide_utf16be"
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class InputsTrailingLayout(Enum):
|
|
49
|
+
"""Shape of the trailing region following the entry list in a
|
|
50
|
+
family-0x46 inputs page. Phase 3 fleshes out the canonical layout;
|
|
51
|
+
Phase 1 simply needs a stable enum tag per variant so call sites
|
|
52
|
+
stop branching on raw ``hub_version`` strings.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
CONTROL_KEYS_PLUS_FAVORITES = "control_keys_plus_favorites"
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
@dataclass(slots=True, frozen=True)
|
|
59
|
+
class WireSchema:
|
|
60
|
+
"""All per-variant wire choices for one hub firmware line."""
|
|
61
|
+
|
|
62
|
+
#: Width in bytes of the name / brand / tail slots inside a family-0x07
|
|
63
|
+
#: device record body. 30 on X1, 60 on X1S/X2.
|
|
64
|
+
device_slot_width: int
|
|
65
|
+
|
|
66
|
+
#: Total length of a device-record body, including the trailing checksum.
|
|
67
|
+
device_body_len: int
|
|
68
|
+
|
|
69
|
+
#: Codec used for the name and brand slots. ``"ascii"`` on X1,
|
|
70
|
+
#: ``"utf-16-be"`` on X1S/X2.
|
|
71
|
+
device_label_encoding: str
|
|
72
|
+
|
|
73
|
+
#: Per-record stride in an assembled family-0x0E command-record body.
|
|
74
|
+
command_stride: int
|
|
75
|
+
|
|
76
|
+
#: Length of the trailing label slot inside one command record.
|
|
77
|
+
command_label_slot_len: int
|
|
78
|
+
|
|
79
|
+
#: Codec used for command labels.
|
|
80
|
+
command_label_encoding: str
|
|
81
|
+
|
|
82
|
+
#: Length of the trailing label slot inside a family-0x12 macro
|
|
83
|
+
#: region (X1 ASCII / X1S/X2 UTF-16BE).
|
|
84
|
+
macro_label_slot_len: int
|
|
85
|
+
|
|
86
|
+
#: Codec used for macro labels.
|
|
87
|
+
macro_label_encoding: str
|
|
88
|
+
|
|
89
|
+
#: Per-entry stride inside the family-0x46 inputs entry region.
|
|
90
|
+
input_entry_stride: int
|
|
91
|
+
|
|
92
|
+
#: Tag describing per-entry field layout. See :class:`InputEntryLayout`.
|
|
93
|
+
input_entry_layout: InputEntryLayout
|
|
94
|
+
|
|
95
|
+
#: Tag describing the shape of the trailing region (control keys,
|
|
96
|
+
#: favorite slots, state byte) following the entries.
|
|
97
|
+
inputs_trailing_layout: InputsTrailingLayout
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
_X1_SCHEMA: Final[WireSchema] = WireSchema(
|
|
101
|
+
device_slot_width=30,
|
|
102
|
+
device_body_len=120,
|
|
103
|
+
device_label_encoding="ascii",
|
|
104
|
+
command_stride=40,
|
|
105
|
+
command_label_slot_len=30,
|
|
106
|
+
command_label_encoding="ascii",
|
|
107
|
+
macro_label_slot_len=30,
|
|
108
|
+
macro_label_encoding="ascii",
|
|
109
|
+
input_entry_stride=27,
|
|
110
|
+
input_entry_layout=InputEntryLayout.NARROW_ASCII,
|
|
111
|
+
inputs_trailing_layout=InputsTrailingLayout.CONTROL_KEYS_PLUS_FAVORITES,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
_X1S_X2_SCHEMA: Final[WireSchema] = WireSchema(
|
|
116
|
+
device_slot_width=60,
|
|
117
|
+
device_body_len=210,
|
|
118
|
+
device_label_encoding="utf-16-be",
|
|
119
|
+
command_stride=70,
|
|
120
|
+
command_label_slot_len=60,
|
|
121
|
+
command_label_encoding="utf-16-be",
|
|
122
|
+
macro_label_slot_len=60,
|
|
123
|
+
macro_label_encoding="utf-16-be",
|
|
124
|
+
input_entry_stride=48,
|
|
125
|
+
input_entry_layout=InputEntryLayout.WIDE_UTF16BE,
|
|
126
|
+
inputs_trailing_layout=InputsTrailingLayout.CONTROL_KEYS_PLUS_FAVORITES,
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
SCHEMAS: Final[Mapping[str, WireSchema]] = {
|
|
131
|
+
HUB_VERSION_X1: _X1_SCHEMA,
|
|
132
|
+
HUB_VERSION_X1S: _X1S_X2_SCHEMA,
|
|
133
|
+
HUB_VERSION_X2: _X1S_X2_SCHEMA,
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def schema_for(hub_version: str) -> WireSchema:
|
|
138
|
+
"""Return the :class:`WireSchema` for ``hub_version``.
|
|
139
|
+
|
|
140
|
+
Raises :class:`ValueError` if ``hub_version`` is anything other
|
|
141
|
+
than one of the known ``HUB_VERSION_*`` constants. Callers must
|
|
142
|
+
never paper over an unknown variant with a default -- if the
|
|
143
|
+
classification surface produces an unfamiliar value, that is a
|
|
144
|
+
signal that a new firmware lineage exists and the wire layouts
|
|
145
|
+
must be re-derived before writes can be trusted.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
return SCHEMAS[hub_version]
|
|
150
|
+
except KeyError as exc:
|
|
151
|
+
known = ", ".join(sorted(SCHEMAS))
|
|
152
|
+
raise ValueError(
|
|
153
|
+
f"schema_for: unknown hub_version={hub_version!r}; "
|
|
154
|
+
f"expected one of {known}."
|
|
155
|
+
) from exc
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
__all__ = [
|
|
159
|
+
"InputEntryLayout",
|
|
160
|
+
"InputsTrailingLayout",
|
|
161
|
+
"SCHEMAS",
|
|
162
|
+
"WireSchema",
|
|
163
|
+
"schema_for",
|
|
164
|
+
]
|