Coverage for src / bluetooth_sig / gatt / characteristics / idd_features.py: 100%
46 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"""IDD Features characteristic (0x2B23).
3Composite structure: E2E-CRC (uint16) + E2E-Counter (uint8) +
4Insulin Concentration (SFLOAT) + Flags (24-bit).
6References:
7 Bluetooth SIG Insulin Delivery Service v1.0.1, Table 4.11, 4.12
8"""
10from __future__ import annotations
12from enum import IntFlag
14import msgspec
16from ..context import CharacteristicContext
17from .base import BaseCharacteristic
18from .utils import DataParser, IEEE11073Parser
21class IDDFeatureFlags(IntFlag):
22 """IDD Feature flags (24-bit) per IDS v1.0.1 Table 4.12."""
24 E2E_PROTECTION_SUPPORTED = 0x000001 # bit 0
25 BASAL_RATE_SUPPORTED = 0x000002 # bit 1
26 TBR_TYPE_ABSOLUTE_SUPPORTED = 0x000004 # bit 2
27 TBR_TYPE_RELATIVE_SUPPORTED = 0x000008 # bit 3
28 TBR_TEMPLATE_SUPPORTED = 0x000010 # bit 4
29 FAST_BOLUS_SUPPORTED = 0x000020 # bit 5
30 EXTENDED_BOLUS_SUPPORTED = 0x000040 # bit 6
31 MULTIWAVE_BOLUS_SUPPORTED = 0x000080 # bit 7
32 BOLUS_DELAY_TIME_SUPPORTED = 0x000100 # bit 8
33 BOLUS_TEMPLATE_SUPPORTED = 0x000200 # bit 9
34 BOLUS_ACTIVATION_TYPE_SUPPORTED = 0x000400 # bit 10
35 MULTIPLE_BOND_SUPPORTED = 0x000800 # bit 11
36 ISF_PROFILE_TEMPLATE_SUPPORTED = 0x001000 # bit 12
37 I2CHO_RATIO_PROFILE_TEMPLATE_SUPPORTED = 0x002000 # bit 13
38 TARGET_GLUCOSE_RANGE_PROFILE_TEMPLATE_SUPPORTED = 0x004000 # bit 14
39 INSULIN_ON_BOARD_SUPPORTED = 0x008000 # bit 15
40 FEATURE_EXTENSION = 0x800000 # bit 23
43class IDDFeaturesData(msgspec.Struct, frozen=True, kw_only=True):
44 """Parsed IDD Features characteristic data.
46 Attributes:
47 e2e_crc: CRC-CCITT value (0xFFFF if E2E not supported).
48 e2e_counter: E2E counter (0x00 if E2E not supported).
49 insulin_concentration: Insulin concentration as SFLOAT.
50 flags: Supported feature flags (24-bit).
52 """
54 e2e_crc: int
55 e2e_counter: int
56 insulin_concentration: float
57 flags: IDDFeatureFlags
60class IDDFeaturesCharacteristic(BaseCharacteristic[IDDFeaturesData]):
61 """IDD Features characteristic (0x2B23).
63 org.bluetooth.characteristic.idd_features
65 Reports supported features of the Insulin Delivery Device.
66 Structure: E2E-CRC(2) + E2E-Counter(1) + InsulinConcentration(2) + Flags(3) = 8 bytes.
67 """
69 min_length = 8
70 allow_variable_length = True
72 def _decode_value(
73 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
74 ) -> IDDFeaturesData:
75 """Parse IDD Features data per IDS v1.0.1 Table 4.11."""
76 e2e_crc = DataParser.parse_int16(data, 0, signed=False)
77 e2e_counter = DataParser.parse_int8(data, 2, signed=False)
78 insulin_concentration = IEEE11073Parser.parse_sfloat(data, 3)
79 flags_raw = DataParser.parse_int24(data, 5, signed=False)
80 flags = IDDFeatureFlags(flags_raw)
81 return IDDFeaturesData(
82 e2e_crc=e2e_crc,
83 e2e_counter=e2e_counter,
84 insulin_concentration=insulin_concentration,
85 flags=flags,
86 )
88 def _encode_value(self, data: IDDFeaturesData) -> bytearray:
89 """Encode IDD Features data."""
90 result = bytearray()
91 result.extend(DataParser.encode_int16(data.e2e_crc, signed=False))
92 result.extend(DataParser.encode_int8(data.e2e_counter, signed=False))
93 result.extend(IEEE11073Parser.encode_sfloat(data.insulin_concentration))
94 result.extend(DataParser.encode_int24(int(data.flags), signed=False))
95 return result