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
« prev ^ index » next coverage.py v7.13.5, created at 2026-04-03 16:41 +0000
1"""Broadcast Receive State characteristic (0x2BC8)."""
3from __future__ import annotations
5from enum import IntEnum
7import msgspec
9from ..context import CharacteristicContext
10from .base import BaseCharacteristic
11from .utils import DataParser
14class PASyncState(IntEnum):
15 """PA Sync State values."""
17 NOT_SYNCHRONIZED = 0x00
18 SYNC_INFO_REQUEST = 0x01
19 SYNCHRONIZED = 0x02
20 FAILED_TO_SYNCHRONIZE = 0x03
21 NO_PAST = 0x04
24class BIGEncryption(IntEnum):
25 """BIG Encryption state values."""
27 NOT_ENCRYPTED = 0x00
28 BROADCAST_CODE_REQUIRED = 0x01
29 DECRYPTING = 0x02
30 BAD_CODE = 0x03
33class BroadcastReceiveStateData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods
34 """Parsed data from Broadcast Receive State characteristic.
36 Contains the source identification, sync state, encryption state,
37 and any additional subgroup data as raw bytes.
38 """
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""
50class BroadcastReceiveStateCharacteristic(BaseCharacteristic[BroadcastReceiveStateData]):
51 """Broadcast Receive State characteristic (0x2BC8).
53 org.bluetooth.characteristic.broadcast_receive_state
55 Contains state information about a broadcast audio source
56 being received.
57 """
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
64 def _decode_value(
65 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True
66 ) -> BroadcastReceiveStateData:
67 """Parse Broadcast Receive State data.
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""
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 )
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