From a5c0384ce0756aa40ae195316cb11fa7ab520d42 Mon Sep 17 00:00:00 2001 From: Matthias Ringwald Date: Mon, 8 Jul 2024 15:29:22 +0200 Subject: [PATCH] Add PBP --- autopts/ptsprojects/stack/layers/__init__.py | 1 + autopts/ptsprojects/stack/layers/pbp.py | 33 +++ autopts/ptsprojects/stack/stack.py | 8 + autopts/pybtp/btp/__init__.py | 1 + autopts/pybtp/btp/btp.py | 11 + autopts/pybtp/btp/pbp.py | 140 ++++++++++ autopts/pybtp/defs.py | 8 + autopts/wid/__init__.py | 1 + autopts/wid/pbp.py | 263 +++++++++++++++++++ doc/btp_pbp.txt | 77 ++++++ doc/overview.txt | 1 + 11 files changed, 544 insertions(+) create mode 100644 autopts/ptsprojects/stack/layers/pbp.py create mode 100644 autopts/pybtp/btp/pbp.py create mode 100644 autopts/wid/pbp.py create mode 100644 doc/btp_pbp.txt diff --git a/autopts/ptsprojects/stack/layers/__init__.py b/autopts/ptsprojects/stack/layers/__init__.py index adb4e1e374..4e6a23e041 100644 --- a/autopts/ptsprojects/stack/layers/__init__.py +++ b/autopts/ptsprojects/stack/layers/__init__.py @@ -40,4 +40,5 @@ from .gtbs import * from .tmap import * from .ots import * +from .pbp import * # GENERATOR append 1 diff --git a/autopts/ptsprojects/stack/layers/pbp.py b/autopts/ptsprojects/stack/layers/pbp.py new file mode 100644 index 0000000000..6ca5f254ab --- /dev/null +++ b/autopts/ptsprojects/stack/layers/pbp.py @@ -0,0 +1,33 @@ +# +# auto-pts - The Bluetooth PTS Automation Framework +# +# Copyright (c) 2024, BlueKitchen GmbH. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# + +from autopts.ptsprojects.stack.common import wait_for_queue_event +from autopts.pybtp import defs + + +class PBP: + def __init__(self): + self.event_queues = { + defs.PBP_EV_PUBLIC_BROADCAST_ANNOUNCEMENT_FOUND: [], + } + + def event_received(self, event_type, event_data): + self.event_queues[event_type].append(event_data) + + def wait_public_broadcast_event_found_ev(self, addr_type, addr, broadcast_name, timeout, remove=True): + return wait_for_queue_event( + self.event_queues[defs.PBP_EV_PUBLIC_BROADCAST_ANNOUNCEMENT_FOUND], + lambda ev: (addr_type, addr, broadcast_name) == (ev['addr_type'], ev['addr'], ev['broadcast_name']), + timeout, remove) diff --git a/autopts/ptsprojects/stack/stack.py b/autopts/ptsprojects/stack/stack.py index 74879f0338..b49aea84a1 100644 --- a/autopts/ptsprojects/stack/stack.py +++ b/autopts/ptsprojects/stack/stack.py @@ -52,6 +52,7 @@ "TBS": 1 << defs.BTP_SERVICE_ID_TBS, "TMAP": 1 << defs.BTP_SERVICE_ID_TMAP, "OTS": 1 << defs.BTP_SERVICE_ID_OTS, + "PBP": 1 << defs.BTP_SERVICE_ID_PBP, # GENERATOR append 1 } @@ -87,6 +88,7 @@ def __init__(self): self.gtbs = None self.tmap = None self.ots = None + self.pbp = None # GENERATOR append 2 def is_svc_supported(self, svc): @@ -186,6 +188,9 @@ def tmap_init(self): def ots_init(self): self.ots = OTS() + def pbp_init(self): + self.pbp = PBP() + # GENERATOR append 3 def cleanup(self): @@ -267,6 +272,9 @@ def cleanup(self): if self.ots: self.ots_init() + if self.pbp: + self.pbp_init() + # GENERATOR append 4 diff --git a/autopts/pybtp/btp/__init__.py b/autopts/pybtp/btp/__init__.py index e26371ba92..eee1fd0d30 100644 --- a/autopts/pybtp/btp/__init__.py +++ b/autopts/pybtp/btp/__init__.py @@ -45,4 +45,5 @@ from autopts.pybtp.btp.tbs import * from autopts.pybtp.btp.tmap import * from autopts.pybtp.btp.ots import * +from autopts.pybtp.btp.pbp import * # GENERATOR append 1 diff --git a/autopts/pybtp/btp/btp.py b/autopts/pybtp/btp/btp.py index c86d1cf3b9..fa7db4d78f 100644 --- a/autopts/pybtp/btp/btp.py +++ b/autopts/pybtp/btp/btp.py @@ -129,6 +129,8 @@ def read_supp_svcs(): defs.BTP_INDEX_NONE, defs.BTP_SERVICE_ID_TMAP), "ots_reg": (defs.BTP_SERVICE_ID_CORE, defs.CORE_REGISTER_SERVICE, defs.BTP_INDEX_NONE, defs.BTP_SERVICE_ID_OTS), + "pbp_reg": (defs.BTP_SERVICE_ID_CORE, defs.CORE_REGISTER_SERVICE, + defs.BTP_INDEX_NONE, defs.BTP_SERVICE_ID_PBP), # GENERATOR append 4 "read_supp_cmds": (defs.BTP_SERVICE_ID_CORE, defs.CORE_READ_SUPPORTED_COMMANDS, @@ -704,6 +706,13 @@ def core_reg_svc_ots(): iutctl.btp_socket.send_wait_rsp(*CORE['ots_reg']) +def core_reg_svc_pbp(): + logging.debug("%s", core_reg_svc_pbp.__name__) + + iutctl = get_iut() + iutctl.btp_socket.send_wait_rsp(*CORE['pbp_reg']) + + # GENERATOR append 1 def core_reg_svc_rsp_succ(): @@ -805,6 +814,7 @@ def init(get_iut_method): from .tbs import TBS_EV from .tmap import TMAP_EV from .ots import OTS_EV +from .pbp import PBP_EV # GENERATOR append 2 from autopts.pybtp.iutctl_common import set_event_handler @@ -844,6 +854,7 @@ def event_handler(hdr, data): defs.BTP_SERVICE_ID_TBS: (TBS_EV, stack.tbs), defs.BTP_SERVICE_ID_TMAP: (TMAP_EV, stack.tmap), defs.BTP_SERVICE_ID_OTS: (OTS_EV, stack.ots), + defs.BTP_SERVICE_ID_PBP: (PBP_EV, stack.pbp), # GENERATOR append 3 } diff --git a/autopts/pybtp/btp/pbp.py b/autopts/pybtp/btp/pbp.py new file mode 100644 index 0000000000..34af9545b5 --- /dev/null +++ b/autopts/pybtp/btp/pbp.py @@ -0,0 +1,140 @@ +# +# auto-pts - The Bluetooth PTS Automation Framework +# +# Copyright (c) 2024, BlueKitchen GmbH. +# +# This program is free software; you can redistribute it and/or modify it +# under the terms and conditions of the GNU General Public License, +# version 2, as published by the Free Software Foundation. +# +# This program is distributed in the hope it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +# more details. +# + +import binascii +import logging +import struct + +from autopts.pybtp import defs +from autopts.pybtp.btp.btp import CONTROLLER_INDEX, get_iut_method as get_iut, \ + btp_hdr_check +from autopts.pybtp.types import BTPError + +log = logging.debug + +PBP = { + 'read_supported_cmds': (defs.BTP_SERVICE_ID_PBP, + defs.PBP_READ_SUPPORTED_COMMANDS, + CONTROLLER_INDEX), + 'set_public_broadcast_announcement': (defs.BTP_SERVICE_ID_PBP, + defs.PBP_SET_PUBLIC_BROADCAST_ANNOUNCEMENT, + CONTROLLER_INDEX), + 'set_broadcast_name': (defs.BTP_SERVICE_ID_PBP, + defs.PBP_SET_BROADCAST_NAME, + CONTROLLER_INDEX), + 'broadcast_scan_start': (defs.BTP_SERVICE_ID_PBP, + defs.PBP_BROADCAST_SCAN_START, + CONTROLLER_INDEX), + 'broadcast_scan_stop': (defs.BTP_SERVICE_ID_PBP, + defs.PBP_BROADCAST_SCAN_STOP, + CONTROLLER_INDEX), +} + + +def pbp_command_rsp_succ(timeout=20.0): + logging.debug("%s", pbp_command_rsp_succ.__name__) + + iutctl = get_iut() + + tuple_hdr, tuple_data = iutctl.btp_socket.read(timeout) + logging.debug("received %r %r", tuple_hdr, tuple_data) + + btp_hdr_check(tuple_hdr, defs.BTP_SERVICE_ID_PBP) + + return tuple_data + + +def pbp_set_public_broadcast_announcement(features, metadata): + logging.debug(f"{pbp_set_public_broadcast_announcement.__name__}") + + data = bytearray() + metadata_len = len(metadata) + data += struct.pack('BB', features, metadata_len) + + if metadata_len: + data += metadata + + iutctl = get_iut() + iutctl.btp_socket.send(*PBP['set_public_broadcast_announcement'], data=data) + + pbp_command_rsp_succ() + + +def pbp_set_broadcast_name(name): + logging.debug(f"{pbp_set_broadcast_name.__name__}") + + name_data = name.encode('utf-8') + data = bytearray() + data += struct.pack('B', len(name_data)) + data += name_data + + iutctl = get_iut() + iutctl.btp_socket.send(*PBP['set_broadcast_name'], data=data) + + pbp_command_rsp_succ() + + +def pbp_broadcast_scan_start(): + logging.debug(f"{pbp_broadcast_scan_start.__name__}") + + data = bytearray() + iutctl = get_iut() + iutctl.btp_socket.send(*PBP['broadcast_scan_start'], data=data) + + pbp_command_rsp_succ() + + +def pbp_broadcast_scan_stop(): + logging.debug(f"{pbp_broadcast_scan_stop.__name__}") + + data = bytearray() + iutctl = get_iut() + iutctl.btp_socket.send(*PBP['broadcast_scan_stop'], data=data) + + pbp_command_rsp_succ() + + +def pbp_ev_public_broadcast_announcement_found(pbp, data, data_len): + logging.debug('%s %r', pbp_ev_public_broadcast_announcement_found.__name__, data) + + fmt = ' + Command parameters: + Response parameters: (variable) + + Each bit in response is a flag indicating if command with + opcode matching bit number is supported. Bit set to 1 means + that command is supported. Bit 0 is reserved and shall always + be set to 0. If specific bit is not present in response (less + than required bytes received) it shall be assumed that command + is not supported. + + In case of an error, the error response will be returned. + + Opcode 0x02: Set Public Broadcast Announcement + + Controller Index: + Command parameters: Features (1 octet) + Metadata LTVs len (1 octet) + LTVs (varies) + + This command is used to set the Public Broadcast Announcement in broadcast advertisements + + In case of an error, the error response will be returned. + + Opcode 0x03: Set Broadcast Name + + Controller Index: + Command parameters: Name Length (1 octet) + Name ( octets) + + This command is used to set the Public Broadcast Announcement in broadcast advertisements + + In case of an error, the error response will be returned. + + Opcode 0x04 - Broadcast Scan Start + Controller Index: + Command parameters: + Response parameters: + + This command is used to start scanning for Public Broadcast Announcements. + In case of an error, the error status response will be returned. + In case of a success, the IUT continues processing the command + asynchronously. + + Opcode 0x05 - Broadcast Scan Stop + Controller Index: + Command parameters: + Response parameters: + + This command is used to stop scanning for Public Broadcast Announcements. + In case of an error, the error status response will be returned. + In case of a success, the IUT continues processing the command + asynchronously. + +Events: + Opcode 0x80 - Public Broadcast Announcement Found event + + Controller Index: + Event parameters: Address_Type (1 octet) + Address (6 octets) + Broadcast_ID (3 octets) + Advertiser_SID (1 octet) + PA_Interval (2 octets) + PBA_Features (1 octet) + Broadcast_Name_Len (1 octet) + Broadcast_Name ( octets) + + This event returns info from scanned Public Broadcast Announcement. diff --git a/doc/overview.txt b/doc/overview.txt index 55771421ad..1f39842870 100644 --- a/doc/overview.txt +++ b/doc/overview.txt @@ -114,4 +114,5 @@ ID Name 27 TBS Service 28 TMAP Service 29 OTS Service + 30 PBP Service # GENERATOR append 1