Skip to content

Commit

Permalink
Merge pull request #489 from google/gbg/basic-auracast-app
Browse files Browse the repository at this point in the history
basic auracast app
  • Loading branch information
barbibulle authored Jun 12, 2024
2 parents d7d03e2 + 658f641 commit 7912231
Show file tree
Hide file tree
Showing 10 changed files with 2,005 additions and 141 deletions.
407 changes: 407 additions & 0 deletions apps/auracast.py

Large diffs are not rendered by default.

804 changes: 689 additions & 115 deletions bumble/core.py

Large diffs are not rendered by default.

422 changes: 413 additions & 9 deletions bumble/device.py

Large diffs are not rendered by default.

255 changes: 246 additions & 9 deletions bumble/hci.py
Original file line number Diff line number Diff line change
Expand Up @@ -1381,7 +1381,7 @@ class LmpFeatureMask(enum.IntFlag):
STATUS_SPEC = {'size': 1, 'mapper': lambda x: HCI_Constant.status_name(x)}


class CodecID(enum.IntEnum):
class CodecID(OpenIntEnum):
# fmt: off
U_LOG = 0x00
A_LOG = 0x01
Expand Down Expand Up @@ -1968,6 +1968,9 @@ def __eq__(self, other):
def __str__(self):
return self.to_string()

def __repr__(self):
return f'Address({self.to_string(False)}/{self.address_type_name(self.address_type)})'


# Predefined address values
Address.NIL = Address(b"\xff\xff\xff\xff\xff\xff", Address.PUBLIC_DEVICE_ADDRESS)
Expand Down Expand Up @@ -4453,6 +4456,80 @@ def __str__(self):
)


# -----------------------------------------------------------------------------
@HCI_Command.command(
[
(
'options',
{
'size': 1,
'mapper': lambda x: HCI_LE_Periodic_Advertising_Create_Sync_Command.Options(
x
).name,
},
),
('advertising_sid', 1),
('advertiser_address_type', Address.ADDRESS_TYPE_SPEC),
('advertiser_address', Address.parse_address_preceded_by_type),
('skip', 2),
('sync_timeout', 2),
(
'sync_cte_type',
{
'size': 1,
'mapper': lambda x: HCI_LE_Periodic_Advertising_Create_Sync_Command.CteType(
x
).name,
},
),
]
)
class HCI_LE_Periodic_Advertising_Create_Sync_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.67 LE Periodic Advertising Create Sync command
'''

class Options(enum.IntFlag):
USE_PERIODIC_ADVERTISER_LIST = 1 << 0
REPORTING_INITIALLY_DISABLED = 1 << 1
DUPLICATE_FILTERING_INITIALLY_ENABLED = 1 << 2

class CteType(enum.IntFlag):
DO_NOT_SYNC_TO_PACKETS_WITH_AN_AOA_CONSTANT_TONE_EXTENSION = 1 << 0
DO_NOT_SYNC_TO_PACKETS_WITH_AN_AOD_CONSTANT_TONE_EXTENSION_1US = 1 << 1
DO_NOT_SYNC_TO_PACKETS_WITH_AN_AOD_CONSTANT_TONE_EXTENSION_2US = 1 << 2
DO_NOT_SYNC_TO_PACKETS_WITH_A_TYPE_3_CONSTANT_TONE_EXTENSION = 1 << 3
DO_NOT_SYNC_TO_PACKETS_WITHOUT_A_CONSTANT_TONE_EXTENSION = 1 << 4


# -----------------------------------------------------------------------------
@HCI_Command.command()
class HCI_LE_Periodic_Advertising_Create_Sync_Cancel_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.68 LE Periodic Advertising Create Sync Cancel Command
'''


# -----------------------------------------------------------------------------
@HCI_Command.command([('sync_handle', 2)])
class HCI_LE_Periodic_Advertising_Terminate_Sync_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.69 LE Periodic Advertising Terminate Sync Command
'''


# -----------------------------------------------------------------------------
@HCI_Command.command([('sync_handle', 2), ('enable', 1)])
class HCI_LE_Set_Periodic_Advertising_Receive_Enable_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.88 LE Set Periodic Advertising Receive Enable Command
'''

class Enable(enum.IntFlag):
REPORTING_ENABLED = 1 << 0
DUPLICATE_FILTERING_ENABLED = 1 << 1


# -----------------------------------------------------------------------------
@HCI_Command.command(
[
Expand Down Expand Up @@ -4488,14 +4565,6 @@ def privacy_mode_name(cls, privacy_mode):
return name_or_number(cls.PRIVACY_MODE_NAMES, privacy_mode)


# -----------------------------------------------------------------------------
@HCI_Command.command([('bit_number', 1), ('bit_value', 1)])
class HCI_LE_Set_Host_Feature_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.115 LE Set Host Feature Command
'''


# -----------------------------------------------------------------------------
@HCI_Command.command(
fields=[
Expand Down Expand Up @@ -4656,6 +4725,14 @@ class HCI_LE_Remove_ISO_Data_Path_Command(HCI_Command):
data_path_direction: int


# -----------------------------------------------------------------------------
@HCI_Command.command([('bit_number', 1), ('bit_value', 1)])
class HCI_LE_Set_Host_Feature_Command(HCI_Command):
'''
See Bluetooth spec @ 7.8.115 LE Set Host Feature Command
'''


# -----------------------------------------------------------------------------
# HCI Events
# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -5272,6 +5349,142 @@ def __str__(self):
)


# -----------------------------------------------------------------------------
@HCI_LE_Meta_Event.event(
[
('status', STATUS_SPEC),
('sync_handle', 2),
('advertising_sid', 1),
('advertiser_address_type', Address.ADDRESS_TYPE_SPEC),
('advertiser_address', Address.parse_address_preceded_by_type),
('advertiser_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
('periodic_advertising_interval', 2),
('advertiser_clock_accuracy', 1),
]
)
class HCI_LE_Periodic_Advertising_Sync_Established_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.14 LE Periodic Advertising Sync Established Event
'''


# -----------------------------------------------------------------------------
@HCI_LE_Meta_Event.event(
[
('status', STATUS_SPEC),
('sync_handle', 2),
('advertising_sid', 1),
('advertiser_address_type', Address.ADDRESS_TYPE_SPEC),
('advertiser_address', Address.parse_address_preceded_by_type),
('advertiser_phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
('periodic_advertising_interval', 2),
('advertiser_clock_accuracy', 1),
('num_subevents', 1),
('subevent_interval', 1),
('response_slot_delay', 1),
('response_slot_spacing', 1),
]
)
class HCI_LE_Periodic_Advertising_Sync_Established_V2_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.14 LE Periodic Advertising Sync Established Event
'''


# -----------------------------------------------------------------------------
@HCI_LE_Meta_Event.event(
[
('sync_handle', 2),
('tx_power', -1),
('rssi', -1),
(
'cte_type',
{
'size': 1,
'mapper': lambda x: HCI_LE_Periodic_Advertising_Report_Event.CteType(
x
).name,
},
),
(
'data_status',
{
'size': 1,
'mapper': lambda x: HCI_LE_Periodic_Advertising_Report_Event.DataStatus(
x
).name,
},
),
('data', 'v'),
]
)
class HCI_LE_Periodic_Advertising_Report_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.15 LE Periodic Advertising Report Event
'''

TX_POWER_INFORMATION_NOT_AVAILABLE = 0x7F
RSSI_NOT_AVAILABLE = 0x7F

class CteType(OpenIntEnum):
AOA_CONSTANT_TONE_EXTENSION = 0x00
AOD_CONSTANT_TONE_EXTENSION_1US = 0x01
AOD_CONSTANT_TONE_EXTENSION_2US = 0x02
NO_CONSTANT_TONE_EXTENSION = 0xFF

class DataStatus(OpenIntEnum):
DATA_COMPLETE = 0x00
DATA_INCOMPLETE_MORE_TO_COME = 0x01
DATA_INCOMPLETE_TRUNCATED_NO_MORE_TO_COME = 0x02


# -----------------------------------------------------------------------------
@HCI_LE_Meta_Event.event(
[
('sync_handle', 2),
('tx_power', -1),
('rssi', -1),
(
'cte_type',
{
'size': 1,
'mapper': lambda x: HCI_LE_Periodic_Advertising_Report_Event.CteType(
x
).name,
},
),
('periodic_event_counter', 2),
('subevent', 1),
(
'data_status',
{
'size': 1,
'mapper': lambda x: HCI_LE_Periodic_Advertising_Report_Event.DataStatus(
x
).name,
},
),
('data', 'v'),
]
)
class HCI_LE_Periodic_Advertising_Report_V2_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.15 LE Periodic Advertising Report Event
'''


# -----------------------------------------------------------------------------
@HCI_LE_Meta_Event.event(
[
('sync_handle', 2),
]
)
class HCI_LE_Periodic_Advertising_Sync_Lost_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.16 LE Periodic Advertising Sync Lost Event
'''


# -----------------------------------------------------------------------------
@HCI_LE_Meta_Event.event(
[
Expand Down Expand Up @@ -5337,6 +5550,30 @@ class HCI_LE_CIS_Request_Event(HCI_LE_Meta_Event):
'''


# -----------------------------------------------------------------------------
@HCI_LE_Meta_Event.event(
[
('sync_handle', 2),
('num_bis', 1),
('nse', 1),
('iso_interval', 2),
('bn', 1),
('pto', 1),
('irc', 1),
('max_pdu', 2),
('sdu_interval', 3),
('max_sdu', 2),
('phy', {'size': 1, 'mapper': HCI_Constant.le_phy_name}),
('framing', 1),
('encryption', 1),
]
)
class HCI_LE_BIGInfo_Advertising_Report_Event(HCI_LE_Meta_Event):
'''
See Bluetooth spec @ 7.7.65.34 LE BIGInfo Advertising Report Event
'''


# -----------------------------------------------------------------------------
@HCI_Event.event([('status', STATUS_SPEC)])
class HCI_Inquiry_Complete_Event(HCI_Event):
Expand Down
21 changes: 21 additions & 0 deletions bumble/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -905,6 +905,27 @@ def on_hci_le_advertising_set_terminated_event(self, event):
event.num_completed_extended_advertising_events,
)

def on_hci_le_periodic_advertising_sync_established_event(self, event):
self.emit(
'periodic_advertising_sync_establishment',
event.status,
event.sync_handle,
event.advertising_sid,
event.advertiser_address,
event.advertiser_phy,
event.periodic_advertising_interval,
event.advertiser_clock_accuracy,
)

def on_hci_le_periodic_advertising_sync_lost_event(self, event):
self.emit('periodic_advertising_sync_loss', event.sync_handle)

def on_hci_le_periodic_advertising_report_event(self, event):
self.emit('periodic_advertising_report', event.sync_handle, event)

def on_hci_le_biginfo_advertising_report_event(self, event):
self.emit('biginfo_advertising_report', event.sync_handle, event)

def on_hci_le_cis_request_event(self, event):
self.emit(
'cis_request',
Expand Down
5 changes: 3 additions & 2 deletions bumble/pandora/host.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
BT_PERIPHERAL_ROLE,
UUID,
AdvertisingData,
Appearance,
ConnectionError,
)
from bumble.device import (
Expand Down Expand Up @@ -988,8 +989,8 @@ def pack_data_types(self, ad: AdvertisingData) -> DataTypes:
dt.random_target_addresses.extend(
[data[i * 6 :: i * 6 + 6] for i in range(int(len(data) / 6))]
)
if i := cast(int, ad.get(AdvertisingData.APPEARANCE)):
dt.appearance = i
if appearance := cast(Appearance, ad.get(AdvertisingData.APPEARANCE)):
dt.appearance = int(appearance)
if i := cast(int, ad.get(AdvertisingData.ADVERTISING_INTERVAL)):
dt.advertising_interval = i
if s := cast(str, ad.get(AdvertisingData.URI)):
Expand Down
Loading

0 comments on commit 7912231

Please sign in to comment.