Coverage for kv4p/messages/version.py: 100%
33 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-13 13:27 +0000
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-13 13:27 +0000
1"""Firmware version payload (part of HELLO)."""
3from __future__ import annotations
5import struct
6from dataclasses import dataclass
7from enum import IntFlag
9_VERSION = struct.Struct("<HcIBffB")
12class RadioFeatures(IntFlag):
13 """Firmware capability flags, as reported in ``Version.features``."""
15 HAS_HL = 1 << 0
16 HAS_PHY_PTT = 1 << 1
17 HAS_ESP32_AFSK = 1 << 2
19 @property
20 def hl(self) -> bool:
21 """True when the firmware reports HL support."""
22 return RadioFeatures.HAS_HL in self
24 @property
25 def phy_ptt(self) -> bool:
26 """True when the firmware reports a physical PTT input."""
27 return RadioFeatures.HAS_PHY_PTT in self
29 @property
30 def esp32_afsk(self) -> bool:
31 """True when the firmware reports ESP32-side AFSK support."""
32 return RadioFeatures.HAS_ESP32_AFSK in self
35@dataclass(frozen=True, slots=True)
36class Version:
37 """Firmware version payload."""
39 ver: int
40 radio_module_status: str
41 window_size: int
42 rf_module_type: int
43 min_radio_freq: float
44 max_radio_freq: float
45 features: RadioFeatures
47 @classmethod
48 def from_bytes(cls, payload: bytes) -> Version:
49 """Parse Version."""
50 if len(payload) != _VERSION.size:
51 raise ValueError(f"Version payload must be {_VERSION.size} bytes, got {len(payload)}")
52 values = _VERSION.unpack(payload)
53 return cls(
54 ver=values[0],
55 radio_module_status=values[1].decode("ascii", errors="replace"),
56 window_size=values[2],
57 rf_module_type=values[3],
58 min_radio_freq=values[4],
59 max_radio_freq=values[5],
60 features=RadioFeatures(values[6]),
61 )