Coverage for src / bluetooth_sig / gatt / characteristics / device_time_control_point.py: 100%
28 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"""Device Time Control Point characteristic (0x2B91).
3Per DTS v1.0 Table 3.14 and Table 3.15, the DTCP characteristic structure is:
4 E2E_CRC (uint16, conditional) + Opcode (uint8) + Operand (0-17 bytes).
6Request opcodes (Client -> Server):
7 0x02: Propose Time Update (M) — Time Update operand (Table 3.16)
8 0x03: Force Time Update (O) — Time Update operand (Table 3.16)
9 0x04: Propose Non-Logged Time Adj Limit — uint16 operand (Table 3.18)
10 0x05: Retrieve Active Time Adjustments — no operand
12Response opcodes (Server -> Client):
13 0x07: Report Active Time Adjustments — operand (Table 3.19)
14 0x09: DTCP Response (M) — operand (Table 3.20)
16Opcodes 0x00, 0x01, 0x06, 0x08, 0x0A-0xFF are Reserved for Future Use.
18References:
19 Bluetooth SIG Device Time Service v1.0, Table 3.14, Table 3.15
20"""
22from __future__ import annotations
24from enum import IntEnum
26import msgspec
28from ..context import CharacteristicContext
29from .base import BaseCharacteristic
30from .utils import DataParser
33class DeviceTimeControlPointOpCode(IntEnum):
34 """DTCP opcode values — DTS v1.0 Table 3.15."""
36 PROPOSE_TIME_UPDATE = 0x02
37 FORCE_TIME_UPDATE = 0x03
38 PROPOSE_NON_LOGGED_TIME_ADJUSTMENT_LIMIT = 0x04
39 RETRIEVE_ACTIVE_TIME_ADJUSTMENTS = 0x05
40 REPORT_ACTIVE_TIME_ADJUSTMENTS = 0x07
41 DTCP_RESPONSE = 0x09
44class DeviceTimeControlPointData(msgspec.Struct, frozen=True, kw_only=True):
45 """Parsed data from Device Time Control Point characteristic."""
47 op_code: DeviceTimeControlPointOpCode
48 parameter: bytes | None = None
51class DeviceTimeControlPointCharacteristic(BaseCharacteristic[DeviceTimeControlPointData]):
52 """Device Time Control Point characteristic (0x2B91).
54 org.bluetooth.characteristic.device_time_control_point
56 Used to initiate DTCP procedures on the Device Time Service server.
57 """
59 min_length = 1
60 allow_variable_length = True
62 def _decode_value(
63 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
64 ) -> DeviceTimeControlPointData:
65 op_code = DeviceTimeControlPointOpCode(DataParser.parse_int8(data, 0, signed=False))
66 parameter = bytes(data[1:]) if len(data) > 1 else None
67 return DeviceTimeControlPointData(op_code=op_code, parameter=parameter)
69 def _encode_value(self, data: DeviceTimeControlPointData) -> bytearray:
70 result = bytearray([int(data.op_code)])
71 if data.parameter is not None:
72 result.extend(data.parameter)
73 return result