Coverage for src / bluetooth_sig / gatt / characteristics / sc_control_point.py: 100%

32 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-03 16:41 +0000

1"""SC Control Point characteristic (0x2A55). 

2 

3Speed and Cadence sensor control point for calibration, 

4cumulative value, and sensor location management. 

5 

6References: 

7 Bluetooth SIG Cycling Speed and Cadence / Running Speed and Cadence 

8 org.bluetooth.characteristic.sc_control_point (GSS YAML) 

9""" 

10 

11from __future__ import annotations 

12 

13from enum import IntEnum 

14 

15import msgspec 

16 

17from ..context import CharacteristicContext 

18from .base import BaseCharacteristic 

19from .utils import DataParser 

20 

21 

22class SCControlPointOpCode(IntEnum): 

23 """SC Control Point Op Codes.""" 

24 

25 SET_CUMULATIVE_VALUE = 0x01 

26 START_SENSOR_CALIBRATION = 0x02 

27 UPDATE_SENSOR_LOCATION = 0x03 

28 REQUEST_SUPPORTED_SENSOR_LOCATIONS = 0x04 

29 RESPONSE_CODE = 0x10 

30 

31 

32class SCControlPointResponseValue(IntEnum): 

33 """SC Control Point Response Values.""" 

34 

35 SUCCESS = 0x01 

36 OP_CODE_NOT_SUPPORTED = 0x02 

37 INVALID_PARAMETER = 0x03 

38 OPERATION_FAILED = 0x04 

39 

40 

41class SCControlPointData(msgspec.Struct, frozen=True, kw_only=True): 

42 """Parsed data from SC Control Point. 

43 

44 Attributes: 

45 opcode: The operation code. 

46 parameter: Raw parameter bytes (variable per opcode). Empty if none. 

47 

48 """ 

49 

50 opcode: SCControlPointOpCode 

51 parameter: bytes = b"" 

52 

53 

54class SCControlPointCharacteristic(BaseCharacteristic[SCControlPointData]): 

55 """SC Control Point characteristic (0x2A55). 

56 

57 org.bluetooth.characteristic.sc_control_point 

58 

59 Control point for Speed and Cadence sensor procedures. 

60 ROLE: CONTROL 

61 """ 

62 

63 min_length = 1 

64 allow_variable_length = True 

65 

66 def _decode_value( 

67 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True 

68 ) -> SCControlPointData: 

69 """Parse SC Control Point data. 

70 

71 Format: OpCode (uint8) + Parameter (variable). 

72 """ 

73 opcode = SCControlPointOpCode(DataParser.parse_int8(data, 0, signed=False)) 

74 parameter = bytes(data[1:]) 

75 

76 return SCControlPointData( 

77 opcode=opcode, 

78 parameter=parameter, 

79 ) 

80 

81 def _encode_value(self, data: SCControlPointData) -> bytearray: 

82 """Encode SC Control Point data.""" 

83 result = bytearray() 

84 result.extend(DataParser.encode_int8(int(data.opcode), signed=False)) 

85 result.extend(data.parameter) 

86 return result