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

1"""Blood Pressure Feature characteristic implementation.""" 

2 

3from __future__ import annotations 

4 

5from enum import IntFlag 

6 

7import msgspec 

8 

9from ..constants import UINT16_MAX 

10from ..context import CharacteristicContext 

11from .base import BaseCharacteristic 

12from .utils import DataParser 

13 

14 

15class BloodPressureFeatures(IntFlag): 

16 """Blood Pressure Feature flags as per Bluetooth SIG specification.""" 

17 

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 

28 

29 

30class BloodPressureFeatureData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods 

31 """Parsed data from Blood Pressure Feature characteristic.""" 

32 

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 

43 

44 

45class BloodPressureFeatureCharacteristic(BaseCharacteristic[BloodPressureFeatureData]): 

46 """Blood Pressure Feature characteristic (0x2A49). 

47 

48 Used to expose the supported features of a blood pressure monitoring 

49 device. Indicates which optional measurements and capabilities are 

50 available. 

51 """ 

52 

53 # YAML has no range constraint; enforce full uint16 bitmap range. 

54 min_value: int = 0 

55 max_value: int = UINT16_MAX 

56 

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. 

61 

62 Format: Features(2) - 16-bit bitmap indicating supported features. 

63 

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) 

68 

69 Returns: 

70 BloodPressureFeatureData containing parsed feature bitmap and capabilities. 

71 

72 """ 

73 features_bitmap = DataParser.parse_int16(data, 0, signed=False) 

74 

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) 

84 

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 ) 

97 

98 def _encode_value(self, data: BloodPressureFeatureData) -> bytearray: 

99 """Encode BloodPressureFeatureData back to bytes. 

100 

101 Args: 

102 data: BloodPressureFeatureData instance to encode 

103 

104 

105 Returns: 

106 Encoded bytes representing the blood pressure features 

107 

108 """ 

109 return DataParser.encode_int16(data.features_bitmap, signed=False)