Coverage for src / bluetooth_sig / gatt / characteristics / blood_pressure_feature.py: 100%
45 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"""Blood Pressure Feature characteristic implementation."""
3from __future__ import annotations
5from enum import IntFlag
7import msgspec
9from ..constants import UINT16_MAX
10from ..context import CharacteristicContext
11from .base import BaseCharacteristic
12from .utils import DataParser
15class BloodPressureFeatures(IntFlag):
16 """Blood Pressure Feature flags as per Bluetooth SIG specification."""
18 BODY_MOVEMENT_DETECTION = 0x01
19 CUFF_FIT_DETECTION = 0x02
20 IRREGULAR_PULSE_DETECTION = 0x04
21 PULSE_RATE_RANGE_DETECTION = 0x08
22 MEASUREMENT_POSITION_DETECTION = 0x10
23 MULTIPLE_BOND_SUPPORT = 0x20
24 # BLS v1.1.1 additions (sections 3.3.1.7-3.3.1.9)
25 E2E_CRC_SUPPORT = 0x40
26 USER_DATA_SERVICE_SUPPORT = 0x80
27 USER_FACING_TIME_SUPPORT = 0x0100
30class BloodPressureFeatureData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods
31 """Parsed data from Blood Pressure Feature characteristic."""
33 features_bitmap: int
34 body_movement_detection_support: bool
35 cuff_fit_detection_support: bool
36 irregular_pulse_detection_support: bool
37 pulse_rate_range_detection_support: bool
38 measurement_position_detection_support: bool
39 multiple_bond_support: bool
40 e2e_crc_support: bool
41 user_data_service_support: bool
42 user_facing_time_support: bool
45class BloodPressureFeatureCharacteristic(BaseCharacteristic[BloodPressureFeatureData]):
46 """Blood Pressure Feature characteristic (0x2A49).
48 Used to expose the supported features of a blood pressure monitoring
49 device. Indicates which optional measurements and capabilities are
50 available.
51 """
53 # YAML has no range constraint; enforce full uint16 bitmap range.
54 min_value: int = 0
55 max_value: int = UINT16_MAX
57 def _decode_value(
58 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
59 ) -> BloodPressureFeatureData:
60 """Parse blood pressure feature data according to Bluetooth specification.
62 Format: Features(2) - 16-bit bitmap indicating supported features.
64 Args:
65 data: Raw bytearray from BLE characteristic.
66 ctx: Optional CharacteristicContext providing surrounding context (may be None).
67 validate: Whether to validate ranges (default True)
69 Returns:
70 BloodPressureFeatureData containing parsed feature bitmap and capabilities.
72 """
73 features_bitmap = DataParser.parse_int16(data, 0, signed=False)
75 body_movement_detection = bool(features_bitmap & BloodPressureFeatures.BODY_MOVEMENT_DETECTION)
76 cuff_fit_detection = bool(features_bitmap & BloodPressureFeatures.CUFF_FIT_DETECTION)
77 irregular_pulse_detection = bool(features_bitmap & BloodPressureFeatures.IRREGULAR_PULSE_DETECTION)
78 pulse_rate_range_detection = bool(features_bitmap & BloodPressureFeatures.PULSE_RATE_RANGE_DETECTION)
79 measurement_position_detection = bool(features_bitmap & BloodPressureFeatures.MEASUREMENT_POSITION_DETECTION)
80 multiple_bond_support = bool(features_bitmap & BloodPressureFeatures.MULTIPLE_BOND_SUPPORT)
81 e2e_crc_support = bool(features_bitmap & BloodPressureFeatures.E2E_CRC_SUPPORT)
82 user_data_service_support = bool(features_bitmap & BloodPressureFeatures.USER_DATA_SERVICE_SUPPORT)
83 user_facing_time_support = bool(features_bitmap & BloodPressureFeatures.USER_FACING_TIME_SUPPORT)
85 return BloodPressureFeatureData(
86 features_bitmap=features_bitmap,
87 body_movement_detection_support=body_movement_detection,
88 cuff_fit_detection_support=cuff_fit_detection,
89 irregular_pulse_detection_support=irregular_pulse_detection,
90 pulse_rate_range_detection_support=pulse_rate_range_detection,
91 measurement_position_detection_support=measurement_position_detection,
92 multiple_bond_support=multiple_bond_support,
93 e2e_crc_support=e2e_crc_support,
94 user_data_service_support=user_data_service_support,
95 user_facing_time_support=user_facing_time_support,
96 )
98 def _encode_value(self, data: BloodPressureFeatureData) -> bytearray:
99 """Encode BloodPressureFeatureData back to bytes.
101 Args:
102 data: BloodPressureFeatureData instance to encode
105 Returns:
106 Encoded bytes representing the blood pressure features
108 """
109 return DataParser.encode_int16(data.features_bitmap, signed=False)