Coverage for src/bluetooth_sig/gatt/descriptors/server_characteristic_configuration.py: 86%
28 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
« prev ^ index » next coverage.py v7.11.0, created at 2025-10-30 00:10 +0000
1"""Server Characteristic Configuration Descriptor implementation."""
3from __future__ import annotations
5from enum import IntFlag
7import msgspec
9from ..characteristics.utils import DataParser
10from .base import BaseDescriptor
13class SCCDFlags(IntFlag):
14 """SCCD (Server Characteristic Configuration Descriptor) flags."""
16 BROADCASTS_ENABLED = 0x0001
19class SCCDData(msgspec.Struct, frozen=True, kw_only=True):
20 """SCCD (Server Characteristic Configuration Descriptor) data."""
22 broadcasts_enabled: bool
25class ServerCharacteristicConfigurationDescriptor(BaseDescriptor):
26 """Server Characteristic Configuration Descriptor (0x2903).
28 Controls server-side configuration for a characteristic.
29 Currently only supports broadcast enable/disable.
30 """
32 def _has_structured_data(self) -> bool:
33 return True
35 def _get_data_format(self) -> str:
36 return "uint16"
38 def _parse_descriptor_value(self, data: bytes) -> SCCDData:
39 """Parse SCCD value into broadcast flags.
41 Args:
42 data: Raw bytes (should be 2 bytes for uint16)
44 Returns:
45 SCCDData with broadcast flags
47 Raises:
48 ValueError: If data is not exactly 2 bytes
49 """
50 if len(data) != 2:
51 raise ValueError(f"SCCD data must be exactly 2 bytes, got {len(data)}")
53 # Parse as little-endian uint16
54 value = DataParser.parse_int16(data, endian="little")
56 return SCCDData(
57 broadcasts_enabled=bool(value & SCCDFlags.BROADCASTS_ENABLED),
58 )
60 @staticmethod
61 def create_enable_broadcasts_value() -> bytes:
62 """Create value to enable broadcasts."""
63 return SCCDFlags.BROADCASTS_ENABLED.to_bytes(2, "little")
65 @staticmethod
66 def create_disable_broadcasts_value() -> bytes:
67 """Create value to disable broadcasts."""
68 return (0).to_bytes(2, "little")
70 def is_broadcasts_enabled(self, data: bytes) -> bool:
71 """Check if broadcasts are enabled."""
72 parsed = self._parse_descriptor_value(data)
73 return parsed.broadcasts_enabled