1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
#!/usr/bin/python3
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
"""Run: /usr/bin/python3 desktop/island/test_sonyctl.py
The frame codec and state parsing only; never touches Bluetooth. The bytes
are ones captured from a WH-CH720N.
"""
import sys
sys.dont_write_bytecode = True # importing sonyctl must not leave a __pycache__
import importlib.machinery
import importlib.util
from pathlib import Path
path = str(Path(__file__).resolve().parent / "sonyctl")
loader = importlib.machinery.SourceFileLoader("sonyctl", path)
spec = importlib.util.spec_from_loader("sonyctl", loader)
s = importlib.util.module_from_spec(spec)
loader.exec_module(s)
# Init request as sent, and the CH720N's init reply as received.
assert s.encode(0x0C, 0, [0x00, 0x00]) == bytes.fromhex("3e0c000000000200000e3c")
reply = s.encode(0x0C, 0, bytes.fromhex("0100030010020000"))
assert s.decode(reply[:-1]) == (0x0C, 0, bytes.fromhex("0100030010020000"))
# Escaping: a 3c, 3d or 3e in the body round-trips and never appears raw.
for b in (0x3C, 0x3D, 0x3E):
f = s.encode(0x0C, 1, [0x68, b])
assert 0x3C not in f[1:-1] and 0x3E not in f[1:-1]
assert s.decode(f[:-1]) == (0x0C, 1, bytes([0x68, b]))
# A bad checksum and a short frame are rejected, not misread.
bad = bytearray(reply[:-1]); bad[-1] ^= 1
assert s.decode(bytes(bad)) is None
assert s.decode(b"\x3e\x0c") is None
assert s.state(bytes.fromhex("6717010100000c")) == {"mode": "nc", "level": 12, "voice": False}
assert s.state(bytes.fromhex("67170101010010")) == {"mode": "ambient", "level": 16, "voice": False}
assert s.state(bytes.fromhex("6717010101010c")) == {"mode": "ambient", "level": 12, "voice": True}
assert s.state(bytes.fromhex("69170100000010")) == {"mode": "off", "level": 16, "voice": False}
assert not s.main(["sonyctl", "00:00:00:00:00:00", "ambient", "21"])["ok"]
assert not s.main(["sonyctl"])["ok"]
assert not s.main(["sonyctl", "00:00:00:00:00:00", "voice", "maybe"])["ok"]
print("ok")
|