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

1"""Device Time Control Point characteristic (0x2B91). 

2 

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). 

5 

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 

11 

12Response opcodes (Server -> Client): 

13 0x07: Report Active Time Adjustments — operand (Table 3.19) 

14 0x09: DTCP Response (M) — operand (Table 3.20) 

15 

16Opcodes 0x00, 0x01, 0x06, 0x08, 0x0A-0xFF are Reserved for Future Use. 

17 

18References: 

19 Bluetooth SIG Device Time Service v1.0, Table 3.14, Table 3.15 

20""" 

21 

22from __future__ import annotations 

23 

24from enum import IntEnum 

25 

26import msgspec 

27 

28from ..context import CharacteristicContext 

29from .base import BaseCharacteristic 

30from .utils import DataParser 

31 

32 

33class DeviceTimeControlPointOpCode(IntEnum): 

34 """DTCP opcode values — DTS v1.0 Table 3.15.""" 

35 

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 

42 

43 

44class DeviceTimeControlPointData(msgspec.Struct, frozen=True, kw_only=True): 

45 """Parsed data from Device Time Control Point characteristic.""" 

46 

47 op_code: DeviceTimeControlPointOpCode 

48 parameter: bytes | None = None 

49 

50 

51class DeviceTimeControlPointCharacteristic(BaseCharacteristic[DeviceTimeControlPointData]): 

52 """Device Time Control Point characteristic (0x2B91). 

53 

54 org.bluetooth.characteristic.device_time_control_point 

55 

56 Used to initiate DTCP procedures on the Device Time Service server. 

57 """ 

58 

59 min_length = 1 

60 allow_variable_length = True 

61 

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) 

68 

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