Add I2C hot-plug detection and streaming diagnostics (firmware v3.04.0)
Phase D firmware hardening: vendor commands 0xBD (streaming diagnostics) and 0xBE (I2C hot-plug detection) with Python library, bridge, and demo support. All I2C operations use timeout-protected helpers, BCM4500 reads are rate-limited during streaming, and frame counter reads use atomic read-verify-reread pattern. Counters saturate instead of wrapping.
This commit is contained in:
parent
592898dd7a
commit
6e353c351f
4 changed files with 372 additions and 4 deletions
|
|
@ -63,6 +63,8 @@ CMD_MULTI_REG_READ = 0xB9
|
|||
CMD_PARAM_SWEEP = 0xBA
|
||||
CMD_ADAPTIVE_BLIND_SCAN = 0xBB
|
||||
CMD_GET_LAST_ERROR = 0xBC
|
||||
CMD_GET_STREAM_DIAG = 0xBD
|
||||
CMD_GET_HOTPLUG_STATUS = 0xBE
|
||||
|
||||
# Error codes (returned by CMD_GET_LAST_ERROR)
|
||||
ERR_OK = 0x00
|
||||
|
|
@ -789,6 +791,68 @@ class SkyWalker1:
|
|||
"""Disable east/west soft limits."""
|
||||
self.send_diseqc_message(diseqc_disable_limits())
|
||||
|
||||
# -- Streaming diagnostics (v3.04+) --
|
||||
|
||||
def get_stream_diag(self, reset: bool = False) -> dict:
|
||||
"""Read streaming diagnostics counters (0xBD).
|
||||
|
||||
Returns dict with poll_count, overflow_count, sync_loss,
|
||||
last_status, last_lock, armed, had_sync.
|
||||
Set reset=True to clear counters after read.
|
||||
"""
|
||||
wval = 1 if reset else 0
|
||||
data = self._vendor_in(CMD_GET_STREAM_DIAG, value=wval, length=12)
|
||||
poll_count = struct.unpack_from('<I', data, 0)[0]
|
||||
overflow_count = struct.unpack_from('<H', data, 4)[0]
|
||||
sync_loss = struct.unpack_from('<H', data, 6)[0]
|
||||
return {
|
||||
"poll_count": poll_count,
|
||||
"overflow_count": overflow_count,
|
||||
"sync_loss": sync_loss,
|
||||
"last_status": data[8],
|
||||
"last_lock": data[9],
|
||||
"armed": bool(data[10]),
|
||||
"had_sync": bool(data[11]),
|
||||
}
|
||||
|
||||
# -- I2C hot-plug detection (v3.04+) --
|
||||
|
||||
def get_hotplug_status(self, reset: bool = False,
|
||||
force_scan: bool = False) -> dict:
|
||||
"""Read I2C hot-plug detection status (0xBE).
|
||||
|
||||
Returns dict with current/previous bus bitmaps, change count,
|
||||
devices added/removed in last scan, and decoded address lists.
|
||||
Set reset=True to clear change counter.
|
||||
Set force_scan=True to trigger immediate I2C rescan.
|
||||
"""
|
||||
wval = 2 if force_scan else (1 if reset else 0)
|
||||
data = self._vendor_in(CMD_GET_HOTPLUG_STATUS, value=wval, length=36)
|
||||
current_bitmap = bytes(data[0:16])
|
||||
changes = struct.unpack_from('<H', data, 16)[0]
|
||||
added = data[18]
|
||||
removed = data[19]
|
||||
previous_bitmap = bytes(data[20:36])
|
||||
return {
|
||||
"current_bitmap": current_bitmap,
|
||||
"previous_bitmap": previous_bitmap,
|
||||
"changes": changes,
|
||||
"added": added,
|
||||
"removed": removed,
|
||||
"current_devices": _bitmap_to_addrs(current_bitmap),
|
||||
"previous_devices": _bitmap_to_addrs(previous_bitmap),
|
||||
}
|
||||
|
||||
|
||||
def _bitmap_to_addrs(bitmap: bytes) -> list[int]:
|
||||
"""Convert 16-byte I2C address bitmap to list of 7-bit addresses."""
|
||||
addrs = []
|
||||
for byte_idx in range(16):
|
||||
for bit in range(8):
|
||||
if bitmap[byte_idx] & (1 << bit):
|
||||
addrs.append((byte_idx << 3) | bit)
|
||||
return addrs
|
||||
|
||||
|
||||
# --- DiSEqC 1.2 command builders ---
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue