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

58 statements  

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

1"""Broadcast Receive State characteristic (0x2BC8).""" 

2 

3from __future__ import annotations 

4 

5from enum import IntEnum 

6 

7import msgspec 

8 

9from ..context import CharacteristicContext 

10from .base import BaseCharacteristic 

11from .utils import DataParser 

12 

13 

14class PASyncState(IntEnum): 

15 """PA Sync State values.""" 

16 

17 NOT_SYNCHRONIZED = 0x00 

18 SYNC_INFO_REQUEST = 0x01 

19 SYNCHRONIZED = 0x02 

20 FAILED_TO_SYNCHRONIZE = 0x03 

21 NO_PAST = 0x04 

22 

23 

24class BIGEncryption(IntEnum): 

25 """BIG Encryption state values.""" 

26 

27 NOT_ENCRYPTED = 0x00 

28 BROADCAST_CODE_REQUIRED = 0x01 

29 DECRYPTING = 0x02 

30 BAD_CODE = 0x03 

31 

32 

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

34 """Parsed data from Broadcast Receive State characteristic. 

35 

36 Contains the source identification, sync state, encryption state, 

37 and any additional subgroup data as raw bytes. 

38 """ 

39 

40 source_id: int 

41 source_address_type: int 

42 source_address: bytes 

43 source_adv_sid: int 

44 broadcast_id: int 

45 pa_sync_state: PASyncState 

46 big_encryption: BIGEncryption 

47 additional_data: bytes = b"" 

48 

49 

50class BroadcastReceiveStateCharacteristic(BaseCharacteristic[BroadcastReceiveStateData]): 

51 """Broadcast Receive State characteristic (0x2BC8). 

52 

53 org.bluetooth.characteristic.broadcast_receive_state 

54 

55 Contains state information about a broadcast audio source 

56 being received. 

57 """ 

58 

59 # Minimum 14 bytes: source_id 1B, addr_type 1B, addr 6B, 

60 # adv_sid 1B, broadcast_id 3B, pa_sync 1B, big_enc 1B. 

61 min_length = 14 

62 allow_variable_length = True 

63 

64 def _decode_value( 

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

66 ) -> BroadcastReceiveStateData: 

67 """Parse Broadcast Receive State data. 

68 

69 Format: Source_ID(uint8) + Source_Address_Type(uint8) + Source_Address(6 bytes) 

70 + Source_Adv_SID(uint8) + Broadcast_ID(uint24) + PA_Sync_State(uint8) 

71 + BIG_Encryption(uint8) + optional additional data. 

72 """ 

73 offset = 0 

74 source_id = DataParser.parse_int8(data, offset, signed=False) 

75 offset += 1 

76 source_address_type = DataParser.parse_int8(data, offset, signed=False) 

77 offset += 1 

78 source_address = bytes(data[offset : offset + 6]) 

79 offset += 6 

80 source_adv_sid = DataParser.parse_int8(data, offset, signed=False) 

81 offset += 1 

82 broadcast_id = DataParser.parse_int24(data, offset, signed=False) 

83 offset += 3 

84 pa_sync_state = PASyncState(DataParser.parse_int8(data, offset, signed=False)) 

85 offset += 1 

86 big_encryption = BIGEncryption(DataParser.parse_int8(data, offset, signed=False)) 

87 offset += 1 

88 additional_data = bytes(data[offset:]) if offset < len(data) else b"" 

89 

90 return BroadcastReceiveStateData( 

91 source_id=source_id, 

92 source_address_type=source_address_type, 

93 source_address=source_address, 

94 source_adv_sid=source_adv_sid, 

95 broadcast_id=broadcast_id, 

96 pa_sync_state=pa_sync_state, 

97 big_encryption=big_encryption, 

98 additional_data=additional_data, 

99 ) 

100 

101 def _encode_value(self, data: BroadcastReceiveStateData) -> bytearray: 

102 """Encode Broadcast Receive State data to bytes.""" 

103 result = bytearray() 

104 result += DataParser.encode_int8(data.source_id) 

105 result += DataParser.encode_int8(data.source_address_type) 

106 result += bytearray(data.source_address) 

107 result += DataParser.encode_int8(data.source_adv_sid) 

108 result += DataParser.encode_int24(data.broadcast_id, signed=False) 

109 result += DataParser.encode_int8(int(data.pa_sync_state)) 

110 result += DataParser.encode_int8(int(data.big_encryption)) 

111 result += bytearray(data.additional_data) 

112 return result