Add MX-T40 BLE desktop controller and protocol documentation
Checks / tests (ubuntu-latest, 3.11) (push) Canceled after 0s
Checks / tests (ubuntu-latest, 3.14) (push) Canceled after 0s
Checks / tests (windows-latest, 3.11) (push) Canceled after 0s
Checks / tests (windows-latest, 3.14) (push) Canceled after 0s
Checks / package (push) Canceled after 0s
Checks / tests (ubuntu-latest, 3.11) (push) Canceled after 0s
Checks / tests (ubuntu-latest, 3.14) (push) Canceled after 0s
Checks / tests (windows-latest, 3.11) (push) Canceled after 0s
Checks / tests (windows-latest, 3.14) (push) Canceled after 0s
Checks / package (push) Canceled after 0s
This commit is contained in:
38 files changed
+2344
No files matched your search
@@ -0,0 +1,58 @@
|
||||
# Architecture
|
||||
|
||||
The protocol module has no Bluetooth or GUI dependencies. Tk exists only in
|
||||
`controller/gui.py`, which `cli.py` imports after parsing arguments. Importing
|
||||
the package or running `--help` does not load Tk or Bleak.
|
||||
|
||||
| Module | Responsibility |
|
||||
| --- | --- |
|
||||
| `protocol.py` | Packet encoding, stream framing, observed checksum variants |
|
||||
| `commands.py` | Semantic command builders; no packet layout in Tk callbacks |
|
||||
| `session.py` | Handshake, outgoing sequence numbers, connection readiness |
|
||||
| `messages.py` | English command/reply descriptions and bounded activity history |
|
||||
| `worker.py` | Thread lifecycle and event/command queues |
|
||||
| `ble_link.py` | Bleak connection, notifications, characteristic writes |
|
||||
| `link.py`, `transport.py` | Experimental RFCOMM and serial adapters |
|
||||
| `gui.py` | Tk controls and event rendering |
|
||||
| `cli.py`, `__main__.py` | Installed command and backwards-compatible module entry |
|
||||
| `ble_probe.py`, `probe.py` | Endpoint diagnostics |
|
||||
| `windows_bluetooth.py` | Experimental RFCOMM initialization |
|
||||
|
||||
## Session interface
|
||||
|
||||
Create one `Session` per connection. Write `session.start()` to begin. Pass
|
||||
received chunks to `session.receive(chunk)` and write every returned `outgoing`
|
||||
packet. `Update.frames` carries decoded packets; `became_ready` is emitted once
|
||||
when the speaker acknowledges the link-complete request. Use
|
||||
`session.command(payload)` for subsequent outgoing packets.
|
||||
|
||||
Both transports cross this same seam. The session owns framing and the state
|
||||
machine, so fixes do not need to be repeated in separate Bluetooth loops.
|
||||
|
||||
A transport connection, a GATT write response, a Samsung packet acknowledgment,
|
||||
and a speaker state report are distinct events. Only the link-complete ACK
|
||||
makes the session ready. Speaker notifications have an independent sequence
|
||||
counter and cannot substitute for that ACK.
|
||||
|
||||
## Threads and ownership
|
||||
|
||||
Tk runs on the main thread. Each connection worker owns its transport. BLE's
|
||||
async event loop lives entirely within the worker thread. The GUI submits
|
||||
payloads through a bounded command queue and consumes events through another
|
||||
queue; workers never call Tk methods.
|
||||
|
||||
BLE notifications enter a bounded async queue and can contain partial or
|
||||
combined packets. The decoder retains framing state between notifications.
|
||||
Queue overflow terminates the connection rather than silently losing framing.
|
||||
|
||||
Writes are spaced and never automatically retried. Retrying a volume or mute
|
||||
key could perform the action twice. The GUI enables controls only after the
|
||||
protocol handshake and disables them on connection closure.
|
||||
|
||||
## Testing
|
||||
|
||||
Protocol tests use captured byte fixtures independently of the outgoing
|
||||
encoder. Session tests cover split replies, duplicate replies, and ACK matching.
|
||||
Transport tests verify subscription order, write mode, disconnects, resource
|
||||
cleanup, and readable error phases. Presentation tests verify the difference
|
||||
between acknowledgment and a reported state. No test opens physical Bluetooth.
|
||||
@@ -0,0 +1,32 @@
|
||||
# Implemented and potential features
|
||||
|
||||
“Verified” below means the owner exercised the control on a physical MX-T40,
|
||||
with packet reports or direct observation. It does not establish compatibility
|
||||
with other Samsung models.
|
||||
|
||||
| Feature | Status |
|
||||
| --- | --- |
|
||||
| BLE connection/status queries | Verified |
|
||||
| EQ presets | Verified, including Rock/Hip-hop/Standard transitions |
|
||||
| Bass boost, volume, mute | Verified |
|
||||
| Lighting presets and RGB color | Verified; RGB activates COLOR mode |
|
||||
| Play/pause and source selection | Owner reports working; playback echo is an event, not absolute state |
|
||||
| DJ effects: off, delay, filter, flanger, chorus, wah-wah | Found in Android app; not implemented or tested here |
|
||||
| Tempo controls | Found in Android app; not implemented or tested here |
|
||||
| USB playback, repeat/shuffle, browsing and track/time information | Found in Android app; not implemented or tested here |
|
||||
| Speaker grouping / wireless party controls | Found in Android app; not implemented or tested here |
|
||||
| Bluetooth multi-connect setting/status | Found in Android app; model compatibility unverified |
|
||||
| Arbitrary per-band EQ | No Samsung app command established |
|
||||
|
||||
## Next work
|
||||
|
||||
Keep the working transport stable. Add read-only status decoding before new
|
||||
controls, then validate one feature at a time on hardware. DJ effects are a
|
||||
useful next feature because the app contains both effect selection and level
|
||||
commands. Grouping is more involved because it changes relationships between
|
||||
speakers and needs more than one device for testing.
|
||||
|
||||
The firmware XML is a Qualcomm configuration schema, not a dump of configured
|
||||
values or a Samsung command dictionary. It documents audio routing/gain curves,
|
||||
button/LED patterns, codec-related definitions, power policies, and GAIA fields.
|
||||
Listed schema options do not prove those features are enabled on the MX-T40.
|
||||
@@ -0,0 +1,107 @@
|
||||
# Samsung control protocol notes
|
||||
|
||||
These original interoperability notes describe observations from an MX-T40 and
|
||||
analysis of the Android Sound Tower app version 0.0.80. Vendor application code
|
||||
and firmware are not included. The working desktop transport is BLE; the iOS
|
||||
app's internal transport/framework has not been established.
|
||||
|
||||
## BLE endpoints
|
||||
|
||||
| Role | UUID |
|
||||
| --- | --- |
|
||||
| Samsung service | `0000ffa0-0000-1000-8000-00805f9b34fb` |
|
||||
| Write, with response | `0000ffa1-0000-1000-8000-00805f9b34fb` |
|
||||
| Notify | `0000ffa2-0000-1000-8000-00805f9b34fb` |
|
||||
|
||||
Subscribe before sending the connection request. Commands currently exposed by
|
||||
the GUI fit within 20 bytes; no larger-command fragmentation scheme is claimed.
|
||||
The speaker also exposes a separate Qualcomm service with UUID
|
||||
`00001100-d102-11e1-9b23-00025b00a5a5`, which this controller does not use.
|
||||
|
||||
MX-T40 model advertisements include FE40/FF40; the Android discovery code also
|
||||
maps FE41/FF41 to T40 names. An advertisement UUID identifies discovery, not
|
||||
necessarily a writable control service.
|
||||
|
||||
## Framing
|
||||
|
||||
```text
|
||||
00 BB TYPE SEQUENCE LENGTH_HI LENGTH_LO PAYLOAD... CHECKSUM
|
||||
```
|
||||
|
||||
Type 0 is an acknowledgment; type 1 carries data. Length counts payload bytes
|
||||
only, in big-endian order. Outgoing sequence numbers cycle 1–127, matching the
|
||||
Android app's signed-byte rollover. Incoming notifications use a separate
|
||||
sequence counter, observed above 127 as well.
|
||||
|
||||
Outgoing checksums sum type, sequence, both length bytes, and payload, modulo
|
||||
256. Incoming packets have several observed checksum variants:
|
||||
|
||||
- Connection/source reports: sum excluding type.
|
||||
- Sound reports: sum including type.
|
||||
- Lighting reports `51 03 MODE`: captured packets match a checksum calculated
|
||||
as though MODE were 1, across Ambient/Dance/Star/Lover/Off observations.
|
||||
- Play/pause echoes `70 11`: the two captured replies similarly match a key
|
||||
slot of 1. This compatibility rule is scoped to that specific payload.
|
||||
|
||||
Why the firmware emits these variants is unknown. Strict decoding recognizes
|
||||
these observed rules. BLE uses advisory mode, retaining structurally framed
|
||||
packets with unfamiliar checksums and flagging them in the activity log. This
|
||||
is compatibility behavior, not a cryptographic integrity guarantee.
|
||||
|
||||
## Handshake
|
||||
|
||||
1. Send payload `01`.
|
||||
2. Receive ACK and connection information beginning `02`.
|
||||
3. Send payload `04` (link complete).
|
||||
4. Receive the ACK matching that outgoing sequence; only then enable controls.
|
||||
5. Query source (`32`) and EQ (`42 03`).
|
||||
|
||||
The captured connection info contains model byte `34` and source IDs
|
||||
`01 02 04 05`: Bluetooth, USB 1, AUX 1, AUX 2. The two bytes following the initial
|
||||
`02` are interpreted by the Android app as protocol version.
|
||||
|
||||
## Payloads
|
||||
|
||||
Numbers below are hexadecimal unless explicitly called decimal.
|
||||
|
||||
| Action | Payload |
|
||||
| --- | --- |
|
||||
| Remote key | `70 KEY` |
|
||||
| Select source | `30 SOURCE` |
|
||||
| Query source | `32` |
|
||||
| Set sound option | `40 TYPE OPTION VALUE EXTRA` |
|
||||
| Query sound option | `42 TYPE` |
|
||||
| Set system option | `50 TYPE VALUE` |
|
||||
| Query system option | `52 TYPE` |
|
||||
| Set RGB color | `60 02 RED GREEN BLUE` |
|
||||
|
||||
Sound TYPE: volume=1, subwoofer=2, EQ=3, bass=4, DJ=5, tempo=6, mute=7.
|
||||
For the implemented EQ/bass controls OPTION and EXTRA are zero.
|
||||
Sound replies use `41 TYPE VALUE VALUE2`, a different layout from writes.
|
||||
|
||||
EQ values (decimal): Party=1, Standard=2, Hip-hop=3, EDM=4, Rock=5, Latin=6,
|
||||
House=7, Reggae=8. Bass values: on=0, off=1. Mute reports: on=1, off=2.
|
||||
|
||||
System TYPE=3 controls lighting. Mode values (decimal): Off=0, Ambient=1,
|
||||
Party=2, Dance=3, Thunder=4, Star=5, Lover=6, Color=7. Reply: `51 03 MODE`.
|
||||
The speaker displays COLOR when the owner chooses an RGB color. The desktop
|
||||
queries lighting mode after RGB writes rather than treating ACK as mode proof.
|
||||
|
||||
Remote keys: volume up=`0F`, volume down=`10`, play/pause=`11`, mute=`14`.
|
||||
A reply `70 11` is a button-event echo, not an absolute playing/paused state.
|
||||
|
||||
## Additional app commands, untested here
|
||||
|
||||
The app defines grouping `05 TYPE CONTROL`, USB playback/browsing/status and
|
||||
repeat controls, DJ selection/levels, tempo, and Bluetooth multi-connect state.
|
||||
See FEATURES.md for the distinction between discovered and verified behavior.
|
||||
Do not infer arbitrary EQ-band access from the firmware configuration schema.
|
||||
|
||||
## Evidence and limits
|
||||
|
||||
Tests contain small, independently captured packet fixtures: connection info,
|
||||
ACKs, source/EQ replies, lighting checksum variants, and play/pause echoes. Real
|
||||
Bluetooth addresses are replaced with synthetic ones. Physical verification
|
||||
covers one MX-T40 on Windows; other models, firmware versions, and platforms
|
||||
remain unverified. RFCOMM channel 1 worked initially but later failed repeatedly;
|
||||
no general explanation or guaranteed workaround has been established.
|
||||
Reference in new issue
Block a user