Coverage for src / bluetooth_sig / gatt / characteristics / rc_feature.py: 100%
52 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:41 +0000
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:41 +0000
1"""RC Feature characteristic (0x2B1D).
3Describes the supported features of the Reconnection Configuration server.
5Structure: E2E-CRC (uint16) + RC Feature field (3+n octets).
6The RC Feature field is a variable-length bit field with an extension
7mechanism via bit 23.
9References:
10 Bluetooth SIG Reconnection Configuration Service v1.0.1, Section 3.1
11"""
13from __future__ import annotations
15from enum import IntFlag
17import msgspec
19from ..context import CharacteristicContext
20from .base import BaseCharacteristic
21from .utils import DataParser
24class RCFeatureFlags(IntFlag):
25 """RC Feature bit definitions as per RCS v1.0.1 Table 3.3."""
27 E2E_CRC_SUPPORTED = 0x000001
28 ENABLE_DISCONNECT_SUPPORTED = 0x000002
29 READY_FOR_DISCONNECT_SUPPORTED = 0x000004
30 PROPOSE_RECONNECTION_TIMEOUT_SUPPORTED = 0x000008
31 PROPOSE_CONNECTION_INTERVAL_SUPPORTED = 0x000010
32 PROPOSE_PERIPHERAL_LATENCY_SUPPORTED = 0x000020
33 PROPOSE_SUPERVISION_TIMEOUT_SUPPORTED = 0x000040
34 PROPOSE_ADVERTISEMENT_INTERVAL_SUPPORTED = 0x000080
35 PROPOSE_ADVERTISEMENT_COUNT_SUPPORTED = 0x000100
36 PROPOSE_ADVERTISEMENT_REPETITION_TIME_SUPPORTED = 0x000200
37 ADVERTISEMENT_CONFIGURATION_1_SUPPORTED = 0x000400
38 ADVERTISEMENT_CONFIGURATION_2_SUPPORTED = 0x000800
39 ADVERTISEMENT_CONFIGURATION_3_SUPPORTED = 0x001000
40 ADVERTISEMENT_CONFIGURATION_4_SUPPORTED = 0x002000
41 UPGRADE_TO_LESC_ONLY_SUPPORTED = 0x004000
42 NEXT_PAIRING_OOB_SUPPORTED = 0x008000
43 USE_OF_FILTER_ACCEPT_LIST_SUPPORTED = 0x010000
44 LIMITED_ACCESS_SUPPORTED = 0x020000
47class RCFeatureData(msgspec.Struct, frozen=True, kw_only=True):
48 """Parsed RC Feature characteristic data.
50 Attributes:
51 e2e_crc: CRC-CCITT value (0xFFFF if E2E-safety not supported).
52 features: Supported feature flags from the RC Feature field.
54 """
56 e2e_crc: int
57 features: RCFeatureFlags
60class RCFeatureCharacteristic(BaseCharacteristic[RCFeatureData]):
61 """RC Feature characteristic (0x2B1D).
63 org.bluetooth.characteristic.rc_feature
65 Composite characteristic: E2E-CRC (uint16) followed by
66 a variable-length RC Feature bit field (3+ octets).
67 """
69 _E2E_CRC_SIZE = 2
70 _MIN_FEATURE_OCTETS = 3
71 _DEFINED_BITS_MASK = 0x03FFFF
72 _BYTE_MASK = 0xFF
73 _BITS_PER_BYTE = 8
75 min_length = _E2E_CRC_SIZE + _MIN_FEATURE_OCTETS
76 allow_variable_length = True
78 def _decode_value(
79 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
80 ) -> RCFeatureData:
81 """Parse RC Feature data per RCS v1.0.1 Section 3.1."""
82 e2e_crc = DataParser.parse_int16(data, 0, signed=False)
84 # RC Feature field starts after E2E-CRC, variable length (3+n octets).
85 # Read all remaining bytes as little-endian integer.
86 feature_bytes = data[self._E2E_CRC_SIZE :]
87 value = 0
88 for i, byte in enumerate(feature_bytes):
89 value |= byte << (self._BITS_PER_BYTE * i)
90 features = RCFeatureFlags(value & self._DEFINED_BITS_MASK)
92 return RCFeatureData(e2e_crc=e2e_crc, features=features)
94 def _encode_value(self, data: RCFeatureData) -> bytearray:
95 """Encode RC Feature data."""
96 result = bytearray()
97 result.extend(DataParser.encode_int16(data.e2e_crc, signed=False))
99 value = int(data.features)
100 num_octets = max(self._MIN_FEATURE_OCTETS, (value.bit_length() + 7) // self._BITS_PER_BYTE)
101 for i in range(num_octets):
102 result.append((value >> (self._BITS_PER_BYTE * i)) & self._BYTE_MASK)
103 return result